Merge branch 'cecil-light'
[mono.git] / mcs / tools / cil-strip / Mono.Cecil / StructureWriter.cs
1 //
2 // StructureWriter.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 {
30
31         using System;
32         using System.IO;
33
34         using Mono.Cecil.Binary;
35         using Mono.Cecil.Metadata;
36
37         internal sealed class StructureWriter : BaseStructureVisitor {
38
39                 MetadataWriter m_mdWriter;
40                 MetadataTableWriter m_tableWriter;
41                 MetadataRowWriter m_rowWriter;
42
43                 AssemblyDefinition m_asm;
44                 BinaryWriter m_binaryWriter;
45
46                 public AssemblyDefinition Assembly {
47                         get { return m_asm; }
48                 }
49
50                 static void ResetImage (ModuleDefinition mod)
51                 {
52                         Image ni = Image.CreateImage ();
53                         ni.Accept (new CopyImageVisitor (mod.Image));
54                         mod.Image = ni;
55                 }
56
57                 public StructureWriter (AssemblyDefinition asm, BinaryWriter writer)
58                 {
59                         m_asm = asm;
60                         m_binaryWriter = writer;
61                 }
62
63                 public BinaryWriter GetWriter ()
64                 {
65                         return m_binaryWriter;
66                 }
67
68                 public override void VisitAssemblyDefinition (AssemblyDefinition asm)
69                 {
70                         if (asm.Kind != AssemblyKind.Dll && asm.EntryPoint == null)
71                                 throw new ReflectionException ("Assembly does not have an entry point defined");
72
73                         if ((asm.MainModule.Image.CLIHeader.Flags & RuntimeImage.ILOnly) == 0)
74                                 throw new NotSupportedException ("Can not write a mixed mode assembly");
75
76                         foreach (ModuleDefinition module in asm.Modules)
77                                 if (module.Image.CLIHeader.Metadata.VirtualAddress != RVA.Zero)
78                                         ResetImage (module);
79
80                         asm.MetadataToken = new MetadataToken (TokenType.Assembly, 1);
81                         ReflectionWriter rw = asm.MainModule.Controller.Writer;
82                         rw.StructureWriter = this;
83
84                         m_mdWriter = rw.MetadataWriter;
85                         m_tableWriter = rw.MetadataTableWriter;
86                         m_rowWriter = rw.MetadataRowWriter;
87
88                         if (!rw.SaveSymbols)
89                                 return;
90
91                         FileStream fs = m_binaryWriter.BaseStream as FileStream;
92                         if (fs != null)
93                                 rw.OutputFile = fs.Name;
94                 }
95
96                 public override void VisitAssemblyNameDefinition (AssemblyNameDefinition name)
97                 {
98                         AssemblyTable asmTable = m_tableWriter.GetAssemblyTable ();
99
100                         if (name.PublicKey != null && name.PublicKey.Length > 0)
101                                 name.Flags |= AssemblyFlags.PublicKey;
102
103                         AssemblyRow asmRow = m_rowWriter.CreateAssemblyRow (
104                                 name.HashAlgorithm,
105                                 (ushort) name.Version.Major,
106                                 (ushort) name.Version.Minor,
107                                 (ushort) name.Version.Build,
108                                 (ushort) name.Version.Revision,
109                                 name.Flags,
110                                 m_mdWriter.AddBlob (name.PublicKey),
111                                 m_mdWriter.AddString (name.Name),
112                                 m_mdWriter.AddString (name.Culture));
113
114                         asmTable.Rows.Add (asmRow);
115                 }
116
117                 public override void VisitAssemblyNameReferenceCollection (AssemblyNameReferenceCollection references)
118                 {
119                         foreach (AssemblyNameReference name in references)
120                                 VisitAssemblyNameReference (name);
121                 }
122
123                 public override void VisitAssemblyNameReference (AssemblyNameReference name)
124                 {
125                         byte [] pkortoken;
126                         if (name.PublicKey != null && name.PublicKey.Length > 0)
127                                 pkortoken = name.PublicKey;
128                         else if (name.PublicKeyToken != null && name.PublicKeyToken.Length > 0)
129                                 pkortoken = name.PublicKeyToken;
130                         else
131                                 pkortoken = new byte [0];
132
133                         AssemblyRefTable arTable = m_tableWriter.GetAssemblyRefTable ();
134                         AssemblyRefRow arRow = m_rowWriter.CreateAssemblyRefRow (
135                                 (ushort) name.Version.Major,
136                                 (ushort) name.Version.Minor,
137                                 (ushort) name.Version.Build,
138                                 (ushort) name.Version.Revision,
139                                 name.Flags,
140                                 m_mdWriter.AddBlob (pkortoken),
141                                 m_mdWriter.AddString (name.Name),
142                                 m_mdWriter.AddString (name.Culture),
143                                 m_mdWriter.AddBlob (name.Hash));
144
145                         arTable.Rows.Add (arRow);
146                 }
147
148                 public override void VisitResourceCollection (ResourceCollection resources)
149                 {
150                         VisitCollection (resources);
151                 }
152
153                 public override void VisitEmbeddedResource (EmbeddedResource res)
154                 {
155                         AddManifestResource (
156                                 m_mdWriter.AddResource (res.Data),
157                                 res.Name, res.Flags,
158                                 new MetadataToken (TokenType.ManifestResource, 0));
159                 }
160
161                 public override void VisitLinkedResource (LinkedResource res)
162                 {
163                         FileTable fTable = m_tableWriter.GetFileTable ();
164                         FileRow fRow = m_rowWriter.CreateFileRow (
165                                 Mono.Cecil.FileAttributes.ContainsNoMetaData,
166                                 m_mdWriter.AddString (res.File),
167                                 m_mdWriter.AddBlob (res.Hash));
168
169                         fTable.Rows.Add (fRow);
170
171                         AddManifestResource (
172                                 0, res.Name, res.Flags,
173                                 new MetadataToken (TokenType.File, (uint) fTable.Rows.IndexOf (fRow) + 1));
174                 }
175
176                 public override void VisitAssemblyLinkedResource (AssemblyLinkedResource res)
177                 {
178                         MetadataToken impl = new MetadataToken (TokenType.AssemblyRef,
179                                 (uint) m_asm.MainModule.AssemblyReferences.IndexOf (res.Assembly) + 1);
180
181                         AddManifestResource (0, res.Name, res.Flags, impl);
182                 }
183
184                 void AddManifestResource (uint offset, string name, ManifestResourceAttributes flags, MetadataToken impl)
185                 {
186                         ManifestResourceTable mrTable = m_tableWriter.GetManifestResourceTable ();
187                         ManifestResourceRow mrRow = m_rowWriter.CreateManifestResourceRow (
188                                 offset,
189                                 flags,
190                                 m_mdWriter.AddString (name),
191                                 impl);
192
193                         mrTable.Rows.Add (mrRow);
194                 }
195
196                 public override void VisitModuleDefinitionCollection (ModuleDefinitionCollection modules)
197                 {
198                         VisitCollection (modules);
199                 }
200
201                 public override void VisitModuleDefinition (ModuleDefinition module)
202                 {
203                         if (module.Main) {
204                                 ModuleTable modTable = m_tableWriter.GetModuleTable ();
205                                 ModuleRow modRow = m_rowWriter.CreateModuleRow (
206                                         0,
207                                         m_mdWriter.AddString (module.Name),
208                                         m_mdWriter.AddGuid (module.Mvid),
209                                         0,
210                                         0);
211
212                                 modTable.Rows.Add (modRow);
213                                 module.MetadataToken = new MetadataToken (TokenType.Module, 1);
214                         } else {
215                                 // multiple module assemblies
216                                 throw new NotImplementedException ();
217                         }
218                 }
219
220                 public override void VisitModuleReferenceCollection (ModuleReferenceCollection modules)
221                 {
222                         VisitCollection (modules);
223                 }
224
225                 public override void VisitModuleReference (ModuleReference module)
226                 {
227                         ModuleRefTable mrTable = m_tableWriter.GetModuleRefTable ();
228                         ModuleRefRow mrRow = m_rowWriter.CreateModuleRefRow (
229                                 m_mdWriter.AddString (module.Name));
230
231                         mrTable.Rows.Add (mrRow);
232                 }
233
234                 public override void TerminateAssemblyDefinition (AssemblyDefinition asm)
235                 {
236                         foreach (ModuleDefinition mod in asm.Modules) {
237                                 ReflectionWriter writer = mod.Controller.Writer;
238                                 writer.VisitModuleDefinition (mod);
239                                 writer.VisitTypeReferenceCollection (mod.TypeReferences);
240                                 writer.VisitTypeDefinitionCollection (mod.Types);
241                                 writer.VisitMemberReferenceCollection (mod.MemberReferences);
242                                 writer.CompleteTypeDefinitions ();
243
244                                 writer.TerminateModuleDefinition (mod);
245                         }
246                 }
247         }
248 }