2007-03-28 Chris Toshok <toshok@ximian.com>
[mono-project.git] / mcs / class / Mono.PEToolkit / PEUtils.cs
bloba3673e0c72b50ed1bda6f8af4cce61d2a3173598
2 //
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:
10 //
11 // The above copyright notice and this permission notice shall be
12 // included in all copies or substantial portions of the Software.
13 //
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>
26 using System;
27 using System.IO;
28 using System.Text;
29 using System.Reflection;
30 using System.Runtime.InteropServices;
32 namespace Mono.PEToolkit {
34 public sealed class PEUtils {
36 private PEUtils()
41 unsafe internal static string GetString (sbyte* data, int start, int len, Encoding encoding)
43 byte[] data_array = new byte[len-start];
45 for (int i=start; i<len; i++)
46 data_array[i-start] = (byte)*data++;
48 return encoding.GetString (data_array);
51 /// <summary>
52 /// Reads structure from the input stream preserving its endianess.
53 /// </summary>
54 /// <param name="reader"></param>
55 /// <param name="pStruct"></param>
56 /// <param name="len"></param>
57 unsafe internal static void ReadStruct(BinaryReader reader, void* pStruct, int len)
59 byte* p = (byte*) pStruct;
61 if (System.BitConverter.IsLittleEndian) {
62 // On a little-endian machine read data in 64-bit chunks,
63 // this won't work on big-endian machine because
64 // BinaryReader APIs are little-endian while
65 // memory writes are platform-native.
66 // This seems faster than ReadBytes/Copy method
67 // in the "else" clause, especially if used often
68 // (no extra memory allocation for byte[]?).
69 int whole = len >> 3;
70 int rem = len & 7;
72 for (int i = whole; --i >= 0;) {
73 long qw = reader.ReadInt64();
74 Marshal.WriteInt64((IntPtr) p, qw);
75 p += sizeof (long);
77 for (int i = rem; --i >= 0;) {
78 *p++ = (byte) reader.ReadByte();
80 } else {
81 byte [] buff = reader.ReadBytes(len);
82 Marshal.Copy(buff, 0, (IntPtr) p, len);
86 /// <summary>
87 /// Reads structure from the input stream
88 /// changing its endianess if required
89 /// (if running on big-endian hardware).
90 /// </summary>
91 /// <param name="reader"></param>
92 /// <param name="pStruct"></param>
93 /// <param name="len"></param>
94 /// <param name="type"></param>
95 unsafe internal static void ReadStruct(BinaryReader reader, void* pStruct, int len, Type type)
97 ReadStruct(reader, pStruct, len);
98 if (!System.BitConverter.IsLittleEndian) {
99 ChangeStructEndianess(pStruct, type);
104 unsafe private static int SwapByTypeCode(byte* p, TypeCode tcode)
106 int inc = 0;
107 switch (tcode) {
108 case TypeCode.Int16 :
109 short* sp = (short*) p;
110 short sx = *sp;
111 sx = LEBitConverter.SwapInt16(sx);
112 *sp = sx;
113 inc = sizeof (short);
114 break;
115 case TypeCode.UInt16 :
116 ushort* usp = (ushort*) p;
117 ushort usx = *usp;
118 usx = LEBitConverter.SwapUInt16(usx);
119 *usp = usx;
120 inc = sizeof (ushort);
121 break;
122 case TypeCode.Int32 :
123 int* ip = (int*) p;
124 int ix = *ip;
125 ix = LEBitConverter.SwapInt32(ix);
126 *ip = ix;
127 inc = sizeof (int);
128 break;
129 case TypeCode.UInt32 :
130 uint* uip = (uint*) p;
131 uint uix = *uip;
132 uix = LEBitConverter.SwapUInt32(uix);
133 *uip = uix;
134 inc = sizeof (uint);
135 break;
136 case TypeCode.Int64 :
137 long* lp = (long*) p;
138 long lx = *lp;
139 lx = LEBitConverter.SwapInt64(lx);
140 *lp = lx;
141 inc = sizeof (long);
142 break;
143 case TypeCode.UInt64 :
144 ulong* ulp = (ulong*) p;
145 ulong ulx = *ulp;
146 ulx = LEBitConverter.SwapUInt64(ulx);
147 *ulp = ulx;
148 inc = sizeof (ulong);
149 break;
150 case TypeCode.Byte :
151 case TypeCode.SByte :
152 inc = sizeof (byte);
153 break;
154 default :
155 break;
157 return inc;
160 unsafe internal static int ChangeStructEndianess(void* pStruct, Type type)
162 if (type == null || !type.IsValueType) return 0;
163 if (!type.IsLayoutSequential && !type.IsExplicitLayout) {
164 throw new Exception("Internal error: struct must have explicit or sequential layout.");
167 bool seq = type.IsLayoutSequential;
168 byte* p = (byte*) pStruct;
169 int offs = 0;
170 int inc;
171 FieldInfo [] fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
173 foreach (FieldInfo fi in fields) {
174 if (!seq) offs = Marshal.OffsetOf(type, fi.Name).ToInt32 ();
175 Type ft = fi.FieldType;
176 TypeCode tcode = Type.GetTypeCode(ft);
177 if (tcode == TypeCode.Object) {
178 // not a primitive type, process recursively.
179 inc = ChangeStructEndianess(p + offs, ft);
180 } else {
181 inc = SwapByTypeCode(p + offs, tcode);
183 if (seq) offs += inc;
186 return offs;