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.
31 namespace Mono
.Cecil
.Binary
{
33 using System
.Collections
;
35 sealed class ResourceWriter
{
39 MemoryBinaryWriter m_writer
;
41 ArrayList m_dataEntries
;
42 ArrayList m_stringEntries
;
46 public ResourceWriter (Image img
, Section rsrc
, MemoryBinaryWriter writer
)
52 m_dataEntries
= new ArrayList ();
53 m_stringEntries
= new ArrayList ();
58 if (m_img
.ResourceDirectoryRoot
== null)
61 ComputeOffset (m_img
.ResourceDirectoryRoot
);
62 WriteResourceDirectoryTable (m_img
.ResourceDirectoryRoot
);
67 foreach (ResourceDataEntry rde
in m_dataEntries
) {
68 GotoOffset (rde
.Offset
);
69 m_writer
.Write ((uint) rde
.Data
+ m_rsrc
.VirtualAddress
);
74 void ComputeOffset (ResourceDirectoryTable root
)
78 Queue directoryTables
= new Queue ();
79 directoryTables
.Enqueue (root
);
81 while (directoryTables
.Count
> 0) {
82 ResourceDirectoryTable rdt
= directoryTables
.Dequeue () as ResourceDirectoryTable
;
86 foreach (ResourceDirectoryEntry rde
in rdt
.Entries
) {
89 if (rde
.IdentifiedByName
)
90 m_stringEntries
.Add (rde
.Name
);
92 if (rde
.Child
is ResourceDirectoryTable
)
93 directoryTables
.Enqueue (rde
.Child
);
95 m_dataEntries
.Add (rde
.Child
);
99 foreach (ResourceDataEntry rde
in m_dataEntries
) {
104 foreach (ResourceDirectoryString rds
in m_stringEntries
) {
106 byte [] str
= Encoding
.Unicode
.GetBytes (rds
.String
);
107 offset
+= 2 + str
.Length
;
113 foreach (ResourceDataEntry rde
in m_dataEntries
) {
114 rde
.Data
= (uint) offset
;
116 offset
+= rde
.ResourceData
.Length
;
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
);
148 ResourceDirectoryEntry
[] GetEntries (ResourceDirectoryTable rdt
, bool identifiedByName
)
150 ArrayList entries
= new ArrayList ();
151 foreach (ResourceDirectoryEntry rde
in rdt
.Entries
)
152 if (rde
.IdentifiedByName
== identifiedByName
)
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
);
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
);
172 m_writer
.Write (rde
.Child
.Offset
);
173 WriteResourceDataEntry (rde
.Child
as ResourceDataEntry
);
179 void WriteResourceDataEntry (ResourceDataEntry rde
)
181 GotoOffset (rde
.Offset
);
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
);
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
);
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
;