2010-02-12 Jb Evain <jbevain@novell.com>
[mcs.git] / class / Mono.Cecil / Mono.Cecil / AssemblyStripper.cs
blob77e72e181d8e21fe1dcd36453349b099f8bf3732
1 //
2 // AssemblyStripper.cs
3 //
4 // Author:
5 // Jb Evain (jbevain@novell.com)
6 //
7 // (C) 2008 Novell, Inc (http://www.novell.com)
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:
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 using System.Collections;
30 using System.IO;
32 using Mono.Cecil.Binary;
33 using Mono.Cecil.Cil;
34 using Mono.Cecil.Metadata;
36 namespace Mono.Cecil {
38 class AssemblyStripper {
40 AssemblyDefinition assembly;
41 BinaryWriter writer;
43 Image original;
44 Image stripped;
46 ReflectionWriter reflection_writer;
47 MetadataWriter metadata_writer;
49 TablesHeap original_tables;
50 TablesHeap stripped_tables;
52 AssemblyStripper (AssemblyDefinition assembly, BinaryWriter writer)
54 this.assembly = assembly;
55 this.writer = writer;
58 void Strip ()
60 FullLoad ();
61 ClearMethodBodies ();
62 CopyOriginalImage ();
63 PatchMethods ();
64 PatchFields ();
65 PatchResources ();
66 Write ();
69 void FullLoad ()
71 assembly.MainModule.FullLoad ();
74 void ClearMethodBodies ()
76 foreach (TypeDefinition type in assembly.MainModule.Types) {
77 ClearMethodBodies (type.Constructors);
78 ClearMethodBodies (type.Methods);
82 static void ClearMethodBodies (ICollection methods)
84 foreach (MethodDefinition method in methods) {
85 if (!method.HasBody)
86 continue;
88 method.Body.ExceptionHandlers.Clear();
89 method.Body.Variables.Clear ();
90 method.Body.Instructions.Clear ();
91 method.Body.CilWorker.Emit (OpCodes.Ret);
95 void CopyOriginalImage ()
97 original = assembly.MainModule.Image;
98 stripped = Image.CreateImage();
100 stripped.Accept (new CopyImageVisitor (original));
102 assembly.MainModule.Image = stripped;
104 original_tables = original.MetadataRoot.Streams.TablesHeap;
105 stripped_tables = stripped.MetadataRoot.Streams.TablesHeap;
107 TableCollection tables = original_tables.Tables;
108 foreach (IMetadataTable table in tables)
109 stripped_tables.Tables.Add(table);
111 stripped_tables.Valid = original_tables.Valid;
112 stripped_tables.Sorted = original_tables.Sorted;
114 reflection_writer = new ReflectionWriter (assembly.MainModule);
115 reflection_writer.StructureWriter = new StructureWriter (assembly, writer);
116 reflection_writer.CodeWriter.Stripped = true;
118 metadata_writer = reflection_writer.MetadataWriter;
120 PatchHeap (metadata_writer.StringWriter, original.MetadataRoot.Streams.StringsHeap);
121 PatchHeap (metadata_writer.GuidWriter, original.MetadataRoot.Streams.GuidHeap);
122 PatchHeap (metadata_writer.UserStringWriter, original.MetadataRoot.Streams.UserStringsHeap);
123 PatchHeap (metadata_writer.BlobWriter, original.MetadataRoot.Streams.BlobHeap);
125 if (assembly.EntryPoint != null)
126 metadata_writer.EntryPointToken = assembly.EntryPoint.MetadataToken.ToUInt ();
129 static void PatchHeap (MemoryBinaryWriter heap_writer, MetadataHeap heap)
131 if (heap == null)
132 return;
134 heap_writer.BaseStream.Position = 0;
135 heap_writer.Write (heap.Data);
138 void PatchMethods ()
140 MethodTable methodTable = (MethodTable) stripped_tables [MethodTable.RId];
141 if (methodTable == null)
142 return;
144 RVA method_rva = RVA.Zero;
146 for (int i = 0; i < methodTable.Rows.Count; i++) {
147 MethodRow methodRow = methodTable[i];
149 MetadataToken methodToken = MetadataToken.FromMetadataRow (TokenType.Method, i);
151 MethodDefinition method = (MethodDefinition) assembly.MainModule.LookupByToken (methodToken);
153 if (method.HasBody) {
154 method_rva = method_rva != RVA.Zero
155 ? method_rva
156 : reflection_writer.CodeWriter.WriteMethodBody (method);
158 methodRow.RVA = method_rva;
159 } else
160 methodRow.RVA = RVA.Zero;
164 void PatchFields ()
166 FieldRVATable fieldRvaTable = (FieldRVATable) stripped_tables [FieldRVATable.RId];
167 if (fieldRvaTable == null)
168 return;
170 for (int i = 0; i < fieldRvaTable.Rows.Count; i++) {
171 FieldRVARow fieldRvaRow = fieldRvaTable [i];
173 MetadataToken fieldToken = new MetadataToken (TokenType.Field, fieldRvaRow.Field);
175 FieldDefinition field = (FieldDefinition) assembly.MainModule.LookupByToken (fieldToken);
177 fieldRvaRow.RVA = metadata_writer.GetDataCursor ();
178 metadata_writer.AddData (field.InitialValue.Length + 3 & (~3));
179 metadata_writer.AddFieldInitData (field.InitialValue);
183 void PatchResources ()
185 ManifestResourceTable resourceTable = (ManifestResourceTable) stripped_tables [ManifestResourceTable.RId];
186 if (resourceTable == null)
187 return;
189 for (int i = 0; i < resourceTable.Rows.Count; i++) {
190 ManifestResourceRow resourceRow = resourceTable [i];
192 if (resourceRow.Implementation.RID != 0)
193 continue;
195 foreach (Resource resource in assembly.MainModule.Resources) {
196 EmbeddedResource er = resource as EmbeddedResource;
197 if (er == null)
198 continue;
200 if (resource.Name != original.MetadataRoot.Streams.StringsHeap [resourceRow.Name])
201 continue;
203 resourceRow.Offset = metadata_writer.AddResource (er.Data);
208 void Write ()
210 stripped.MetadataRoot.Accept (metadata_writer);
213 public static void StripAssembly (AssemblyDefinition assembly, string file)
215 using (FileStream fs = new FileStream (file, FileMode.Create, FileAccess.Write, FileShare.None)) {
216 new AssemblyStripper (assembly, new BinaryWriter (fs)).Strip ();