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 | } |
---|