2010-04-06 Jb Evain <jbevain@novell.com>
[mcs.git] / class / Mono.Cecil / Mono.Cecil.Binary / ResourceWriter.cs
blob5f6de0d532af565681f1362dc197cc1e4d7a8d31
1 //
2 // ResourceWriter.cs
3 //
4 // Author:
5 // Jb Evain (jbevain@gmail.com)
6 //
7 // (C) 2006 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:
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.Text;
31 namespace Mono.Cecil.Binary {
33 using System.Collections;
35 sealed class ResourceWriter {
37 Image m_img;
38 Section m_rsrc;
39 MemoryBinaryWriter m_writer;
41 ArrayList m_dataEntries;
42 ArrayList m_stringEntries;
44 long m_pos;
46 public ResourceWriter (Image img, Section rsrc, MemoryBinaryWriter writer)
48 m_img = img;
49 m_rsrc = rsrc;
50 m_writer = writer;
52 m_dataEntries = new ArrayList ();
53 m_stringEntries = new ArrayList ();
56 public void Write ()
58 if (m_img.ResourceDirectoryRoot == null)
59 return;
61 ComputeOffset (m_img.ResourceDirectoryRoot);
62 WriteResourceDirectoryTable (m_img.ResourceDirectoryRoot);
65 public void Patch ()
67 foreach (ResourceDataEntry rde in m_dataEntries) {
68 GotoOffset (rde.Offset);
69 m_writer.Write ((uint) rde.Data + m_rsrc.VirtualAddress);
70 RestoreOffset ();
74 void ComputeOffset (ResourceDirectoryTable root)
76 int offset = 0;
78 Queue directoryTables = new Queue ();
79 directoryTables.Enqueue (root);
81 while (directoryTables.Count > 0) {
82 ResourceDirectoryTable rdt = directoryTables.Dequeue () as ResourceDirectoryTable;
83 rdt.Offset = offset;
84 offset += 16;
86 foreach (ResourceDirectoryEntry rde in rdt.Entries) {
87 rde.Offset = offset;
88 offset += 8;
89 if (rde.IdentifiedByName)
90 m_stringEntries.Add (rde.Name);
92 if (rde.Child is ResourceDirectoryTable)
93 directoryTables.Enqueue (rde.Child);
94 else
95 m_dataEntries.Add (rde.Child);
99 foreach (ResourceDataEntry rde in m_dataEntries) {
100 rde.Offset = offset;
101 offset += 16;
104 foreach (ResourceDirectoryString rds in m_stringEntries) {
105 rds.Offset = offset;
106 byte [] str = Encoding.Unicode.GetBytes (rds.String);
107 offset += 2 + str.Length;
109 offset += 3;
110 offset &= ~3;
113 foreach (ResourceDataEntry rde in m_dataEntries) {
114 rde.Data = (uint) offset;
116 offset += rde.ResourceData.Length;
117 offset += 3;
118 offset &= ~3;
121 m_writer.Write (new byte [offset]);
124 void WriteResourceDirectoryTable (ResourceDirectoryTable rdt)
126 GotoOffset (rdt.Offset);
128 m_writer.Write (rdt.Characteristics);
129 m_writer.Write (rdt.TimeDateStamp);
130 m_writer.Write (rdt.MajorVersion);
131 m_writer.Write (rdt.MinorVersion);
133 ResourceDirectoryEntry [] namedEntries = GetEntries (rdt, true);
134 ResourceDirectoryEntry [] idEntries = GetEntries (rdt, false);
136 m_writer.Write ((ushort) namedEntries.Length);
137 m_writer.Write ((ushort) idEntries.Length);
139 foreach (ResourceDirectoryEntry rde in namedEntries)
140 WriteResourceDirectoryEntry (rde);
142 foreach (ResourceDirectoryEntry rde in idEntries)
143 WriteResourceDirectoryEntry (rde);
145 RestoreOffset ();
148 ResourceDirectoryEntry [] GetEntries (ResourceDirectoryTable rdt, bool identifiedByName)
150 ArrayList entries = new ArrayList ();
151 foreach (ResourceDirectoryEntry rde in rdt.Entries)
152 if (rde.IdentifiedByName == identifiedByName)
153 entries.Add (rde);
155 return entries.ToArray (typeof (ResourceDirectoryEntry)) as ResourceDirectoryEntry [];
158 void WriteResourceDirectoryEntry (ResourceDirectoryEntry rde)
160 GotoOffset (rde.Offset);
162 if (rde.IdentifiedByName) {
163 m_writer.Write ((uint) rde.Name.Offset | 0x80000000);
164 WriteResourceDirectoryString (rde.Name);
165 } else
166 m_writer.Write ((uint) rde.ID);
168 if (rde.Child is ResourceDirectoryTable) {
169 m_writer.Write((uint) rde.Child.Offset | 0x80000000);
170 WriteResourceDirectoryTable (rde.Child as ResourceDirectoryTable);
171 } else {
172 m_writer.Write (rde.Child.Offset);
173 WriteResourceDataEntry (rde.Child as ResourceDataEntry);
176 RestoreOffset ();
179 void WriteResourceDataEntry (ResourceDataEntry rde)
181 GotoOffset (rde.Offset);
183 m_writer.Write (0);
184 m_writer.Write ((uint) rde.ResourceData.Length);
185 m_writer.Write (rde.Codepage);
186 m_writer.Write (rde.Reserved);
188 m_writer.BaseStream.Position = rde.Data;
189 m_writer.Write (rde.ResourceData);
191 RestoreOffset ();
194 void WriteResourceDirectoryString (ResourceDirectoryString name)
196 GotoOffset (name.Offset);
198 byte [] str = Encoding.Unicode.GetBytes (name.String);
199 m_writer.Write ((ushort) str.Length);
200 m_writer.Write (str);
202 RestoreOffset ();
205 void GotoOffset (int offset)
207 m_pos = m_writer.BaseStream.Position;
208 m_writer.BaseStream.Position = offset;
211 void RestoreOffset ()
213 m_writer.BaseStream.Position = m_pos;