Imported Upstream version 3.6.0

Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
This commit is contained in:
Jo Shields
2014-08-13 10:39:27 +01:00
commit a575963da9
50588 changed files with 8155799 additions and 0 deletions

View File

@@ -0,0 +1,368 @@
/*
Copyright (C) 2008 Jeroen Frijters
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jeroen Frijters
jeroen@frijters.net
*/
using System;
using System.Collections.Generic;
using System.Text;
using IKVM.Reflection.Metadata;
namespace IKVM.Reflection.Writer
{
sealed class ByteBuffer
{
private byte[] buffer;
private int pos;
private int __length; // __length is only valid if > pos, otherwise pos is the current length
internal ByteBuffer(int initialCapacity)
{
buffer = new byte[initialCapacity];
}
private ByteBuffer(byte[] wrap, int length)
{
this.buffer = wrap;
this.pos = length;
}
internal int Position
{
get { return pos; }
set
{
if (value > this.Length || value > buffer.Length)
throw new ArgumentOutOfRangeException();
__length = Math.Max(__length, pos);
pos = value;
}
}
internal int Length
{
get { return Math.Max(pos, __length); }
}
// insert count bytes at the current position (without advancing the current position)
internal void Insert(int count)
{
if (count > 0)
{
int len = this.Length;
int free = buffer.Length - len;
if (free < count)
{
Grow(count - free);
}
Buffer.BlockCopy(buffer, pos, buffer, pos + count, len - pos);
__length = Math.Max(__length, pos) + count;
}
else if (count < 0)
{
throw new ArgumentOutOfRangeException("count");
}
}
private void Grow(int minGrow)
{
byte[] newbuf = new byte[Math.Max(buffer.Length + minGrow, buffer.Length * 2)];
Buffer.BlockCopy(buffer, 0, newbuf, 0, buffer.Length);
buffer = newbuf;
}
// NOTE this does not advance the position
internal int GetInt32AtCurrentPosition()
{
return buffer[pos]
+ (buffer[pos + 1] << 8)
+ (buffer[pos + 2] << 16)
+ (buffer[pos + 3] << 24);
}
// NOTE this does not advance the position
internal byte GetByteAtCurrentPosition()
{
return buffer[pos];
}
// return the number of bytes that the compressed int at the current position takes
internal int GetCompressedUIntLength()
{
switch (buffer[pos] & 0xC0)
{
default:
return 1;
case 0x80:
return 2;
case 0xC0:
return 4;
}
}
internal void Write(byte[] value)
{
if (pos + value.Length > buffer.Length)
Grow(value.Length);
Buffer.BlockCopy(value, 0, buffer, pos, value.Length);
pos += value.Length;
}
internal void Write(byte value)
{
if (pos == buffer.Length)
Grow(1);
buffer[pos++] = value;
}
internal void Write(sbyte value)
{
Write((byte)value);
}
internal void Write(ushort value)
{
Write((short)value);
}
internal void Write(short value)
{
if (pos + 2 > buffer.Length)
Grow(2);
buffer[pos++] = (byte)value;
buffer[pos++] = (byte)(value >> 8);
}
internal void Write(uint value)
{
Write((int)value);
}
internal void Write(int value)
{
if (pos + 4 > buffer.Length)
Grow(4);
buffer[pos++] = (byte)value;
buffer[pos++] = (byte)(value >> 8);
buffer[pos++] = (byte)(value >> 16);
buffer[pos++] = (byte)(value >> 24);
}
internal void Write(ulong value)
{
Write((long)value);
}
internal void Write(long value)
{
if (pos + 8 > buffer.Length)
Grow(8);
buffer[pos++] = (byte)value;
buffer[pos++] = (byte)(value >> 8);
buffer[pos++] = (byte)(value >> 16);
buffer[pos++] = (byte)(value >> 24);
buffer[pos++] = (byte)(value >> 32);
buffer[pos++] = (byte)(value >> 40);
buffer[pos++] = (byte)(value >> 48);
buffer[pos++] = (byte)(value >> 56);
}
internal void Write(float value)
{
Write(SingleConverter.SingleToInt32Bits(value));
}
internal void Write(double value)
{
Write(BitConverter.DoubleToInt64Bits(value));
}
internal void Write(string str)
{
if (str == null)
{
Write((byte)0xFF);
}
else
{
byte[] buf = Encoding.UTF8.GetBytes(str);
WriteCompressedUInt(buf.Length);
Write(buf);
}
}
internal void WriteCompressedUInt(int value)
{
if (value <= 0x7F)
{
Write((byte)value);
}
else if (value <= 0x3FFF)
{
Write((byte)(0x80 | (value >> 8)));
Write((byte)value);
}
else
{
Write((byte)(0xC0 | (value >> 24)));
Write((byte)(value >> 16));
Write((byte)(value >> 8));
Write((byte)value);
}
}
internal void WriteCompressedInt(int value)
{
if (value >= 0)
{
WriteCompressedUInt(value << 1);
}
else if (value >= -64)
{
value = ((value << 1) & 0x7F) | 1;
Write((byte)value);
}
else if (value >= -8192)
{
value = ((value << 1) & 0x3FFF) | 1;
Write((byte)(0x80 | (value >> 8)));
Write((byte)value);
}
else
{
value = ((value << 1) & 0x1FFFFFFF) | 1;
Write((byte)(0xC0 | (value >> 24)));
Write((byte)(value >> 16));
Write((byte)(value >> 8));
Write((byte)value);
}
}
internal void Write(ByteBuffer bb)
{
if (pos + bb.Length > buffer.Length)
Grow(bb.Length);
Buffer.BlockCopy(bb.buffer, 0, buffer, pos, bb.Length);
pos += bb.Length;
}
internal void WriteTo(System.IO.Stream stream)
{
stream.Write(buffer, 0, this.Length);
}
internal void Clear()
{
pos = 0;
__length = 0;
}
internal void Align(int alignment)
{
if (pos + alignment > buffer.Length)
Grow(alignment);
int newpos = (pos + alignment - 1) & ~(alignment - 1);
while (pos < newpos)
buffer[pos++] = 0;
}
internal void WriteTypeDefOrRefEncoded(int token)
{
switch (token >> 24)
{
case TypeDefTable.Index:
WriteCompressedUInt((token & 0xFFFFFF) << 2 | 0);
break;
case TypeRefTable.Index:
WriteCompressedUInt((token & 0xFFFFFF) << 2 | 1);
break;
case TypeSpecTable.Index:
WriteCompressedUInt((token & 0xFFFFFF) << 2 | 2);
break;
default:
throw new InvalidOperationException();
}
}
internal void Write(System.IO.Stream stream)
{
const int chunkSize = 8192;
for (; ; )
{
if (pos + chunkSize > buffer.Length)
Grow(chunkSize);
int read = stream.Read(buffer, pos, chunkSize);
if (read <= 0)
{
break;
}
pos += read;
}
}
internal byte[] ToArray()
{
int len = this.Length;
byte[] buf = new byte[len];
Buffer.BlockCopy(buffer, 0, buf, 0, len);
return buf;
}
internal static ByteBuffer Wrap(byte[] buf)
{
return new ByteBuffer(buf, buf.Length);
}
internal static ByteBuffer Wrap(byte[] buf, int length)
{
return new ByteBuffer(buf, length);
}
internal bool Match(int pos, ByteBuffer bb2, int pos2, int len)
{
for (int i = 0; i < len; i++)
{
if (buffer[pos + i] != bb2.buffer[pos2 + i])
{
return false;
}
}
return true;
}
internal int Hash()
{
int hash = 0;
int len = this.Length;
for (int i = 0; i < len; i++)
{
hash *= 37;
hash ^= buffer[i];
}
return hash;
}
internal IKVM.Reflection.Reader.ByteReader GetBlob(int offset)
{
return IKVM.Reflection.Reader.ByteReader.FromBlob(buffer, offset);
}
}
}

395
external/ikvm/reflect/Writer/Heaps.cs vendored Normal file
View File

@@ -0,0 +1,395 @@
/*
Copyright (C) 2008 Jeroen Frijters
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jeroen Frijters
jeroen@frijters.net
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using IKVM.Reflection.Metadata;
namespace IKVM.Reflection.Writer
{
abstract class Heap
{
protected bool frozen;
protected int unalignedlength;
internal void Write(MetadataWriter mw)
{
int pos = mw.Position;
WriteImpl(mw);
Debug.Assert(mw.Position == pos + unalignedlength);
int align = Length - unalignedlength;
for (int i = 0; i < align; i++)
{
mw.Write((byte)0);
}
}
internal bool IsBig
{
get { return Length > 65535; }
}
internal int Length
{
get
{
if (!frozen)
throw new InvalidOperationException();
return (unalignedlength + 3) & ~3;
}
}
protected abstract void WriteImpl(MetadataWriter mw);
}
abstract class SimpleHeap : Heap
{
internal void Freeze()
{
if (frozen)
throw new InvalidOperationException();
frozen = true;
unalignedlength = GetLength();
}
protected abstract int GetLength();
}
sealed class TableHeap : Heap
{
internal void Freeze(MetadataWriter mw)
{
if (frozen)
throw new InvalidOperationException();
frozen = true;
unalignedlength = GetLength(mw);
}
protected override void WriteImpl(MetadataWriter mw)
{
Table[] tables = mw.ModuleBuilder.GetTables();
// Header
mw.Write(0); // Reserved
int ver = mw.ModuleBuilder.MDStreamVersion;
mw.Write((byte)(ver >> 16)); // MajorVersion
mw.Write((byte)ver); // MinorVersion
byte heapSizes = 0;
if (mw.ModuleBuilder.Strings.IsBig)
{
heapSizes |= 0x01;
}
if (mw.ModuleBuilder.Guids.IsBig)
{
heapSizes |= 0x02;
}
if (mw.ModuleBuilder.Blobs.IsBig)
{
heapSizes |= 0x04;
}
mw.Write(heapSizes);// HeapSizes
// LAMESPEC spec says reserved, but .NET 2.0 Ref.Emit sets it to 0x10
mw.Write((byte)0x10); // Reserved
long bit = 1;
long valid = 0;
foreach (Table table in tables)
{
if (table != null && table.RowCount > 0)
{
valid |= bit;
}
bit <<= 1;
}
mw.Write(valid); // Valid
mw.Write(0x0016003301FA00L); // Sorted
// Rows
foreach (Table table in tables)
{
if (table != null && table.RowCount > 0)
{
mw.Write(table.RowCount);
}
}
// Tables
foreach (Table table in tables)
{
if (table != null && table.RowCount > 0)
{
int pos = mw.Position;
table.Write(mw);
Debug.Assert(mw.Position - pos == table.GetLength(mw));
}
}
// unexplained extra padding
mw.Write((byte)0);
}
private static int GetLength(MetadataWriter mw)
{
int len = 4 + 4 + 8 + 8;
foreach (Table table in mw.ModuleBuilder.GetTables())
{
if (table != null && table.RowCount > 0)
{
len += 4; // row count
len += table.GetLength(mw);
}
}
// note that we pad one extra (unexplained) byte
return len + 1;
}
}
sealed class StringHeap : SimpleHeap
{
private List<string> list = new List<string>();
private Dictionary<string, int> strings = new Dictionary<string, int>();
private int nextOffset;
internal StringHeap()
{
Add("");
}
internal int Add(string str)
{
Debug.Assert(!frozen);
int offset;
if (!strings.TryGetValue(str, out offset))
{
offset = nextOffset;
nextOffset += System.Text.Encoding.UTF8.GetByteCount(str) + 1;
list.Add(str);
strings.Add(str, offset);
}
return offset;
}
internal string Find(int index)
{
foreach (KeyValuePair<string, int> kv in strings)
{
if (kv.Value == index)
{
return kv.Key;
}
}
return null;
}
protected override int GetLength()
{
return nextOffset;
}
protected override void WriteImpl(MetadataWriter mw)
{
foreach (string str in list)
{
mw.Write(System.Text.Encoding.UTF8.GetBytes(str));
mw.Write((byte)0);
}
}
}
sealed class UserStringHeap : SimpleHeap
{
private List<string> list = new List<string>();
private Dictionary<string, int> strings = new Dictionary<string, int>();
private int nextOffset;
internal UserStringHeap()
{
nextOffset = 1;
}
internal bool IsEmpty
{
get { return nextOffset == 1; }
}
internal int Add(string str)
{
Debug.Assert(!frozen);
int offset;
if (!strings.TryGetValue(str, out offset))
{
int length = str.Length * 2 + 1 + MetadataWriter.GetCompressedUIntLength(str.Length * 2 + 1);
if (nextOffset + length > 0xFFFFFF)
{
throw new FileFormatLimitationExceededException("No logical space left to create more user strings.", FileFormatLimitationExceededException.META_E_STRINGSPACE_FULL);
}
offset = nextOffset;
nextOffset += length;
list.Add(str);
strings.Add(str, offset);
}
return offset;
}
protected override int GetLength()
{
return nextOffset;
}
protected override void WriteImpl(MetadataWriter mw)
{
mw.Write((byte)0);
foreach (string str in list)
{
mw.WriteCompressedUInt(str.Length * 2 + 1);
byte hasSpecialChars = 0;
foreach (char ch in str)
{
mw.Write((ushort)ch);
if (hasSpecialChars == 0 && (ch < 0x20 || ch > 0x7E))
{
if (ch > 0x7E
|| (ch >= 0x01 && ch <= 0x08)
|| (ch >= 0x0E && ch <= 0x1F)
|| ch == 0x27
|| ch == 0x2D)
{
hasSpecialChars = 1;
}
}
}
mw.Write(hasSpecialChars);
}
}
}
sealed class GuidHeap : SimpleHeap
{
private List<Guid> list = new List<Guid>();
internal GuidHeap()
{
}
internal int Add(Guid guid)
{
Debug.Assert(!frozen);
list.Add(guid);
return list.Count;
}
protected override int GetLength()
{
return list.Count * 16;
}
protected override void WriteImpl(MetadataWriter mw)
{
foreach (Guid guid in list)
{
mw.Write(guid.ToByteArray());
}
}
}
sealed class BlobHeap : SimpleHeap
{
private Key[] map = new Key[8179];
private readonly ByteBuffer buf = new ByteBuffer(32);
private struct Key
{
internal Key[] next;
internal int len;
internal int hash;
internal int offset;
}
internal BlobHeap()
{
buf.Write((byte)0);
}
internal int Add(ByteBuffer bb)
{
Debug.Assert(!frozen);
int bblen = bb.Length;
if (bblen == 0)
{
return 0;
}
int lenlen = MetadataWriter.GetCompressedUIntLength(bblen);
int hash = bb.Hash();
int index = (hash & 0x7FFFFFFF) % map.Length;
Key[] keys = map;
int last = index;
while (keys[index].offset != 0)
{
if (keys[index].hash == hash
&& keys[index].len == bblen
&& buf.Match(keys[index].offset + lenlen, bb, 0, bblen))
{
return keys[index].offset;
}
if (index == last)
{
if (keys[index].next == null)
{
keys[index].next = new Key[4];
keys = keys[index].next;
index = 0;
break;
}
keys = keys[index].next;
index = -1;
last = keys.Length - 1;
}
index++;
}
int offset = buf.Position;
buf.WriteCompressedUInt(bblen);
buf.Write(bb);
keys[index].len = bblen;
keys[index].hash = hash;
keys[index].offset = offset;
return offset;
}
protected override int GetLength()
{
return buf.Position;
}
protected override void WriteImpl(MetadataWriter mw)
{
mw.Write(buf);
}
internal bool IsEmpty
{
get { return buf.Position == 1; }
}
internal IKVM.Reflection.Reader.ByteReader GetBlob(int blobIndex)
{
return buf.GetBlob(blobIndex);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,428 @@
/*
Copyright (C) 2008-2011 Jeroen Frijters
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jeroen Frijters
jeroen@frijters.net
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
using IKVM.Reflection.Emit;
using IKVM.Reflection.Impl;
using IKVM.Reflection.Metadata;
namespace IKVM.Reflection.Writer
{
static class ModuleWriter
{
internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, ModuleBuilder moduleBuilder,
PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine,
ResourceSection resources, int entryPointToken)
{
WriteModule(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPointToken, null);
}
internal static void WriteModule(StrongNameKeyPair keyPair, byte[] publicKey, ModuleBuilder moduleBuilder,
PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine,
ResourceSection resources, int entryPointToken, Stream stream)
{
if (stream == null)
{
string fileName = moduleBuilder.FullyQualifiedName;
bool mono = System.Type.GetType("Mono.Runtime") != null;
if (mono)
{
try
{
// Mono mmaps the file, so unlink the previous version since it may be in use
File.Delete(fileName);
}
catch { }
}
using (FileStream fs = new FileStream(fileName, FileMode.Create))
{
WriteModuleImpl(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPointToken, fs);
}
// if we're running on Mono, mark the module as executable by using a Mono private API extension
if (mono)
{
File.SetAttributes(fileName, (FileAttributes)(unchecked((int)0x80000000)));
}
}
else
{
WriteModuleImpl(keyPair, publicKey, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, resources, entryPointToken, stream);
}
}
private static void WriteModuleImpl(StrongNameKeyPair keyPair, byte[] publicKey, ModuleBuilder moduleBuilder,
PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine,
ResourceSection resources, int entryPointToken, Stream stream)
{
moduleBuilder.ApplyUnmanagedExports(imageFileMachine);
moduleBuilder.FixupMethodBodyTokens();
moduleBuilder.ModuleTable.Add(0, moduleBuilder.Strings.Add(moduleBuilder.moduleName), moduleBuilder.Guids.Add(moduleBuilder.ModuleVersionId), 0, 0);
if (moduleBuilder.UserStrings.IsEmpty)
{
// for compat with Ref.Emit, if there aren't any user strings, we add one
moduleBuilder.UserStrings.Add(" ");
}
if (resources != null)
{
resources.Finish();
}
PEWriter writer = new PEWriter(stream);
writer.Headers.OptionalHeader.FileAlignment = (uint)moduleBuilder.__FileAlignment;
switch (imageFileMachine)
{
case ImageFileMachine.I386:
writer.Headers.FileHeader.Machine = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386;
writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_32BIT_MACHINE;
writer.Headers.OptionalHeader.SizeOfStackReserve = moduleBuilder.GetStackReserve(0x100000);
break;
case ImageFileMachine.ARM:
writer.Headers.FileHeader.Machine = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM;
writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_HEADER.IMAGE_FILE_LARGE_ADDRESS_AWARE;
writer.Headers.OptionalHeader.SizeOfStackReserve = moduleBuilder.GetStackReserve(0x100000);
writer.Headers.OptionalHeader.SectionAlignment = 0x1000;
break;
case ImageFileMachine.AMD64:
writer.Headers.FileHeader.Machine = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64;
writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_LARGE_ADDRESS_AWARE;
writer.Headers.FileHeader.SizeOfOptionalHeader = 0xF0;
writer.Headers.OptionalHeader.Magic = IMAGE_OPTIONAL_HEADER.IMAGE_NT_OPTIONAL_HDR64_MAGIC;
writer.Headers.OptionalHeader.SizeOfStackReserve = moduleBuilder.GetStackReserve(0x400000);
writer.Headers.OptionalHeader.SizeOfStackCommit = 0x4000;
writer.Headers.OptionalHeader.SizeOfHeapCommit = 0x2000;
break;
case ImageFileMachine.IA64:
writer.Headers.FileHeader.Machine = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64;
writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_LARGE_ADDRESS_AWARE;
writer.Headers.FileHeader.SizeOfOptionalHeader = 0xF0;
writer.Headers.OptionalHeader.Magic = IMAGE_OPTIONAL_HEADER.IMAGE_NT_OPTIONAL_HDR64_MAGIC;
writer.Headers.OptionalHeader.SizeOfStackReserve = moduleBuilder.GetStackReserve(0x400000);
writer.Headers.OptionalHeader.SizeOfStackCommit = 0x4000;
writer.Headers.OptionalHeader.SizeOfHeapCommit = 0x2000;
break;
default:
throw new ArgumentOutOfRangeException("imageFileMachine");
}
if (fileKind == PEFileKinds.Dll)
{
writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_DLL;
}
switch (fileKind)
{
case PEFileKinds.WindowApplication:
writer.Headers.OptionalHeader.Subsystem = IMAGE_OPTIONAL_HEADER.IMAGE_SUBSYSTEM_WINDOWS_GUI;
break;
default:
writer.Headers.OptionalHeader.Subsystem = IMAGE_OPTIONAL_HEADER.IMAGE_SUBSYSTEM_WINDOWS_CUI;
break;
}
writer.Headers.OptionalHeader.DllCharacteristics = (ushort)moduleBuilder.__DllCharacteristics;
CliHeader cliHeader = new CliHeader();
cliHeader.Cb = 0x48;
cliHeader.MajorRuntimeVersion = 2;
cliHeader.MinorRuntimeVersion = moduleBuilder.MDStreamVersion < 0x20000 ? (ushort)0 : (ushort)5;
if ((portableExecutableKind & PortableExecutableKinds.ILOnly) != 0)
{
cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_ILONLY;
}
if ((portableExecutableKind & PortableExecutableKinds.Required32Bit) != 0)
{
cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_32BITREQUIRED;
}
if ((portableExecutableKind & PortableExecutableKinds.Preferred32Bit) != 0)
{
cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_32BITREQUIRED | CliHeader.COMIMAGE_FLAGS_32BITPREFERRED;
}
if (keyPair != null)
{
cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_STRONGNAMESIGNED;
}
if (ModuleBuilder.IsPseudoToken(entryPointToken))
{
entryPointToken = moduleBuilder.ResolvePseudoToken(entryPointToken);
}
cliHeader.EntryPointToken = (uint)entryPointToken;
moduleBuilder.Strings.Freeze();
moduleBuilder.UserStrings.Freeze();
moduleBuilder.Guids.Freeze();
moduleBuilder.Blobs.Freeze();
MetadataWriter mw = new MetadataWriter(moduleBuilder, stream);
moduleBuilder.Tables.Freeze(mw);
TextSection code = new TextSection(writer, cliHeader, moduleBuilder, ComputeStrongNameSignatureLength(publicKey));
// Export Directory
if (code.ExportDirectoryLength != 0)
{
writer.Headers.OptionalHeader.DataDirectory[0].VirtualAddress = code.ExportDirectoryRVA;
writer.Headers.OptionalHeader.DataDirectory[0].Size = code.ExportDirectoryLength;
}
// Import Directory
if (code.ImportDirectoryLength != 0)
{
writer.Headers.OptionalHeader.DataDirectory[1].VirtualAddress = code.ImportDirectoryRVA;
writer.Headers.OptionalHeader.DataDirectory[1].Size = code.ImportDirectoryLength;
}
// Import Address Table Directory
if (code.ImportAddressTableLength != 0)
{
writer.Headers.OptionalHeader.DataDirectory[12].VirtualAddress = code.ImportAddressTableRVA;
writer.Headers.OptionalHeader.DataDirectory[12].Size = code.ImportAddressTableLength;
}
// COM Descriptor Directory
writer.Headers.OptionalHeader.DataDirectory[14].VirtualAddress = code.ComDescriptorRVA;
writer.Headers.OptionalHeader.DataDirectory[14].Size = code.ComDescriptorLength;
// Debug Directory
if (code.DebugDirectoryLength != 0)
{
writer.Headers.OptionalHeader.DataDirectory[6].VirtualAddress = code.DebugDirectoryRVA;
writer.Headers.OptionalHeader.DataDirectory[6].Size = code.DebugDirectoryLength;
}
// we need to start by computing the number of sections, because code.PointerToRawData depends on that
writer.Headers.FileHeader.NumberOfSections = 2;
if (moduleBuilder.initializedData.Length != 0)
{
// .sdata
writer.Headers.FileHeader.NumberOfSections++;
}
if (resources != null)
{
// .rsrc
writer.Headers.FileHeader.NumberOfSections++;
}
SectionHeader text = new SectionHeader();
text.Name = ".text";
text.VirtualAddress = code.BaseRVA;
text.VirtualSize = (uint)code.Length;
text.PointerToRawData = code.PointerToRawData;
text.SizeOfRawData = writer.ToFileAlignment((uint)code.Length);
text.Characteristics = SectionHeader.IMAGE_SCN_CNT_CODE | SectionHeader.IMAGE_SCN_MEM_EXECUTE | SectionHeader.IMAGE_SCN_MEM_READ;
SectionHeader sdata = new SectionHeader();
sdata.Name = ".sdata";
sdata.VirtualAddress = text.VirtualAddress + writer.ToSectionAlignment(text.VirtualSize);
sdata.VirtualSize = (uint)moduleBuilder.initializedData.Length;
sdata.PointerToRawData = text.PointerToRawData + text.SizeOfRawData;
sdata.SizeOfRawData = writer.ToFileAlignment((uint)moduleBuilder.initializedData.Length);
sdata.Characteristics = SectionHeader.IMAGE_SCN_CNT_INITIALIZED_DATA | SectionHeader.IMAGE_SCN_MEM_READ | SectionHeader.IMAGE_SCN_MEM_WRITE;
SectionHeader rsrc = new SectionHeader();
rsrc.Name = ".rsrc";
rsrc.VirtualAddress = sdata.VirtualAddress + writer.ToSectionAlignment(sdata.VirtualSize);
rsrc.PointerToRawData = sdata.PointerToRawData + sdata.SizeOfRawData;
rsrc.VirtualSize = resources == null ? 0 : (uint)resources.Length;
rsrc.SizeOfRawData = writer.ToFileAlignment(rsrc.VirtualSize);
rsrc.Characteristics = SectionHeader.IMAGE_SCN_MEM_READ | SectionHeader.IMAGE_SCN_CNT_INITIALIZED_DATA;
if (rsrc.SizeOfRawData != 0)
{
// Resource Directory
writer.Headers.OptionalHeader.DataDirectory[2].VirtualAddress = rsrc.VirtualAddress;
writer.Headers.OptionalHeader.DataDirectory[2].Size = rsrc.VirtualSize;
}
SectionHeader reloc = new SectionHeader();
reloc.Name = ".reloc";
reloc.VirtualAddress = rsrc.VirtualAddress + writer.ToSectionAlignment(rsrc.VirtualSize);
reloc.VirtualSize = code.PackRelocations();
reloc.PointerToRawData = rsrc.PointerToRawData + rsrc.SizeOfRawData;
reloc.SizeOfRawData = writer.ToFileAlignment(reloc.VirtualSize);
reloc.Characteristics = SectionHeader.IMAGE_SCN_MEM_READ | SectionHeader.IMAGE_SCN_CNT_INITIALIZED_DATA | SectionHeader.IMAGE_SCN_MEM_DISCARDABLE;
if (reloc.SizeOfRawData != 0)
{
// Base Relocation Directory
writer.Headers.OptionalHeader.DataDirectory[5].VirtualAddress = reloc.VirtualAddress;
writer.Headers.OptionalHeader.DataDirectory[5].Size = reloc.VirtualSize;
}
writer.Headers.OptionalHeader.SizeOfCode = text.SizeOfRawData;
writer.Headers.OptionalHeader.SizeOfInitializedData = sdata.SizeOfRawData + rsrc.SizeOfRawData + reloc.SizeOfRawData;
writer.Headers.OptionalHeader.SizeOfUninitializedData = 0;
writer.Headers.OptionalHeader.SizeOfImage = reloc.VirtualAddress + writer.ToSectionAlignment(reloc.VirtualSize);
writer.Headers.OptionalHeader.SizeOfHeaders = text.PointerToRawData;
writer.Headers.OptionalHeader.BaseOfCode = code.BaseRVA;
writer.Headers.OptionalHeader.BaseOfData = sdata.VirtualAddress;
writer.Headers.OptionalHeader.ImageBase = (ulong)moduleBuilder.__ImageBase;
if (imageFileMachine == ImageFileMachine.IA64)
{
// apparently for IA64 AddressOfEntryPoint points to the address of the entry point
// (i.e. there is an additional layer of indirection), so we add the offset to the pointer
writer.Headers.OptionalHeader.AddressOfEntryPoint = code.StartupStubRVA + 0x20;
}
else
{
writer.Headers.OptionalHeader.AddressOfEntryPoint = code.StartupStubRVA + writer.Thumb;
}
writer.WritePEHeaders();
writer.WriteSectionHeader(text);
if (sdata.SizeOfRawData != 0)
{
writer.WriteSectionHeader(sdata);
}
if (rsrc.SizeOfRawData != 0)
{
writer.WriteSectionHeader(rsrc);
}
if (reloc.SizeOfRawData != 0)
{
writer.WriteSectionHeader(reloc);
}
stream.Seek(text.PointerToRawData, SeekOrigin.Begin);
code.Write(mw, sdata.VirtualAddress);
if (sdata.SizeOfRawData != 0)
{
stream.Seek(sdata.PointerToRawData, SeekOrigin.Begin);
mw.Write(moduleBuilder.initializedData);
}
if (rsrc.SizeOfRawData != 0)
{
stream.Seek(rsrc.PointerToRawData, SeekOrigin.Begin);
resources.Write(mw, rsrc.VirtualAddress);
}
if (reloc.SizeOfRawData != 0)
{
stream.Seek(reloc.PointerToRawData, SeekOrigin.Begin);
code.WriteRelocations(mw);
}
// file alignment
stream.SetLength(reloc.PointerToRawData + reloc.SizeOfRawData);
// do the strong naming
if (keyPair != null)
{
StrongName(stream, keyPair, writer.HeaderSize, text.PointerToRawData, code.StrongNameSignatureRVA - text.VirtualAddress + text.PointerToRawData, code.StrongNameSignatureLength);
}
if (moduleBuilder.symbolWriter != null)
{
moduleBuilder.WriteSymbolTokenMap();
moduleBuilder.symbolWriter.Close();
}
}
private static int ComputeStrongNameSignatureLength(byte[] publicKey)
{
if (publicKey == null)
{
return 0;
}
else if (publicKey.Length == 16)
{
// it must be the ECMA pseudo public key, we don't know the key size of the real key, but currently both Mono and Microsoft use a 1024 bit key size
return 128;
}
else
{
// for the supported strong naming algorithms, the signature size is the same as the key size
// (we have to subtract 32 for the header)
return publicKey.Length - 32;
}
}
private static void StrongName(Stream stream, StrongNameKeyPair keyPair, uint headerLength, uint textSectionFileOffset, uint strongNameSignatureFileOffset, uint strongNameSignatureLength)
{
SHA1Managed hash = new SHA1Managed();
using (CryptoStream cs = new CryptoStream(Stream.Null, hash, CryptoStreamMode.Write))
{
stream.Seek(0, SeekOrigin.Begin);
byte[] buf = new byte[8192];
HashChunk(stream, cs, buf, (int)headerLength);
stream.Seek(textSectionFileOffset, SeekOrigin.Begin);
HashChunk(stream, cs, buf, (int)(strongNameSignatureFileOffset - textSectionFileOffset));
stream.Seek(strongNameSignatureLength, SeekOrigin.Current);
HashChunk(stream, cs, buf, (int)(stream.Length - (strongNameSignatureFileOffset + strongNameSignatureLength)));
}
using (RSA rsa = keyPair.CreateRSA())
{
RSAPKCS1SignatureFormatter sign = new RSAPKCS1SignatureFormatter(rsa);
byte[] signature = sign.CreateSignature(hash);
Array.Reverse(signature);
if (signature.Length != strongNameSignatureLength)
{
throw new InvalidOperationException("Signature length mismatch");
}
stream.Seek(strongNameSignatureFileOffset, SeekOrigin.Begin);
stream.Write(signature, 0, signature.Length);
}
// compute the PE checksum
stream.Seek(0, SeekOrigin.Begin);
int count = (int)stream.Length / 4;
BinaryReader br = new BinaryReader(stream);
long sum = 0;
for (int i = 0; i < count; i++)
{
sum += br.ReadUInt32();
int carry = (int)(sum >> 32);
sum &= 0xFFFFFFFFU;
sum += carry;
}
while ((sum >> 16) != 0)
{
sum = (sum & 0xFFFF) + (sum >> 16);
}
sum += stream.Length;
// write the PE checksum, note that it is always at offset 0xD8 in the file
ByteBuffer bb = new ByteBuffer(4);
bb.Write((int)sum);
stream.Seek(0xD8, SeekOrigin.Begin);
bb.WriteTo(stream);
}
internal static void HashChunk(Stream stream, CryptoStream cs, byte[] buf, int length)
{
while (length > 0)
{
int read = stream.Read(buf, 0, Math.Min(buf.Length, length));
cs.Write(buf, 0, read);
length -= read;
}
}
}
}

287
external/ikvm/reflect/Writer/PEWriter.cs vendored Normal file
View File

@@ -0,0 +1,287 @@
/*
Copyright (C) 2008-2013 Jeroen Frijters
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jeroen Frijters
jeroen@frijters.net
*/
using System;
using System.IO;
using BYTE = System.Byte;
using WORD = System.UInt16;
using DWORD = System.UInt32;
using ULONGLONG = System.UInt64;
using IMAGE_DATA_DIRECTORY = IKVM.Reflection.Reader.IMAGE_DATA_DIRECTORY;
namespace IKVM.Reflection.Writer
{
sealed class PEWriter
{
private readonly BinaryWriter bw;
private readonly IMAGE_NT_HEADERS hdr = new IMAGE_NT_HEADERS();
internal PEWriter(Stream stream)
{
bw = new BinaryWriter(stream);
WriteMSDOSHeader();
}
public IMAGE_NT_HEADERS Headers
{
get { return hdr; }
}
public uint HeaderSize
{
get
{
return (uint)
((8 * 16) + // MSDOS header
4 + // signature
20 + // IMAGE_FILE_HEADER
hdr.FileHeader.SizeOfOptionalHeader +
hdr.FileHeader.NumberOfSections * 40);
}
}
private void WriteMSDOSHeader()
{
bw.Write(new byte[] {
0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD,
0x21, 0xB8, 0x01, 0x4C, 0xCD, 0x21, 0x54, 0x68,
0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72,
0x61, 0x6D, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F,
0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E,
0x20, 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20,
0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x0D, 0x0D, 0x0A,
0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
});
}
internal void WritePEHeaders()
{
bw.Write(hdr.Signature);
// IMAGE_FILE_HEADER
bw.Write(hdr.FileHeader.Machine);
bw.Write(hdr.FileHeader.NumberOfSections);
bw.Write(hdr.FileHeader.TimeDateStamp);
bw.Write(hdr.FileHeader.PointerToSymbolTable);
bw.Write(hdr.FileHeader.NumberOfSymbols);
bw.Write(hdr.FileHeader.SizeOfOptionalHeader);
bw.Write(hdr.FileHeader.Characteristics);
// IMAGE_OPTIONAL_HEADER
hdr.OptionalHeader.Write(bw);
}
internal void WriteSectionHeader(SectionHeader sectionHeader)
{
byte[] name = new byte[8];
System.Text.Encoding.UTF8.GetBytes(sectionHeader.Name, 0, sectionHeader.Name.Length, name, 0);
bw.Write(name);
bw.Write(sectionHeader.VirtualSize);
bw.Write(sectionHeader.VirtualAddress);
bw.Write(sectionHeader.SizeOfRawData);
bw.Write(sectionHeader.PointerToRawData);
bw.Write(sectionHeader.PointerToRelocations);
bw.Write(sectionHeader.PointerToLinenumbers);
bw.Write(sectionHeader.NumberOfRelocations);
bw.Write(sectionHeader.NumberOfLinenumbers);
bw.Write(sectionHeader.Characteristics);
}
internal uint ToFileAlignment(uint p)
{
return (p + (Headers.OptionalHeader.FileAlignment - 1)) & ~(Headers.OptionalHeader.FileAlignment - 1);
}
internal uint ToSectionAlignment(uint p)
{
return (p + (Headers.OptionalHeader.SectionAlignment - 1)) & ~(Headers.OptionalHeader.SectionAlignment - 1);
}
internal bool Is32Bit
{
get { return (Headers.FileHeader.Characteristics & IMAGE_FILE_HEADER.IMAGE_FILE_32BIT_MACHINE) != 0; }
}
internal uint Thumb
{
// On ARM we need to set the least significant bit of the program counter to select the Thumb instruction set
get { return Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_ARM ? 1u : 0u; }
}
}
sealed class IMAGE_NT_HEADERS
{
public DWORD Signature = 0x00004550; // "PE\0\0"
public IMAGE_FILE_HEADER FileHeader = new IMAGE_FILE_HEADER();
public IMAGE_OPTIONAL_HEADER OptionalHeader = new IMAGE_OPTIONAL_HEADER();
}
sealed class IMAGE_FILE_HEADER
{
public const WORD IMAGE_FILE_MACHINE_I386 = 0x014c;
public const WORD IMAGE_FILE_MACHINE_ARM = 0x01c4;
public const WORD IMAGE_FILE_MACHINE_IA64 = 0x0200;
public const WORD IMAGE_FILE_MACHINE_AMD64 = 0x8664;
public const WORD IMAGE_FILE_32BIT_MACHINE = 0x0100;
public const WORD IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002;
public const WORD IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020;
public const WORD IMAGE_FILE_DLL = 0x2000;
public WORD Machine;
public WORD NumberOfSections;
public DWORD TimeDateStamp = (uint)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;
public DWORD PointerToSymbolTable = 0;
public DWORD NumberOfSymbols = 0;
public WORD SizeOfOptionalHeader = 0xE0;
public WORD Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
}
sealed class IMAGE_OPTIONAL_HEADER
{
public const WORD IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b;
public const WORD IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b;
public const WORD IMAGE_SUBSYSTEM_WINDOWS_GUI = 2;
public const WORD IMAGE_SUBSYSTEM_WINDOWS_CUI = 3;
public WORD Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC;
public BYTE MajorLinkerVersion = 8;
public BYTE MinorLinkerVersion = 0;
public DWORD SizeOfCode;
public DWORD SizeOfInitializedData;
public DWORD SizeOfUninitializedData;
public DWORD AddressOfEntryPoint;
public DWORD BaseOfCode;
public DWORD BaseOfData;
public ULONGLONG ImageBase;
public DWORD SectionAlignment = 0x2000;
public DWORD FileAlignment;
public WORD MajorOperatingSystemVersion = 4;
public WORD MinorOperatingSystemVersion = 0;
public WORD MajorImageVersion = 0;
public WORD MinorImageVersion = 0;
public WORD MajorSubsystemVersion = 4;
public WORD MinorSubsystemVersion = 0;
public DWORD Win32VersionValue = 0;
public DWORD SizeOfImage;
public DWORD SizeOfHeaders;
public DWORD CheckSum = 0;
public WORD Subsystem;
public WORD DllCharacteristics;
public ULONGLONG SizeOfStackReserve;
public ULONGLONG SizeOfStackCommit = 0x1000;
public ULONGLONG SizeOfHeapReserve = 0x100000;
public ULONGLONG SizeOfHeapCommit = 0x1000;
public DWORD LoaderFlags = 0;
public DWORD NumberOfRvaAndSizes = 16;
public IMAGE_DATA_DIRECTORY[] DataDirectory = new IMAGE_DATA_DIRECTORY[16];
internal void Write(BinaryWriter bw)
{
bw.Write(Magic);
bw.Write(MajorLinkerVersion);
bw.Write(MinorLinkerVersion);
bw.Write(SizeOfCode);
bw.Write(SizeOfInitializedData);
bw.Write(SizeOfUninitializedData);
bw.Write(AddressOfEntryPoint);
bw.Write(BaseOfCode);
if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
{
bw.Write(BaseOfData);
bw.Write((DWORD)ImageBase);
}
else
{
bw.Write(ImageBase);
}
bw.Write(SectionAlignment);
bw.Write(FileAlignment);
bw.Write(MajorOperatingSystemVersion);
bw.Write(MinorOperatingSystemVersion);
bw.Write(MajorImageVersion);
bw.Write(MinorImageVersion);
bw.Write(MajorSubsystemVersion);
bw.Write(MinorSubsystemVersion);
bw.Write(Win32VersionValue);
bw.Write(SizeOfImage);
bw.Write(SizeOfHeaders);
bw.Write(CheckSum);
bw.Write(Subsystem);
bw.Write(DllCharacteristics);
if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
{
bw.Write((DWORD)SizeOfStackReserve);
bw.Write((DWORD)SizeOfStackCommit);
bw.Write((DWORD)SizeOfHeapReserve);
bw.Write((DWORD)SizeOfHeapCommit);
}
else
{
bw.Write(SizeOfStackReserve);
bw.Write(SizeOfStackCommit);
bw.Write(SizeOfHeapReserve);
bw.Write(SizeOfHeapCommit);
}
bw.Write(LoaderFlags);
bw.Write(NumberOfRvaAndSizes);
for (int i = 0; i < DataDirectory.Length; i++)
{
bw.Write(DataDirectory[i].VirtualAddress);
bw.Write(DataDirectory[i].Size);
}
}
}
class SectionHeader
{
public const DWORD IMAGE_SCN_CNT_CODE = 0x00000020;
public const DWORD IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040;
public const DWORD IMAGE_SCN_MEM_DISCARDABLE = 0x02000000;
public const DWORD IMAGE_SCN_MEM_EXECUTE = 0x20000000;
public const DWORD IMAGE_SCN_MEM_READ = 0x40000000;
public const DWORD IMAGE_SCN_MEM_WRITE = 0x80000000;
public string Name; // 8 byte UTF8 encoded 0-padded
public DWORD VirtualSize;
public DWORD VirtualAddress;
public DWORD SizeOfRawData;
public DWORD PointerToRawData;
#pragma warning disable 649 // the follow fields are never assigned to
public DWORD PointerToRelocations;
public DWORD PointerToLinenumbers;
public WORD NumberOfRelocations;
public WORD NumberOfLinenumbers;
#pragma warning restore 649
public DWORD Characteristics;
}
}

View File

@@ -0,0 +1,411 @@
/*
Copyright (C) 2010-2012 Jeroen Frijters
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jeroen Frijters
jeroen@frijters.net
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using IKVM.Reflection.Reader;
namespace IKVM.Reflection.Writer
{
sealed class ResourceSection
{
private const int RT_ICON = 3;
private const int RT_GROUP_ICON = 14;
private const int RT_VERSION = 16;
private const int RT_MANIFEST = 24;
private ResourceDirectoryEntry root = new ResourceDirectoryEntry(new OrdinalOrName("root"));
private ByteBuffer bb;
private List<int> linkOffsets;
internal void AddVersionInfo(ByteBuffer versionInfo)
{
root[new OrdinalOrName(RT_VERSION)][new OrdinalOrName(1)][new OrdinalOrName(0)].Data = versionInfo;
}
internal void AddIcon(byte[] iconFile)
{
BinaryReader br = new BinaryReader(new MemoryStream(iconFile));
ushort idReserved = br.ReadUInt16();
ushort idType = br.ReadUInt16();
ushort idCount = br.ReadUInt16();
if (idReserved != 0 || idType != 1)
{
throw new ArgumentException("The supplied byte array is not a valid .ico file.");
}
ByteBuffer group = new ByteBuffer(6 + 14 * idCount);
group.Write(idReserved);
group.Write(idType);
group.Write(idCount);
for (int i = 0; i < idCount; i++)
{
byte bWidth = br.ReadByte();
byte bHeight = br.ReadByte();
byte bColorCount = br.ReadByte();
byte bReserved = br.ReadByte();
ushort wPlanes = br.ReadUInt16();
ushort wBitCount = br.ReadUInt16();
uint dwBytesInRes = br.ReadUInt32();
uint dwImageOffset = br.ReadUInt32();
// we start the icon IDs at 2
ushort id = (ushort)(2 + i);
group.Write(bWidth);
group.Write(bHeight);
group.Write(bColorCount);
group.Write(bReserved);
group.Write(wPlanes);
group.Write(wBitCount);
group.Write(dwBytesInRes);
group.Write(id);
byte[] icon = new byte[dwBytesInRes];
Buffer.BlockCopy(iconFile, (int)dwImageOffset, icon, 0, icon.Length);
root[new OrdinalOrName(RT_ICON)][new OrdinalOrName(id)][new OrdinalOrName(0)].Data = ByteBuffer.Wrap(icon);
}
root[new OrdinalOrName(RT_GROUP_ICON)][new OrdinalOrName(32512)][new OrdinalOrName(0)].Data = group;
}
internal void AddManifest(byte[] manifest, ushort resourceID)
{
root[new OrdinalOrName(RT_MANIFEST)][new OrdinalOrName(resourceID)][new OrdinalOrName(0)].Data = ByteBuffer.Wrap(manifest);
}
internal void ExtractResources(byte[] buf)
{
ByteReader br = new ByteReader(buf, 0, buf.Length);
while (br.Length >= 32)
{
br.Align(4);
RESOURCEHEADER hdr = new RESOURCEHEADER(br);
if (hdr.DataSize != 0)
{
root[hdr.TYPE][hdr.NAME][new OrdinalOrName(hdr.LanguageId)].Data = ByteBuffer.Wrap(br.ReadBytes(hdr.DataSize));
}
}
}
internal void Finish()
{
if (bb != null)
{
throw new InvalidOperationException();
}
bb = new ByteBuffer(1024);
linkOffsets = new List<int>();
root.Write(bb, linkOffsets);
root = null;
}
internal int Length
{
get { return bb.Length; }
}
internal void Write(MetadataWriter mw, uint rva)
{
foreach (int offset in linkOffsets)
{
bb.Position = offset;
bb.Write(bb.GetInt32AtCurrentPosition() + (int)rva);
}
mw.Write(bb);
}
}
sealed class ResourceDirectoryEntry
{
internal readonly OrdinalOrName OrdinalOrName;
internal ByteBuffer Data;
private int namedEntries;
private readonly List<ResourceDirectoryEntry> entries = new List<ResourceDirectoryEntry>();
internal ResourceDirectoryEntry(OrdinalOrName id)
{
this.OrdinalOrName = id;
}
internal ResourceDirectoryEntry this[OrdinalOrName id]
{
get
{
foreach (ResourceDirectoryEntry entry in entries)
{
if (entry.OrdinalOrName.IsEqual(id))
{
return entry;
}
}
// the entries must be sorted
ResourceDirectoryEntry newEntry = new ResourceDirectoryEntry(id);
if (id.Name == null)
{
for (int i = namedEntries; i < entries.Count; i++)
{
if (entries[i].OrdinalOrName.IsGreaterThan(id))
{
entries.Insert(i, newEntry);
return newEntry;
}
}
entries.Add(newEntry);
return newEntry;
}
else
{
for (int i = 0; i < namedEntries; i++)
{
if (entries[i].OrdinalOrName.IsGreaterThan(id))
{
entries.Insert(i, newEntry);
namedEntries++;
return newEntry;
}
}
entries.Insert(namedEntries++, newEntry);
return newEntry;
}
}
}
private int DirectoryLength
{
get
{
if (Data != null)
{
return 16;
}
else
{
int length = 16 + entries.Count * 8;
foreach (ResourceDirectoryEntry entry in entries)
{
length += entry.DirectoryLength;
}
return length;
}
}
}
internal void Write(ByteBuffer bb, List<int> linkOffsets)
{
if (entries.Count != 0)
{
int stringTableOffset = this.DirectoryLength;
Dictionary<string, int> strings = new Dictionary<string, int>();
ByteBuffer stringTable = new ByteBuffer(16);
int offset = 16 + entries.Count * 8;
for (int pass = 0; pass < 3; pass++)
{
Write(bb, pass, 0, ref offset, strings, ref stringTableOffset, stringTable);
}
// the pecoff spec says that the string table is between the directory entries and the data entries,
// but the windows linker puts them after the data entries, so we do too.
stringTable.Align(4);
offset += stringTable.Length;
WriteResourceDataEntries(bb, linkOffsets, ref offset);
bb.Write(stringTable);
WriteData(bb);
}
}
private void WriteResourceDataEntries(ByteBuffer bb, List<int> linkOffsets, ref int offset)
{
foreach (ResourceDirectoryEntry entry in entries)
{
if (entry.Data != null)
{
linkOffsets.Add(bb.Position);
bb.Write(offset);
bb.Write(entry.Data.Length);
bb.Write(0); // code page
bb.Write(0); // reserved
offset += (entry.Data.Length + 3) & ~3;
}
else
{
entry.WriteResourceDataEntries(bb, linkOffsets, ref offset);
}
}
}
private void WriteData(ByteBuffer bb)
{
foreach (ResourceDirectoryEntry entry in entries)
{
if (entry.Data != null)
{
bb.Write(entry.Data);
bb.Align(4);
}
else
{
entry.WriteData(bb);
}
}
}
private void Write(ByteBuffer bb, int writeDepth, int currentDepth, ref int offset, Dictionary<string, int> strings, ref int stringTableOffset, ByteBuffer stringTable)
{
if (currentDepth == writeDepth)
{
// directory header
bb.Write(0); // Characteristics
bb.Write(0); // Time/Date Stamp
bb.Write(0); // Version (Major / Minor)
bb.Write((ushort)namedEntries);
bb.Write((ushort)(entries.Count - namedEntries));
}
foreach (ResourceDirectoryEntry entry in entries)
{
if (currentDepth == writeDepth)
{
entry.WriteEntry(bb, ref offset, strings, ref stringTableOffset, stringTable);
}
else
{
entry.Write(bb, writeDepth, currentDepth + 1, ref offset, strings, ref stringTableOffset, stringTable);
}
}
}
private void WriteEntry(ByteBuffer bb, ref int offset, Dictionary<string, int> strings, ref int stringTableOffset, ByteBuffer stringTable)
{
WriteNameOrOrdinal(bb, OrdinalOrName, strings, ref stringTableOffset, stringTable);
if (Data == null)
{
bb.Write(0x80000000U | (uint)offset);
}
else
{
bb.Write(offset);
}
offset += 16 + entries.Count * 8;
}
private static void WriteNameOrOrdinal(ByteBuffer bb, OrdinalOrName id, Dictionary<string, int> strings, ref int stringTableOffset, ByteBuffer stringTable)
{
if (id.Name == null)
{
bb.Write((int)id.Ordinal);
}
else
{
int stringOffset;
if (!strings.TryGetValue(id.Name, out stringOffset))
{
stringOffset = stringTableOffset;
strings.Add(id.Name, stringOffset);
stringTableOffset += id.Name.Length * 2 + 2;
stringTable.Write((ushort)id.Name.Length);
foreach (char c in id.Name)
{
stringTable.Write((short)c);
}
}
bb.Write(0x80000000U | (uint)stringOffset);
}
}
}
struct OrdinalOrName
{
internal readonly ushort Ordinal;
internal readonly string Name;
internal OrdinalOrName(ushort value)
{
Ordinal = value;
Name = null;
}
internal OrdinalOrName(string value)
{
Ordinal = 0xFFFF;
Name = value;
}
internal bool IsGreaterThan(OrdinalOrName other)
{
return this.Name == null
? this.Ordinal > other.Ordinal
: String.Compare(this.Name, other.Name, StringComparison.OrdinalIgnoreCase) > 0;
}
internal bool IsEqual(OrdinalOrName other)
{
return this.Name == null
? this.Ordinal == other.Ordinal
: String.Compare(this.Name, other.Name, StringComparison.OrdinalIgnoreCase) == 0;
}
}
struct RESOURCEHEADER
{
internal int DataSize;
internal int HeaderSize;
internal OrdinalOrName TYPE;
internal OrdinalOrName NAME;
internal int DataVersion;
internal ushort MemoryFlags;
internal ushort LanguageId;
internal int Version;
internal int Characteristics;
internal RESOURCEHEADER(ByteReader br)
{
DataSize = br.ReadInt32();
HeaderSize = br.ReadInt32();
TYPE = ReadOrdinalOrName(br);
NAME = ReadOrdinalOrName(br);
br.Align(4);
DataVersion = br.ReadInt32();
MemoryFlags = br.ReadUInt16();
LanguageId = br.ReadUInt16();
Version = br.ReadInt32();
Characteristics = br.ReadInt32();
}
private static OrdinalOrName ReadOrdinalOrName(ByteReader br)
{
char c = br.ReadChar();
if (c == 0xFFFF)
{
return new OrdinalOrName(br.ReadUInt16());
}
else
{
StringBuilder sb = new StringBuilder();
while (c != 0)
{
sb.Append(c);
c = br.ReadChar();
}
return new OrdinalOrName(sb.ToString());
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,278 @@
/*
Copyright (C) 2008 Jeroen Frijters
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jeroen Frijters
jeroen@frijters.net
*/
using System;
using System.Globalization;
using IKVM.Reflection.Emit;
namespace IKVM.Reflection.Writer
{
sealed class VersionInfo
{
private AssemblyName name;
private string fileName;
internal string copyright;
internal string trademark;
internal string product;
internal string company;
private string description;
private string title;
internal string informationalVersion;
private string fileVersion;
internal void SetName(AssemblyName name)
{
this.name = name;
}
internal void SetFileName(string assemblyFileName)
{
this.fileName = System.IO.Path.GetFileName(assemblyFileName);
}
internal void SetAttribute(CustomAttributeBuilder cab)
{
Universe u = cab.Constructor.Module.universe;
Type type = cab.Constructor.DeclaringType;
if (copyright == null && type == u.System_Reflection_AssemblyCopyrightAttribute)
{
copyright = (string)cab.GetConstructorArgument(0);
}
else if (trademark == null && type == u.System_Reflection_AssemblyTrademarkAttribute)
{
trademark = (string)cab.GetConstructorArgument(0);
}
else if (product == null && type == u.System_Reflection_AssemblyProductAttribute)
{
product = (string)cab.GetConstructorArgument(0);
}
else if (company == null && type == u.System_Reflection_AssemblyCompanyAttribute)
{
company = (string)cab.GetConstructorArgument(0);
}
else if (description == null && type == u.System_Reflection_AssemblyDescriptionAttribute)
{
description = (string)cab.GetConstructorArgument(0);
}
else if (title == null && type == u.System_Reflection_AssemblyTitleAttribute)
{
title = (string)cab.GetConstructorArgument(0);
}
else if (informationalVersion == null && type == u.System_Reflection_AssemblyInformationalVersionAttribute)
{
informationalVersion = (string)cab.GetConstructorArgument(0);
}
else if (fileVersion == null && type == u.System_Reflection_AssemblyFileVersionAttribute)
{
fileVersion = (string)cab.GetConstructorArgument(0);
}
}
internal void Write(ByteBuffer bb)
{
if (fileVersion == null)
{
if (name.Version != null)
{
fileVersion = name.Version.ToString();
}
else
{
fileVersion = "0.0.0.0";
}
}
int codepage = 1200; // Unicode codepage
int lcid = 0x7f;
try
{
if (name.CultureInfo != null)
{
lcid = name.CultureInfo.LCID;
}
}
catch (ArgumentException)
{
// AssemblyName.CultureInfo throws an ArgumentException if AssemblyBuilder.__SetAssemblyCulture() was used to specify a non-existing culture
}
Version filever = ParseVersionRobust(fileVersion);
int fileVersionMajor = filever.Major;
int fileVersionMinor = filever.Minor;
int fileVersionBuild = filever.Build;
int fileVersionRevision = filever.Revision;
int productVersionMajor = fileVersionMajor;
int productVersionMinor = fileVersionMinor;
int productVersionBuild = fileVersionBuild;
int productVersionRevision = fileVersionRevision;
if (informationalVersion != null)
{
Version productver = ParseVersionRobust(informationalVersion);
productVersionMajor = productver.Major;
productVersionMinor = productver.Minor;
productVersionBuild = productver.Build;
productVersionRevision = productver.Revision;
}
ByteBuffer stringTable = new ByteBuffer(512);
stringTable.Write((short)0); // wLength (placeholder)
stringTable.Write((short)0); // wValueLength
stringTable.Write((short)1); // wType
WriteUTF16Z(stringTable, string.Format("{0:x4}{1:x4}", lcid, codepage));
stringTable.Align(4);
WriteString(stringTable, "Comments", description);
WriteString(stringTable, "CompanyName", company);
WriteString(stringTable, "FileDescription", title);
WriteString(stringTable, "FileVersion", fileVersion);
WriteString(stringTable, "InternalName", name.Name);
WriteString(stringTable, "LegalCopyright", copyright);
WriteString(stringTable, "LegalTrademarks", trademark);
WriteString(stringTable, "OriginalFilename", fileName);
WriteString(stringTable, "ProductName", product);
WriteString(stringTable, "ProductVersion", informationalVersion);
stringTable.Position = 0;
stringTable.Write((short)stringTable.Length);
ByteBuffer stringFileInfo = new ByteBuffer(512);
stringFileInfo.Write((short)0); // wLength (placeholder)
stringFileInfo.Write((short)0); // wValueLength
stringFileInfo.Write((short)1); // wType
WriteUTF16Z(stringFileInfo, "StringFileInfo");
stringFileInfo.Align(4);
stringFileInfo.Write(stringTable);
stringFileInfo.Position = 0;
stringFileInfo.Write((short)stringFileInfo.Length);
byte[] preamble1 = new byte[] {
// VS_VERSIONINFO (platform SDK)
0x34, 0x00, // wValueLength
0x00, 0x00, // wType
0x56, 0x00, 0x53, 0x00, 0x5F, 0x00, 0x56, 0x00, 0x45, 0x00, 0x52, 0x00, 0x53, 0x00, 0x49, 0x00, 0x4F, 0x00, 0x4E, 0x00, 0x5F, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x46, 0x00, 0x4F, 0x00, 0x00, 0x00, // "VS_VERSION_INFO\0"
0x00, 0x00, // Padding1 (32 bit alignment)
// VS_FIXEDFILEINFO starts
0xBD, 0x04, 0xEF, 0xFE, // dwSignature (0xFEEF04BD)
0x00, 0x00, 0x01, 0x00, // dwStrucVersion
};
byte[] preamble2 = new byte[] {
0x3F, 0x00, 0x00, 0x00, // dwFileFlagsMask (??)
0x00, 0x00, 0x00, 0x00, // dwFileFlags (??)
0x04, 0x00, 0x00, 0x00, // dwFileOS
0x02, 0x00, 0x00, 0x00, // dwFileType
0x00, 0x00, 0x00, 0x00, // dwFileSubtype
0x00, 0x00, 0x00, 0x00, // dwFileDateMS
0x00, 0x00, 0x00, 0x00, // dwFileDateLS
// Padding2 (32 bit alignment)
// VarFileInfo
0x44, 0x00, // wLength
0x00, 0x00, // wValueLength
0x01, 0x00, // wType
0x56, 0x00, 0x61, 0x00, 0x72, 0x00, 0x46, 0x00, 0x69, 0x00, 0x6C, 0x00, 0x65, 0x00, 0x49, 0x00, 0x6E, 0x00, 0x66, 0x00, 0x6F, 0x00, 0x00, 0x00, // "VarFileInfo\0"
0x00, 0x00, // Padding
// Var
0x24, 0x00, // wLength
0x04, 0x00, // wValueLength
0x00, 0x00, // wType
0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x6E, 0x00, 0x73, 0x00, 0x6C, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x00, 0x00, // "Translation\0"
0x00, 0x00, // Padding (32 bit alignment)
};
bb.Write((short)(2 + preamble1.Length + 8 + 8 + preamble2.Length + 4 + stringFileInfo.Length));
bb.Write(preamble1);
bb.Write((short)fileVersionMinor);
bb.Write((short)fileVersionMajor);
bb.Write((short)fileVersionRevision);
bb.Write((short)fileVersionBuild);
bb.Write((short)productVersionMinor);
bb.Write((short)productVersionMajor);
bb.Write((short)productVersionRevision);
bb.Write((short)productVersionBuild);
bb.Write(preamble2);
bb.Write((short)lcid);
bb.Write((short)codepage);
bb.Write(stringFileInfo);
}
private static void WriteUTF16Z(ByteBuffer bb, string str)
{
foreach (char c in str)
{
bb.Write((short)c);
}
bb.Write((short)0);
}
private static void WriteString(ByteBuffer bb, string name, string value)
{
value = value ?? " ";
int pos = bb.Position;
bb.Write((short)0); // wLength (placeholder)
bb.Write((short)(value.Length + 1));// wValueLength
bb.Write((short)1); // wType
WriteUTF16Z(bb, name);
bb.Align(4);
WriteUTF16Z(bb, value);
bb.Align(4);
int savedPos = bb.Position;
bb.Position = pos;
bb.Write((short)(savedPos - pos));
bb.Position = savedPos;
}
private static Version ParseVersionRobust(string ver)
{
int index = 0;
ushort major = ParseVersionPart(ver, ref index);
ushort minor = ParseVersionPart(ver, ref index);
ushort build = ParseVersionPart(ver, ref index);
ushort revision = ParseVersionPart(ver, ref index);
return new Version(major, minor, build, revision);
}
private static ushort ParseVersionPart(string str, ref int pos)
{
ushort value = 0;
while (pos < str.Length)
{
char c = str[pos];
if (c == '.')
{
pos++;
break;
}
else if (c >= '0' && c <= '9')
{
value *= 10;
value += (ushort)(c - '0');
pos++;
}
else
{
break;
}
}
return value;
}
}
}