3 // Permission is hereby granted, free of charge, to any person obtaining
4 // a copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to
8 // permit persons to whom the Software is furnished to do so, subject to
9 // the following conditions:
11 // The above copyright notice and this permission notice shall be
12 // included in all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 * Copyright (c) 2002 Sergey Chaban <serge@wildwestsoftware.com>
\r
29 using System.Reflection;
\r
30 using System.Runtime.InteropServices;
\r
32 namespace Mono.PEToolkit {
\r
34 public sealed class PEUtils {
\r
41 unsafe internal static string GetString (sbyte* data, int start, int len, Encoding encoding)
\r
43 byte[] data_array = new byte[len-start];
\r
45 for (int i=start; i<len; i++)
\r
46 data_array[i-start] = (byte)*data++;
\r
48 return encoding.GetString (data_array);
\r
52 /// Reads structure from the input stream preserving its endianess.
\r
54 /// <param name="reader"></param>
\r
55 /// <param name="pStruct"></param>
\r
56 /// <param name="len"></param>
\r
57 unsafe internal static void ReadStruct(BinaryReader reader, void* pStruct, int len)
\r
59 byte* p = (byte*) pStruct;
\r
61 if (System.BitConverter.IsLittleEndian) {
\r
62 // On a little-endian machine read data in 64-bit chunks,
\r
63 // this won't work on big-endian machine because
\r
64 // BinaryReader APIs are little-endian while
\r
65 // memory writes are platform-native.
\r
66 // This seems faster than ReadBytes/Copy method
\r
67 // in the "else" clause, especially if used often
\r
68 // (no extra memory allocation for byte[]?).
\r
69 int whole = len >> 3;
\r
72 for (int i = whole; --i >= 0;) {
\r
73 long qw = reader.ReadInt64();
\r
74 Marshal.WriteInt64((IntPtr) p, qw);
\r
77 for (int i = rem; --i >= 0;) {
\r
78 *p++ = (byte) reader.ReadByte();
\r
81 byte [] buff = reader.ReadBytes(len);
\r
82 Marshal.Copy(buff, 0, (IntPtr) p, len);
\r
87 /// Reads structure from the input stream
\r
88 /// changing its endianess if required
\r
89 /// (if running on big-endian hardware).
\r
91 /// <param name="reader"></param>
\r
92 /// <param name="pStruct"></param>
\r
93 /// <param name="len"></param>
\r
94 /// <param name="type"></param>
\r
95 unsafe internal static void ReadStruct(BinaryReader reader, void* pStruct, int len, Type type)
\r
97 ReadStruct(reader, pStruct, len);
\r
98 if (!System.BitConverter.IsLittleEndian) {
\r
99 ChangeStructEndianess(pStruct, type);
\r
104 unsafe private static int SwapByTypeCode(byte* p, TypeCode tcode)
\r
108 case TypeCode.Int16 :
\r
109 short* sp = (short*) p;
\r
111 sx = LEBitConverter.SwapInt16(sx);
\r
113 inc = sizeof (short);
\r
115 case TypeCode.UInt16 :
\r
116 ushort* usp = (ushort*) p;
\r
118 usx = LEBitConverter.SwapUInt16(usx);
\r
120 inc = sizeof (ushort);
\r
122 case TypeCode.Int32 :
\r
123 int* ip = (int*) p;
\r
125 ix = LEBitConverter.SwapInt32(ix);
\r
127 inc = sizeof (int);
\r
129 case TypeCode.UInt32 :
\r
130 uint* uip = (uint*) p;
\r
132 uix = LEBitConverter.SwapUInt32(uix);
\r
134 inc = sizeof (uint);
\r
136 case TypeCode.Int64 :
\r
137 long* lp = (long*) p;
\r
139 lx = LEBitConverter.SwapInt64(lx);
\r
141 inc = sizeof (long);
\r
143 case TypeCode.UInt64 :
\r
144 ulong* ulp = (ulong*) p;
\r
146 ulx = LEBitConverter.SwapUInt64(ulx);
\r
148 inc = sizeof (ulong);
\r
150 case TypeCode.Byte :
\r
151 case TypeCode.SByte :
\r
152 inc = sizeof (byte);
\r
160 unsafe internal static int ChangeStructEndianess(void* pStruct, Type type)
\r
162 if (type == null || !type.IsValueType) return 0;
\r
163 if (!type.IsLayoutSequential && !type.IsExplicitLayout) {
\r
164 throw new Exception("Internal error: struct must have explicit or sequential layout.");
\r
167 bool seq = type.IsLayoutSequential;
\r
168 byte* p = (byte*) pStruct;
\r
171 FieldInfo [] fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
\r
173 foreach (FieldInfo fi in fields) {
\r
174 if (!seq) offs = Marshal.OffsetOf(type, fi.Name).ToInt32 ();
\r
175 Type ft = fi.FieldType;
\r
176 TypeCode tcode = Type.GetTypeCode(ft);
\r
177 if (tcode == TypeCode.Object) {
\r
178 // not a primitive type, process recursively.
\r
179 inc = ChangeStructEndianess(p + offs, ft);
\r
181 inc = SwapByTypeCode(p + offs, tcode);
\r
183 if (seq) offs += inc;
\r