* docs.make, Makefile.am: Build mono-file-formats{.tree,.zip},
[mono.git] / mcs / class / Mono.Cecil / Mono.Cecil.Metadata / MetadataReader.cs
1 //
2 // MetadataReader.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@gmail.com)
6 //
7 // (C) 2005 Jb Evain
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 namespace Mono.Cecil.Metadata {
30
31         using System;
32         using System.IO;
33         using System.Text;
34
35         using Mono.Cecil.Binary;
36
37         sealed class MetadataReader : BaseMetadataVisitor {
38
39                 ImageReader m_ir;
40                 BinaryReader m_binaryReader;
41                 MetadataTableReader m_tableReader;
42                 MetadataRoot m_root;
43
44                 public MetadataTableReader TableReader {
45                         get { return m_tableReader; }
46                 }
47
48                 public MetadataReader (ImageReader brv)
49                 {
50                         m_ir = brv;
51                         m_binaryReader = brv.GetReader ();
52                 }
53
54                 public MetadataRoot GetMetadataRoot ()
55                 {
56                         return m_root;
57                 }
58
59                 public BinaryReader GetDataReader (RVA rva)
60                 {
61                         return m_ir.Image.GetReaderAtVirtualAddress (rva);
62                 }
63
64                 public override void VisitMetadataRoot (MetadataRoot root)
65                 {
66                         m_root = root;
67                         root.Header = new MetadataRoot.MetadataRootHeader ();
68                         root.Streams = new MetadataStreamCollection ();
69                 }
70
71                 public override void VisitMetadataRootHeader (MetadataRoot.MetadataRootHeader header)
72                 {
73                         long headpos = m_binaryReader.BaseStream.Position;
74
75                         header.Signature = m_binaryReader.ReadUInt32 ();
76
77                         if (header.Signature != MetadataRoot.MetadataRootHeader.StandardSignature)
78                                 throw new MetadataFormatException ("Wrong magic number");
79
80                         header.MajorVersion = m_binaryReader.ReadUInt16 ();
81                         header.MinorVersion = m_binaryReader.ReadUInt16 ();
82                         header.Reserved = m_binaryReader.ReadUInt32 ();
83
84                         // read version
85                         uint length = m_binaryReader.ReadUInt32 ();
86                         if (length != 0) {
87                                 long pos = m_binaryReader.BaseStream.Position;
88
89                                 byte [] version, buffer = new byte [length];
90                                 int read = 0;
91                                 while (read < length) {
92                                         byte cur = (byte)m_binaryReader.ReadSByte ();
93                                         if (cur == 0)
94                                                 break;
95                                         buffer [read++] = cur;
96                                 }
97                                 version = new byte [read];
98                                 Buffer.BlockCopy (buffer, 0, version, 0, read);
99                                 header.Version = Encoding.UTF8.GetString (version, 0, version.Length);
100
101                                 pos += length - headpos + 3;
102                                 pos &= ~3;
103                                 pos += headpos;
104
105                                 m_binaryReader.BaseStream.Position = pos;
106                         } else
107                                 header.Version = string.Empty;
108
109                         header.Flags = m_binaryReader.ReadUInt16 ();
110                         header.Streams = m_binaryReader.ReadUInt16 ();
111                 }
112
113                 public override void VisitMetadataStreamCollection (MetadataStreamCollection coll)
114                 {
115                         for (int i = 0; i < m_root.Header.Streams; i++)
116                                 coll.Add (new MetadataStream ());
117                 }
118
119                 public override void VisitMetadataStreamHeader (MetadataStream.MetadataStreamHeader header)
120                 {
121                         header.Offset = m_binaryReader.ReadUInt32 ();
122                         header.Size = m_binaryReader.ReadUInt32 ();
123
124                         StringBuilder buffer = new StringBuilder ();
125                         while (true) {
126                                 char cur = (char) m_binaryReader.ReadSByte ();
127                                 if (cur == '\0')
128                                         break;
129                                 buffer.Append (cur);
130                         }
131                         header.Name = buffer.ToString ();
132                         if (header.Name.Length == 0)
133                                 throw new MetadataFormatException ("Invalid stream name");
134
135                         long rootpos = m_root.GetImage ().ResolveVirtualAddress (
136                                 m_root.GetImage ().CLIHeader.Metadata.VirtualAddress);
137
138                         long curpos = m_binaryReader.BaseStream.Position;
139
140                         if (header.Size != 0)
141                                 curpos -= rootpos;
142
143                         curpos += 3;
144                         curpos &= ~3;
145
146                         if (header.Size != 0)
147                                 curpos += rootpos;
148
149                         m_binaryReader.BaseStream.Position = curpos;
150
151                         header.Stream.Heap = MetadataHeap.HeapFactory (header.Stream);
152                 }
153
154                 public override void VisitGuidHeap (GuidHeap heap)
155                 {
156                         VisitHeap (heap);
157                 }
158
159                 public override void VisitStringsHeap (StringsHeap heap)
160                 {
161                         VisitHeap (heap);
162
163                         if (heap.Data.Length < 1 && heap.Data [0] != 0)
164                                 throw new MetadataFormatException ("Malformed #Strings heap");
165
166                         heap [(uint) 0] = string.Empty;
167                 }
168
169                 public override void VisitTablesHeap (TablesHeap heap)
170                 {
171                         VisitHeap (heap);
172                         heap.Tables = new TableCollection (heap);
173
174                         BinaryReader br = new BinaryReader (new MemoryStream (heap.Data));
175                         try {
176                                 heap.Reserved = br.ReadUInt32 ();
177                                 heap.MajorVersion = br.ReadByte ();
178                                 heap.MinorVersion = br.ReadByte ();
179                                 heap.HeapSizes = br.ReadByte ();
180                                 heap.Reserved2 = br.ReadByte ();
181                                 heap.Valid = br.ReadInt64 ();
182                                 heap.Sorted = br.ReadInt64 ();
183                         } finally {
184                                 // COMPACT FRAMEWORK NOTE: BinaryReader is not IDisposable
185                                 br.Close ();
186                         }
187                 }
188
189                 public override void VisitBlobHeap (BlobHeap heap)
190                 {
191                         VisitHeap (heap);
192                 }
193
194                 public override void VisitUserStringsHeap (UserStringsHeap heap)
195                 {
196                         VisitHeap (heap);
197                 }
198
199                 void VisitHeap (MetadataHeap heap)
200                 {
201                         long cursor = m_binaryReader.BaseStream.Position;
202
203                         m_binaryReader.BaseStream.Position = m_root.GetImage ().ResolveVirtualAddress (
204                                 m_root.GetImage ().CLIHeader.Metadata.VirtualAddress)
205                                 + heap.GetStream ().Header.Offset;
206
207                         heap.Data = m_binaryReader.ReadBytes ((int) heap.GetStream ().Header.Size);
208
209                         m_binaryReader.BaseStream.Position = cursor;
210                 }
211
212                 void SetHeapIndexSize (MetadataHeap heap, byte flag)
213                 {
214                         if (heap == null)
215                                 return;
216                         TablesHeap th = m_root.Streams.TablesHeap;
217                         heap.IndexSize = ((th.HeapSizes & flag) > 0) ? 4 : 2;
218                 }
219
220                 public override void TerminateMetadataRoot (MetadataRoot root)
221                 {
222                         SetHeapIndexSize (root.Streams.StringsHeap, 0x01);
223                         SetHeapIndexSize (root.Streams.GuidHeap, 0x02);
224                         SetHeapIndexSize (root.Streams.BlobHeap, 0x04);
225                         m_tableReader = new MetadataTableReader (this);
226                         root.Streams.TablesHeap.Tables.Accept (m_tableReader);
227                 }
228         }
229 }