5 // Jb Evain (jbevain@gmail.com)
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
29 namespace Mono.Cecil.Metadata {
35 using Mono.Cecil.Binary;
37 sealed class MetadataReader : BaseMetadataVisitor {
40 BinaryReader m_binaryReader;
41 MetadataTableReader m_tableReader;
44 public MetadataTableReader TableReader {
45 get { return m_tableReader; }
48 public MetadataReader (ImageReader brv)
51 m_binaryReader = brv.GetReader ();
54 public MetadataRoot GetMetadataRoot ()
59 public BinaryReader GetDataReader (RVA rva)
61 return m_ir.Image.GetReaderAtVirtualAddress (rva);
64 public override void VisitMetadataRoot (MetadataRoot root)
67 root.Header = new MetadataRoot.MetadataRootHeader ();
68 root.Streams = new MetadataStreamCollection ();
71 public override void VisitMetadataRootHeader (MetadataRoot.MetadataRootHeader header)
73 long headpos = m_binaryReader.BaseStream.Position;
75 header.Signature = m_binaryReader.ReadUInt32 ();
77 if (header.Signature != MetadataRoot.MetadataRootHeader.StandardSignature)
78 throw new MetadataFormatException ("Wrong magic number");
80 header.MajorVersion = m_binaryReader.ReadUInt16 ();
81 header.MinorVersion = m_binaryReader.ReadUInt16 ();
82 header.Reserved = m_binaryReader.ReadUInt32 ();
85 uint length = m_binaryReader.ReadUInt32 ();
87 long pos = m_binaryReader.BaseStream.Position;
89 byte [] version, buffer = new byte [length];
91 while (read < length) {
92 byte cur = (byte)m_binaryReader.ReadSByte ();
95 buffer [read++] = cur;
97 version = new byte [read];
98 Buffer.BlockCopy (buffer, 0, version, 0, read);
99 header.Version = Encoding.UTF8.GetString (version, 0, version.Length);
101 pos += length - headpos + 3;
105 m_binaryReader.BaseStream.Position = pos;
107 header.Version = string.Empty;
109 header.Flags = m_binaryReader.ReadUInt16 ();
110 header.Streams = m_binaryReader.ReadUInt16 ();
113 public override void VisitMetadataStreamCollection (MetadataStreamCollection coll)
115 for (int i = 0; i < m_root.Header.Streams; i++)
116 coll.Add (new MetadataStream ());
119 public override void VisitMetadataStreamHeader (MetadataStream.MetadataStreamHeader header)
121 header.Offset = m_binaryReader.ReadUInt32 ();
122 header.Size = m_binaryReader.ReadUInt32 ();
124 StringBuilder buffer = new StringBuilder ();
126 char cur = (char) m_binaryReader.ReadSByte ();
131 header.Name = buffer.ToString ();
132 if (header.Name.Length == 0)
133 throw new MetadataFormatException ("Invalid stream name");
135 long rootpos = m_root.GetImage ().ResolveVirtualAddress (
136 m_root.GetImage ().CLIHeader.Metadata.VirtualAddress);
138 long curpos = m_binaryReader.BaseStream.Position;
140 if (header.Size != 0)
146 if (header.Size != 0)
149 m_binaryReader.BaseStream.Position = curpos;
151 header.Stream.Heap = MetadataHeap.HeapFactory (header.Stream);
154 public override void VisitGuidHeap (GuidHeap heap)
159 public override void VisitStringsHeap (StringsHeap heap)
163 if (heap.Data.Length < 1 && heap.Data [0] != 0)
164 throw new MetadataFormatException ("Malformed #Strings heap");
166 heap [(uint) 0] = string.Empty;
169 public override void VisitTablesHeap (TablesHeap heap)
172 heap.Tables = new TableCollection (heap);
174 BinaryReader br = new BinaryReader (new MemoryStream (heap.Data));
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 ();
184 // COMPACT FRAMEWORK NOTE: BinaryReader is not IDisposable
189 public override void VisitBlobHeap (BlobHeap heap)
194 public override void VisitUserStringsHeap (UserStringsHeap heap)
199 void VisitHeap (MetadataHeap heap)
201 long cursor = m_binaryReader.BaseStream.Position;
203 m_binaryReader.BaseStream.Position = m_root.GetImage ().ResolveVirtualAddress (
204 m_root.GetImage ().CLIHeader.Metadata.VirtualAddress)
205 + heap.GetStream ().Header.Offset;
207 heap.Data = m_binaryReader.ReadBytes ((int) heap.GetStream ().Header.Size);
209 m_binaryReader.BaseStream.Position = cursor;
212 void SetHeapIndexSize (MetadataHeap heap, byte flag)
216 TablesHeap th = m_root.Streams.TablesHeap;
217 heap.IndexSize = ((th.HeapSizes & flag) > 0) ? 4 : 2;
220 public override void TerminateMetadataRoot (MetadataRoot root)
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);