a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
217 lines
5.5 KiB
C#
217 lines
5.5 KiB
C#
//
|
|
// 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;
|
|
}
|
|
}
|
|
}
|