// // ResourceWriter.cs // // Author: // Jb Evain (jbevain@gmail.com) // // (C) 2006 Jb Evain // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System.Text; namespace Mono.Cecil.Binary { using System.Collections; sealed class ResourceWriter { Image m_img; Section m_rsrc; MemoryBinaryWriter m_writer; ArrayList m_dataEntries; ArrayList m_stringEntries; long m_pos; public ResourceWriter (Image img, Section rsrc, MemoryBinaryWriter writer) { m_img = img; m_rsrc = rsrc; m_writer = writer; m_dataEntries = new ArrayList (); m_stringEntries = new ArrayList (); } public void Write () { if (m_img.ResourceDirectoryRoot == null) return; ComputeOffset (m_img.ResourceDirectoryRoot); WriteResourceDirectoryTable (m_img.ResourceDirectoryRoot); } public void Patch () { foreach (ResourceDataEntry rde in m_dataEntries) { GotoOffset (rde.Offset); m_writer.Write ((uint) rde.Data + m_rsrc.VirtualAddress); RestoreOffset (); } } void ComputeOffset (ResourceDirectoryTable root) { int offset = 0; Queue directoryTables = new Queue (); directoryTables.Enqueue (root); while (directoryTables.Count > 0) { ResourceDirectoryTable rdt = directoryTables.Dequeue () as ResourceDirectoryTable; rdt.Offset = offset; offset += 16; foreach (ResourceDirectoryEntry rde in rdt.Entries) { rde.Offset = offset; offset += 8; if (rde.IdentifiedByName) m_stringEntries.Add (rde.Name); if (rde.Child is ResourceDirectoryTable) directoryTables.Enqueue (rde.Child); else m_dataEntries.Add (rde.Child); } } foreach (ResourceDataEntry rde in m_dataEntries) { rde.Offset = offset; offset += 16; } foreach (ResourceDirectoryString rds in m_stringEntries) { rds.Offset = offset; byte [] str = Encoding.Unicode.GetBytes (rds.String); offset += 2 + str.Length; offset += 3; offset &= ~3; } foreach (ResourceDataEntry rde in m_dataEntries) { rde.Data = (uint) offset; offset += rde.ResourceData.Length; offset += 3; offset &= ~3; } m_writer.Write (new byte [offset]); } void WriteResourceDirectoryTable (ResourceDirectoryTable rdt) { GotoOffset (rdt.Offset); m_writer.Write (rdt.Characteristics); m_writer.Write (rdt.TimeDateStamp); m_writer.Write (rdt.MajorVersion); m_writer.Write (rdt.MinorVersion); ResourceDirectoryEntry [] namedEntries = GetEntries (rdt, true); ResourceDirectoryEntry [] idEntries = GetEntries (rdt, false); m_writer.Write ((ushort) namedEntries.Length); m_writer.Write ((ushort) idEntries.Length); foreach (ResourceDirectoryEntry rde in namedEntries) WriteResourceDirectoryEntry (rde); foreach (ResourceDirectoryEntry rde in idEntries) WriteResourceDirectoryEntry (rde); RestoreOffset (); } ResourceDirectoryEntry [] GetEntries (ResourceDirectoryTable rdt, bool identifiedByName) { ArrayList entries = new ArrayList (); foreach (ResourceDirectoryEntry rde in rdt.Entries) if (rde.IdentifiedByName == identifiedByName) entries.Add (rde); return entries.ToArray (typeof (ResourceDirectoryEntry)) as ResourceDirectoryEntry []; } void WriteResourceDirectoryEntry (ResourceDirectoryEntry rde) { GotoOffset (rde.Offset); if (rde.IdentifiedByName) { m_writer.Write ((uint) rde.Name.Offset | 0x80000000); WriteResourceDirectoryString (rde.Name); } else m_writer.Write ((uint) rde.ID); if (rde.Child is ResourceDirectoryTable) { m_writer.Write((uint) rde.Child.Offset | 0x80000000); WriteResourceDirectoryTable (rde.Child as ResourceDirectoryTable); } else { m_writer.Write (rde.Child.Offset); WriteResourceDataEntry (rde.Child as ResourceDataEntry); } RestoreOffset (); } void WriteResourceDataEntry (ResourceDataEntry rde) { GotoOffset (rde.Offset); m_writer.Write (0); m_writer.Write ((uint) rde.ResourceData.Length); m_writer.Write (rde.Codepage); m_writer.Write (rde.Reserved); m_writer.BaseStream.Position = rde.Data; m_writer.Write (rde.ResourceData); RestoreOffset (); } void WriteResourceDirectoryString (ResourceDirectoryString name) { GotoOffset (name.Offset); byte [] str = Encoding.Unicode.GetBytes (name.String); m_writer.Write ((ushort) str.Length); m_writer.Write (str); RestoreOffset (); } void GotoOffset (int offset) { m_pos = m_writer.BaseStream.Position; m_writer.BaseStream.Position = offset; } void RestoreOffset () { m_writer.BaseStream.Position = m_pos; } } }