New test.
[mono.git] / mcs / class / Mono.PEToolkit / PEUtils.cs
1 \r
2 //\r
3 // Permission is hereby granted, free of charge, to any person obtaining\r
4 // a copy of this software and associated documentation files (the\r
5 // "Software"), to deal in the Software without restriction, including\r
6 // without limitation the rights to use, copy, modify, merge, publish,\r
7 // distribute, sublicense, and/or sell copies of the Software, and to\r
8 // permit persons to whom the Software is furnished to do so, subject to\r
9 // the following conditions:\r
10 // \r
11 // The above copyright notice and this permission notice shall be\r
12 // included in all copies or substantial portions of the Software.\r
13 // \r
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
18 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
19 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
20 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21 //\r
22 /*\r
23  * Copyright (c) 2002 Sergey Chaban <serge@wildwestsoftware.com>\r
24  */\r
25 \r
26 using System;\r
27 using System.IO;\r
28 using System.Text;\r
29 using System.Reflection;\r
30 using System.Runtime.InteropServices;\r
31 \r
32 namespace Mono.PEToolkit {\r
33 \r
34         public sealed class PEUtils {\r
35 \r
36                 private PEUtils()\r
37                 {\r
38                 }\r
39 \r
40 \r
41                 unsafe internal static string GetString (sbyte* data, int start, int len, Encoding encoding)\r
42                 {\r
43                         byte[] data_array = new byte[len-start];\r
44                         \r
45                         for (int i=start; i<len; i++)\r
46                                 data_array[i-start] = (byte)*data++;\r
47                         \r
48                         return encoding.GetString (data_array);\r
49                 }\r
50 \r
51                 /// <summary>\r
52                 /// Reads structure from the input stream preserving its endianess.\r
53                 /// </summary>\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
58                 {\r
59                         byte* p = (byte*) pStruct;\r
60 \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
70                                 int rem = len & 7;\r
71 \r
72                                 for (int i = whole; --i >= 0;) {\r
73                                         long qw = reader.ReadInt64();\r
74                                         Marshal.WriteInt64((IntPtr) p, qw);\r
75                                         p += sizeof (long);\r
76                                 }\r
77                                 for (int i = rem; --i >= 0;) {\r
78                                         *p++ = (byte) reader.ReadByte();\r
79                                 }\r
80                         } else {\r
81                                 byte [] buff = reader.ReadBytes(len);\r
82                                 Marshal.Copy(buff, 0, (IntPtr) p, len);\r
83                         }\r
84                 }\r
85 \r
86                 /// <summary>\r
87                 /// Reads structure from the input stream\r
88                 /// changing its endianess if required\r
89                 /// (if running on big-endian hardware).\r
90                 /// </summary>\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
96                 {\r
97                         ReadStruct(reader, pStruct, len);\r
98                         if (!System.BitConverter.IsLittleEndian) {\r
99                                 ChangeStructEndianess(pStruct, type);\r
100                         }\r
101                 }\r
102 \r
103 \r
104                 unsafe private static int SwapByTypeCode(byte* p, TypeCode tcode)\r
105                 {\r
106                         int inc = 0;\r
107                         switch (tcode) {\r
108                                 case TypeCode.Int16 :\r
109                                         short* sp = (short*) p;\r
110                                         short sx = *sp;\r
111                                         sx = LEBitConverter.SwapInt16(sx);\r
112                                         *sp = sx;\r
113                                         inc = sizeof (short);\r
114                                         break;\r
115                                 case TypeCode.UInt16 :\r
116                                         ushort* usp = (ushort*) p;\r
117                                         ushort usx = *usp;\r
118                                         usx = LEBitConverter.SwapUInt16(usx);\r
119                                         *usp = usx;\r
120                                         inc = sizeof (ushort);\r
121                                         break;\r
122                                 case TypeCode.Int32 :\r
123                                         int* ip = (int*) p;\r
124                                         int ix = *ip;\r
125                                         ix = LEBitConverter.SwapInt32(ix);\r
126                                         *ip = ix;\r
127                                         inc = sizeof (int);\r
128                                         break;\r
129                                 case TypeCode.UInt32 :\r
130                                         uint* uip = (uint*) p;\r
131                                         uint uix = *uip;\r
132                                         uix = LEBitConverter.SwapUInt32(uix);\r
133                                         *uip = uix;\r
134                                         inc = sizeof (uint);\r
135                                         break;\r
136                                 case TypeCode.Int64 :\r
137                                         long* lp = (long*) p;\r
138                                         long lx = *lp;\r
139                                         lx = LEBitConverter.SwapInt64(lx);\r
140                                         *lp = lx;\r
141                                         inc = sizeof (long);\r
142                                         break;\r
143                                 case TypeCode.UInt64 :\r
144                                         ulong* ulp = (ulong*) p;\r
145                                         ulong ulx = *ulp;\r
146                                         ulx = LEBitConverter.SwapUInt64(ulx);\r
147                                         *ulp = ulx;\r
148                                         inc = sizeof (ulong);\r
149                                         break;\r
150                                 case TypeCode.Byte :\r
151                                 case TypeCode.SByte :\r
152                                         inc = sizeof (byte);\r
153                                         break;\r
154                                 default :\r
155                                         break;\r
156                         }\r
157                         return inc;\r
158                 }\r
159 \r
160                 unsafe internal static int ChangeStructEndianess(void* pStruct, Type type)\r
161                 {\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
165                         }\r
166 \r
167                         bool seq = type.IsLayoutSequential;\r
168                         byte* p = (byte*) pStruct;\r
169                         int offs = 0;\r
170                         int inc;\r
171                         FieldInfo [] fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);\r
172                         \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
180                                 } else {\r
181                                         inc = SwapByTypeCode(p + offs, tcode);\r
182                                 }\r
183                                 if (seq) offs += inc;\r
184                         }\r
185 \r
186                         return offs;\r
187                 }\r
188 \r
189         }\r
190 \r
191 }\r
192 \r