[msvc] Update csproj files (#4284)
[mono.git] / mcs / tools / pdb2mdb / PdbWriter.cs
1 //-----------------------------------------------------------------------------
2 //
3 // Copyright (C) Microsoft Corporation.  All Rights Reserved.
4 //
5 //-----------------------------------------------------------------------------
6 using System;
7 using System.IO;
8
9 namespace Microsoft.Cci.Pdb {
10   internal class PdbWriter {
11     internal PdbWriter(Stream writer, int pageSize) {
12       this.pageSize = pageSize;
13       this.usedBytes = pageSize * 3;
14       this.writer = writer;
15
16       writer.SetLength(usedBytes);
17     }
18
19     internal void WriteMeta(DataStream[] streams, BitAccess bits) {
20       PdbFileHeader head = new PdbFileHeader(pageSize);
21
22       WriteDirectory(streams,
23                      out head.directoryRoot,
24                      out head.directorySize,
25                      bits);
26       WriteFreeMap();
27
28       head.freePageMap = 2;
29       head.pagesUsed = usedBytes / pageSize;
30
31       writer.Seek(0, SeekOrigin.Begin);
32       head.Write(writer, bits);
33     }
34
35     private void WriteDirectory(DataStream[] streams,
36                                 out int directoryRoot,
37                                 out int directorySize,
38                                 BitAccess bits) {
39       DataStream directory = new DataStream();
40
41       int pages = 0;
42       for (int s = 0; s < streams.Length; s++) {
43         if (streams[s].Length > 0) {
44           pages += streams[s].Pages;
45         }
46       }
47
48       int use = 4 * (1 + streams.Length + pages);
49       bits.MinCapacity(use);
50       bits.WriteInt32(streams.Length);
51       for (int s = 0; s < streams.Length; s++) {
52         bits.WriteInt32(streams[s].Length);
53       }
54       for (int s = 0; s < streams.Length; s++) {
55         if (streams[s].Length > 0) {
56           bits.WriteInt32(streams[s].pages);
57         }
58       }
59       directory.Write(this, bits.Buffer, use);
60       directorySize = directory.Length;
61
62       use = 4 * directory.Pages;
63       bits.MinCapacity(use);
64       bits.WriteInt32(directory.pages);
65
66       DataStream ddir = new DataStream();
67       ddir.Write(this, bits.Buffer, use);
68
69       directoryRoot = ddir.pages[0];
70     }
71
72     private void WriteFreeMap() {
73       byte[] buffer = new byte[pageSize];
74
75       // We configure the old free map with only the first 3 pages allocated.
76       buffer[0] = 0xf8;
77       for (int i = 1; i < pageSize; i++) {
78         buffer[i] = 0xff;
79       }
80       Seek(1, 0);
81       Write(buffer, 0, pageSize);
82
83       // We configure the new free map with all of the used pages gone.
84       int count = usedBytes / pageSize;
85       int full = count / 8;
86       for (int i = 0; i < full; i++) {
87         buffer[i] = 0;
88       }
89       int rema = count % 8;
90       buffer[full] = (byte)(0xff << rema);
91
92       Seek(2, 0);
93       Write(buffer, 0, pageSize);
94     }
95
96     internal int AllocatePages(int count) {
97       int begin = usedBytes;
98
99       usedBytes += count * pageSize;
100       writer.SetLength(usedBytes);
101
102       if (usedBytes > pageSize * pageSize * 8) {
103         throw new Exception("PdbWriter does not support multiple free maps.");
104       }
105       return begin / pageSize;
106     }
107
108     internal void Seek(int page, int offset) {
109       writer.Seek(page * pageSize + offset, SeekOrigin.Begin);
110     }
111
112     internal void Write(byte[] bytes, int offset, int count) {
113       writer.Write(bytes, offset, count);
114     }
115
116     //////////////////////////////////////////////////////////////////////
117     //
118     internal int PageSize {
119       get { return pageSize; }
120     }
121
122     //////////////////////////////////////////////////////////////////////
123     //
124     internal readonly int pageSize;
125     private Stream writer;
126     private int usedBytes;
127   }
128
129 }