2 * Copyright (c) 2002 Sergey Chaban <serge@wildwestsoftware.com>
\r
8 using System.Reflection;
\r
9 using System.Runtime.InteropServices;
\r
11 namespace Mono.PEToolkit {
\r
13 public sealed class PEUtils {
\r
20 unsafe internal static string GetString (sbyte* data, int start, int len, Encoding encoding)
\r
22 byte[] data_array = new byte[len-start];
\r
24 for (int i=start; i<len; i++)
\r
25 data_array[i-start] = (byte)*data++;
\r
27 return encoding.GetString (data_array);
\r
31 /// Reads structure from the input stream preserving its endianess.
\r
33 /// <param name="reader"></param>
\r
34 /// <param name="pStruct"></param>
\r
35 /// <param name="len"></param>
\r
36 unsafe internal static void ReadStruct(BinaryReader reader, void* pStruct, int len)
\r
38 byte* p = (byte*) pStruct;
\r
40 if (System.BitConverter.IsLittleEndian) {
\r
41 // On a little-endian machine read data in 64-bit chunks,
\r
42 // this won't work on big-endian machine because
\r
43 // BinaryReader APIs are little-endian while
\r
44 // memory writes are platform-native.
\r
45 // This seems faster than ReadBytes/Copy method
\r
46 // in the "else" clause, especially if used often
\r
47 // (no extra memory allocation for byte[]?).
\r
48 int whole = len >> 3;
\r
51 for (int i = whole; --i >= 0;) {
\r
52 long qw = reader.ReadInt64();
\r
53 Marshal.WriteInt64((IntPtr) p, qw);
\r
56 for (int i = rem; --i >= 0;) {
\r
57 *p++ = (byte) reader.ReadByte();
\r
60 byte [] buff = reader.ReadBytes(len);
\r
61 Marshal.Copy(buff, 0, (IntPtr) p, len);
\r
66 /// Reads structure from the input stream
\r
67 /// changing its endianess if required
\r
68 /// (if running on big-endian hardware).
\r
70 /// <param name="reader"></param>
\r
71 /// <param name="pStruct"></param>
\r
72 /// <param name="len"></param>
\r
73 /// <param name="type"></param>
\r
74 unsafe internal static void ReadStruct(BinaryReader reader, void* pStruct, int len, Type type)
\r
76 ReadStruct(reader, pStruct, len);
\r
77 if (!System.BitConverter.IsLittleEndian) {
\r
78 ChangeStructEndianess(pStruct, type);
\r
83 unsafe private static int SwapByTypeCode(byte* p, TypeCode tcode)
\r
87 case TypeCode.Int16 :
\r
88 short* sp = (short*) p;
\r
90 sx = LEBitConverter.SwapInt16(sx);
\r
92 inc = sizeof (short);
\r
94 case TypeCode.UInt16 :
\r
95 ushort* usp = (ushort*) p;
\r
97 usx = LEBitConverter.SwapUInt16(usx);
\r
99 inc = sizeof (ushort);
\r
101 case TypeCode.Int32 :
\r
102 int* ip = (int*) p;
\r
104 ix = LEBitConverter.SwapInt32(ix);
\r
106 inc = sizeof (int);
\r
108 case TypeCode.UInt32 :
\r
109 uint* uip = (uint*) p;
\r
111 uix = LEBitConverter.SwapUInt32(uix);
\r
113 inc = sizeof (uint);
\r
115 case TypeCode.Int64 :
\r
116 long* lp = (long*) p;
\r
118 lx = LEBitConverter.SwapInt64(lx);
\r
120 inc = sizeof (long);
\r
122 case TypeCode.UInt64 :
\r
123 ulong* ulp = (ulong*) p;
\r
125 ulx = LEBitConverter.SwapUInt64(ulx);
\r
127 inc = sizeof (ulong);
\r
129 case TypeCode.Byte :
\r
130 case TypeCode.SByte :
\r
131 inc = sizeof (byte);
\r
139 unsafe internal static int ChangeStructEndianess(void* pStruct, Type type)
\r
141 if (type == null || !type.IsValueType) return 0;
\r
142 if (!type.IsLayoutSequential && !type.IsExplicitLayout) {
\r
143 throw new Exception("Internal error: struct must have explicit or sequential layout.");
\r
146 bool seq = type.IsLayoutSequential;
\r
147 byte* p = (byte*) pStruct;
\r
150 FieldInfo [] fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
\r
152 foreach (FieldInfo fi in fields) {
\r
153 if (!seq) offs = Marshal.OffsetOf(type, fi.Name).ToInt32 ();
\r
154 Type ft = fi.FieldType;
\r
155 TypeCode tcode = Type.GetTypeCode(ft);
\r
156 if (tcode == TypeCode.Object) {
\r
157 // not a primitive type, process recursively.
\r
158 inc = ChangeStructEndianess(p + offs, ft);
\r
160 inc = SwapByTypeCode(p + offs, tcode);
\r
162 if (seq) offs += inc;
\r