338948458933a4c12c84ecacfdca9c9f0f0a7ea3
[mono.git] / PEUtils.cs
1 /*\r
2  * Copyright (c) 2002 Sergey Chaban <serge@wildwestsoftware.com>\r
3  */\r
4 \r
5 using System;\r
6 using System.IO;\r
7 using System.Text;\r
8 using System.Reflection;\r
9 using System.Runtime.InteropServices;\r
10 \r
11 namespace Mono.PEToolkit {\r
12 \r
13         public sealed class PEUtils {\r
14 \r
15                 private PEUtils()\r
16                 {\r
17                 }\r
18 \r
19 \r
20                 unsafe internal static string GetString (sbyte* data, int start, int len, Encoding encoding)\r
21                 {\r
22                         byte[] data_array = new byte[len-start];\r
23                         \r
24                         for (int i=start; i<len; i++)\r
25                                 data_array[i-start] = (byte)*data++;\r
26                         \r
27                         return encoding.GetString (data_array);\r
28                 }\r
29 \r
30                 /// <summary>\r
31                 /// Reads structure from the input stream preserving its endianess.\r
32                 /// </summary>\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
37                 {\r
38                         byte* p = (byte*) pStruct;\r
39 \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
49                                 int rem = len & 7;\r
50 \r
51                                 for (int i = whole; --i >= 0;) {\r
52                                         long qw = reader.ReadInt64();\r
53                                         Marshal.WriteInt64((IntPtr) p, qw);\r
54                                         p += sizeof (long);\r
55                                 }\r
56                                 for (int i = rem; --i >= 0;) {\r
57                                         *p++ = (byte) reader.ReadByte();\r
58                                 }\r
59                         } else {\r
60                                 byte [] buff = reader.ReadBytes(len);\r
61                                 Marshal.Copy(buff, 0, (IntPtr) p, len);\r
62                         }\r
63                 }\r
64 \r
65                 /// <summary>\r
66                 /// Reads structure from the input stream\r
67                 /// changing its endianess if required\r
68                 /// (if running on big-endian hardware).\r
69                 /// </summary>\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
75                 {\r
76                         ReadStruct(reader, pStruct, len);\r
77                         if (!System.BitConverter.IsLittleEndian) {\r
78                                 ChangeStructEndianess(pStruct, type);\r
79                         }\r
80                 }\r
81 \r
82 \r
83                 unsafe private static int SwapByTypeCode(byte* p, TypeCode tcode)\r
84                 {\r
85                         int inc = 0;\r
86                         switch (tcode) {\r
87                                 case TypeCode.Int16 :\r
88                                         short* sp = (short*) p;\r
89                                         short sx = *sp;\r
90                                         sx = LEBitConverter.SwapInt16(sx);\r
91                                         *sp = sx;\r
92                                         inc = sizeof (short);\r
93                                         break;\r
94                                 case TypeCode.UInt16 :\r
95                                         ushort* usp = (ushort*) p;\r
96                                         ushort usx = *usp;\r
97                                         usx = LEBitConverter.SwapUInt16(usx);\r
98                                         *usp = usx;\r
99                                         inc = sizeof (ushort);\r
100                                         break;\r
101                                 case TypeCode.Int32 :\r
102                                         int* ip = (int*) p;\r
103                                         int ix = *ip;\r
104                                         ix = LEBitConverter.SwapInt32(ix);\r
105                                         *ip = ix;\r
106                                         inc = sizeof (int);\r
107                                         break;\r
108                                 case TypeCode.UInt32 :\r
109                                         uint* uip = (uint*) p;\r
110                                         uint uix = *uip;\r
111                                         uix = LEBitConverter.SwapUInt32(uix);\r
112                                         *uip = uix;\r
113                                         inc = sizeof (uint);\r
114                                         break;\r
115                                 case TypeCode.Int64 :\r
116                                         long* lp = (long*) p;\r
117                                         long lx = *lp;\r
118                                         lx = LEBitConverter.SwapInt64(lx);\r
119                                         *lp = lx;\r
120                                         inc = sizeof (long);\r
121                                         break;\r
122                                 case TypeCode.UInt64 :\r
123                                         ulong* ulp = (ulong*) p;\r
124                                         ulong ulx = *ulp;\r
125                                         ulx = LEBitConverter.SwapUInt64(ulx);\r
126                                         *ulp = ulx;\r
127                                         inc = sizeof (ulong);\r
128                                         break;\r
129                                 case TypeCode.Byte :\r
130                                 case TypeCode.SByte :\r
131                                         inc = sizeof (byte);\r
132                                         break;\r
133                                 default :\r
134                                         break;\r
135                         }\r
136                         return inc;\r
137                 }\r
138 \r
139                 unsafe internal static int ChangeStructEndianess(void* pStruct, Type type)\r
140                 {\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
144                         }\r
145 \r
146                         bool seq = type.IsLayoutSequential;\r
147                         byte* p = (byte*) pStruct;\r
148                         int offs = 0;\r
149                         int inc;\r
150                         FieldInfo [] fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);\r
151                         \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
159                                 } else {\r
160                                         inc = SwapByTypeCode(p + offs, tcode);\r
161                                 }\r
162                                 if (seq) offs += inc;\r
163                         }\r
164 \r
165                         return offs;\r
166                 }\r
167 \r
168         }\r
169 \r
170 }\r
171 \r