Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

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;
}
}
}