System.Drawing: added email to icon and test file headers
[mono.git] / mcs / class / IKVM.Reflection / MarshalSpec.cs
1 /*
2   Copyright (C) 2008-2011 Jeroen Frijters
3
4   This software is provided 'as-is', without any express or implied
5   warranty.  In no event will the authors be held liable for any damages
6   arising from the use of this software.
7
8   Permission is granted to anyone to use this software for any purpose,
9   including commercial applications, and to alter it and redistribute it
10   freely, subject to the following restrictions:
11
12   1. The origin of this software must not be misrepresented; you must not
13      claim that you wrote the original software. If you use this software
14      in a product, an acknowledgment in the product documentation would be
15      appreciated but is not required.
16   2. Altered source versions must be plainly marked as such, and must not be
17      misrepresented as being the original software.
18   3. This notice may not be removed or altered from any source distribution.
19
20   Jeroen Frijters
21   jeroen@frijters.net
22   
23 */
24 using System;
25 using System.Collections.Generic;
26 using System.Runtime.InteropServices;
27 using System.Text;
28 using IKVM.Reflection.Emit;
29 using IKVM.Reflection.Reader;
30 using IKVM.Reflection.Writer;
31 using IKVM.Reflection.Metadata;
32
33 namespace IKVM.Reflection
34 {
35         static class MarshalSpec
36         {
37                 private const UnmanagedType NATIVE_TYPE_MAX = (UnmanagedType)0x50;
38
39                 internal static CustomAttributeData GetMarshalAsAttribute(Module module, int token)
40                 {
41                         foreach (int i in module.FieldMarshal.Filter(token))
42                         {
43                                 ByteReader blob = module.GetBlob(module.FieldMarshal.records[i].NativeType);
44                                 UnmanagedType unmanagedType = (UnmanagedType)blob.ReadCompressedInt();
45                                 UnmanagedType? arraySubType = null;
46                                 short? sizeParamIndex = null;
47                                 int? sizeConst = null;
48                                 VarEnum? safeArraySubType = null;
49                                 Type safeArrayUserDefinedSubType = null;
50                                 int? iidParameterIndex = null;
51                                 string marshalType = null;
52                                 string marshalCookie = null;
53                                 Type marshalTypeRef = null;
54                                 if (unmanagedType == UnmanagedType.LPArray)
55                                 {
56                                         arraySubType = (UnmanagedType)blob.ReadCompressedInt();
57                                         if (arraySubType == NATIVE_TYPE_MAX)
58                                         {
59                                                 arraySubType = null;
60                                         }
61                                         if (blob.Length != 0)
62                                         {
63                                                 sizeParamIndex = (short)blob.ReadCompressedInt();
64                                                 if (blob.Length != 0)
65                                                 {
66                                                         sizeConst = blob.ReadCompressedInt();
67                                                         if (blob.Length != 0 && blob.ReadCompressedInt() == 0)
68                                                         {
69                                                                 sizeParamIndex = null;
70                                                         }
71                                                 }
72                                         }
73                                 }
74                                 else if (unmanagedType == UnmanagedType.SafeArray)
75                                 {
76                                         if (blob.Length != 0)
77                                         {
78                                                 safeArraySubType = (VarEnum)blob.ReadCompressedInt();
79                                                 if (blob.Length != 0)
80                                                 {
81                                                         safeArrayUserDefinedSubType = ReadType(module, blob);
82                                                 }
83                                         }
84                                 }
85                                 else if (unmanagedType == UnmanagedType.ByValArray)
86                                 {
87                                         sizeConst = blob.ReadCompressedInt();
88                                         if (blob.Length != 0)
89                                         {
90                                                 arraySubType = (UnmanagedType)blob.ReadCompressedInt();
91                                         }
92                                 }
93                                 else if (unmanagedType == UnmanagedType.ByValTStr)
94                                 {
95                                         sizeConst = blob.ReadCompressedInt();
96                                 }
97                                 else if (unmanagedType == UnmanagedType.Interface
98                                         || unmanagedType == UnmanagedType.IDispatch
99                                         || unmanagedType == UnmanagedType.IUnknown)
100                                 {
101                                         if (blob.Length != 0)
102                                         {
103                                                 iidParameterIndex = blob.ReadCompressedInt();
104                                         }
105                                 }
106                                 else if (unmanagedType == UnmanagedType.CustomMarshaler)
107                                 {
108                                         blob.ReadCompressedInt();
109                                         blob.ReadCompressedInt();
110                                         marshalType = ReadString(blob);
111                                         marshalCookie = ReadString(blob);
112
113                                         TypeNameParser parser = TypeNameParser.Parse(marshalType, false);
114                                         if (!parser.Error)
115                                         {
116                                                 marshalTypeRef = parser.GetType(module.universe, module.Assembly, false, marshalType, false, false);
117                                         }
118                                 }
119
120                                 Type typeofMarshalAs = module.universe.System_Runtime_InteropServices_MarshalAsAttribute;
121                                 Type typeofUnmanagedType = module.universe.System_Runtime_InteropServices_UnmanagedType;
122                                 Type typeofVarEnum = module.universe.System_Runtime_InteropServices_VarEnum;
123                                 Type typeofType = module.universe.System_Type;
124                                 List<CustomAttributeNamedArgument> named = new List<CustomAttributeNamedArgument>();
125                                 if (arraySubType != null)
126                                 {
127                                         AddNamedArgument(named, typeofMarshalAs, "ArraySubType", typeofUnmanagedType, arraySubType.Value);
128                                 }
129                                 if (sizeParamIndex != null)
130                                 {
131                                         AddNamedArgument(named, typeofMarshalAs, "SizeParamIndex", module.universe.System_Int16, sizeParamIndex.Value);
132                                 }
133                                 if (sizeConst != null)
134                                 {
135                                         AddNamedArgument(named, typeofMarshalAs, "SizeConst", module.universe.System_Int32, sizeConst.Value);
136                                 }
137                                 if (safeArraySubType != null)
138                                 {
139                                         AddNamedArgument(named, typeofMarshalAs, "SafeArraySubType", typeofVarEnum, safeArraySubType.Value);
140                                 }
141                                 if (safeArrayUserDefinedSubType != null)
142                                 {
143                                         AddNamedArgument(named, typeofMarshalAs, "SafeArrayUserDefinedSubType", typeofType, safeArrayUserDefinedSubType);
144                                 }
145                                 if (iidParameterIndex != null)
146                                 {
147                                         AddNamedArgument(named, typeofMarshalAs, "IidParameterIndex", module.universe.System_Int32, iidParameterIndex.Value);
148                                 }
149                                 if (marshalType != null)
150                                 {
151                                         AddNamedArgument(named, typeofMarshalAs, "MarshalType", module.universe.System_String, marshalType);
152                                 }
153                                 if (marshalTypeRef != null)
154                                 {
155                                         AddNamedArgument(named, typeofMarshalAs, "MarshalTypeRef", module.universe.System_Type, marshalTypeRef);
156                                 }
157                                 if (marshalCookie != null)
158                                 {
159                                         AddNamedArgument(named, typeofMarshalAs, "MarshalCookie", module.universe.System_String, marshalCookie);
160                                 }
161                                 ConstructorInfo constructor = typeofMarshalAs.GetPseudoCustomAttributeConstructor(typeofUnmanagedType);
162                                 return new CustomAttributeData(module, constructor, new object[] { unmanagedType }, named);
163                         }
164                         throw new BadImageFormatException();
165                 }
166
167                 private static void AddNamedArgument(List<CustomAttributeNamedArgument> list, Type attributeType, string fieldName, Type valueType, object value)
168                 {
169                         // some fields are not available on the .NET Compact Framework version of MarshalAsAttribute
170                         FieldInfo field = attributeType.FindField(fieldName, FieldSignature.Create(valueType, new CustomModifiers()));
171                         if (field != null)
172                         {
173                                 list.Add(new CustomAttributeNamedArgument(field, new CustomAttributeTypedArgument(valueType, value)));
174                         }
175                 }
176
177                 internal static void SetMarshalAsAttribute(ModuleBuilder module, int token, CustomAttributeBuilder attribute)
178                 {
179                         attribute = attribute.DecodeBlob(module.Assembly);
180                         FieldMarshalTable.Record rec = new FieldMarshalTable.Record();
181                         rec.Parent = token;
182                         rec.NativeType = WriteMarshallingDescriptor(module, attribute);
183                         module.FieldMarshal.AddRecord(rec);
184                 }
185
186                 private static int WriteMarshallingDescriptor(ModuleBuilder module, CustomAttributeBuilder attribute)
187                 {
188                         UnmanagedType unmanagedType;
189                         object val = attribute.GetConstructorArgument(0);
190                         if (val is short)
191                         {
192                                 unmanagedType = (UnmanagedType)(short)val;
193                         }
194                         else if (val is int)
195                         {
196                                 unmanagedType = (UnmanagedType)(int)val;
197                         }
198                         else
199                         {
200                                 unmanagedType = (UnmanagedType)val;
201                         }
202
203                         ByteBuffer bb = new ByteBuffer(5);
204                         bb.WriteCompressedInt((int)unmanagedType);
205
206                         if (unmanagedType == UnmanagedType.LPArray)
207                         {
208                                 UnmanagedType arraySubType = attribute.GetFieldValue<UnmanagedType>("ArraySubType") ?? NATIVE_TYPE_MAX;
209                                 bb.WriteCompressedInt((int)arraySubType);
210                                 int? sizeParamIndex = attribute.GetFieldValue<short>("SizeParamIndex");
211                                 int? sizeConst = attribute.GetFieldValue<int>("SizeConst");
212                                 if (sizeParamIndex != null)
213                                 {
214                                         bb.WriteCompressedInt(sizeParamIndex.Value);
215                                         if (sizeConst != null)
216                                         {
217                                                 bb.WriteCompressedInt(sizeConst.Value);
218                                                 bb.WriteCompressedInt(1); // flag that says that SizeParamIndex was specified
219                                         }
220                                 }
221                                 else if (sizeConst != null)
222                                 {
223                                         bb.WriteCompressedInt(0); // SizeParamIndex
224                                         bb.WriteCompressedInt(sizeConst.Value);
225                                         bb.WriteCompressedInt(0); // flag that says that SizeParamIndex was not specified
226                                 }
227                         }
228                         else if (unmanagedType == UnmanagedType.SafeArray)
229                         {
230                                 VarEnum? safeArraySubType = attribute.GetFieldValue<VarEnum>("SafeArraySubType");
231                                 if (safeArraySubType != null)
232                                 {
233                                         bb.WriteCompressedInt((int)safeArraySubType);
234                                         Type safeArrayUserDefinedSubType = (Type)attribute.GetFieldValue("SafeArrayUserDefinedSubType");
235                                         if (safeArrayUserDefinedSubType != null)
236                                         {
237                                                 WriteType(module, bb, safeArrayUserDefinedSubType);
238                                         }
239                                 }
240                         }
241                         else if (unmanagedType == UnmanagedType.ByValArray)
242                         {
243                                 bb.WriteCompressedInt(attribute.GetFieldValue<int>("SizeConst") ?? 1);
244                                 UnmanagedType? arraySubType = attribute.GetFieldValue<UnmanagedType>("ArraySubType");
245                                 if (arraySubType != null)
246                                 {
247                                         bb.WriteCompressedInt((int)arraySubType);
248                                 }
249                         }
250                         else if (unmanagedType == UnmanagedType.ByValTStr)
251                         {
252                                 bb.WriteCompressedInt(attribute.GetFieldValue<int>("SizeConst").Value);
253                         }
254                         else if (unmanagedType == UnmanagedType.Interface
255                                 || unmanagedType == UnmanagedType.IDispatch
256                                 || unmanagedType == UnmanagedType.IUnknown)
257                         {
258                                 int? iidParameterIndex = attribute.GetFieldValue<int>("IidParameterIndex");
259                                 if (iidParameterIndex != null)
260                                 {
261                                         bb.WriteCompressedInt(iidParameterIndex.Value);
262                                 }
263                         }
264                         else if (unmanagedType == UnmanagedType.CustomMarshaler)
265                         {
266                                 bb.WriteCompressedInt(0);
267                                 bb.WriteCompressedInt(0);
268                                 string marshalType = (string)attribute.GetFieldValue("MarshalType");
269                                 if (marshalType != null)
270                                 {
271                                         WriteString(bb, marshalType);
272                                 }
273                                 else
274                                 {
275                                         WriteType(module, bb, (Type)attribute.GetFieldValue("MarshalTypeRef"));
276                                 }
277                                 WriteString(bb, (string)attribute.GetFieldValue("MarshalCookie") ?? "");
278                         }
279
280                         return module.Blobs.Add(bb);
281                 }
282
283                 private static Type ReadType(Module module, ByteReader br)
284                 {
285                         string str = ReadString(br);
286                         if (str == "")
287                         {
288                                 return null;
289                         }
290                         return module.Assembly.GetType(str) ?? module.universe.GetType(str, true);
291                 }
292
293                 private static void WriteType(Module module, ByteBuffer bb, Type type)
294                 {
295                         WriteString(bb, type.Assembly == module.Assembly ? type.FullName : type.AssemblyQualifiedName);
296                 }
297
298                 private static string ReadString(ByteReader br)
299                 {
300                         return Encoding.UTF8.GetString(br.ReadBytes(br.ReadCompressedInt()));
301                 }
302
303                 private static void WriteString(ByteBuffer bb, string str)
304                 {
305                         byte[] buf = Encoding.UTF8.GetBytes(str);
306                         bb.WriteCompressedInt(buf.Length);
307                         bb.Write(buf);
308                 }
309         }
310 }