[HttpWebRequest] EndGetResponse already does this.
[mono.git] / mcs / class / IKVM.Reflection / MarshalSpec.cs
1 /*
2   Copyright (C) 2008, 2010 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                         // TODO use binary search?
42                         for (int i = 0; i < module.FieldMarshal.records.Length; i++)
43                         {
44                                 if (module.FieldMarshal.records[i].Parent == token)
45                                 {
46                                         ByteReader blob = module.GetBlob(module.FieldMarshal.records[i].NativeType);
47                                         UnmanagedType unmanagedType = (UnmanagedType)blob.ReadCompressedInt();
48                                         UnmanagedType? arraySubType = null;
49                                         short? sizeParamIndex = null;
50                                         int? sizeConst = null;
51                                         VarEnum? safeArraySubType = null;
52                                         Type safeArrayUserDefinedSubType = null;
53                                         int? iidParameterIndex = null;
54                                         string marshalType = null;
55                                         string marshalCookie = null;
56                                         Type marshalTypeRef = null;
57                                         if (unmanagedType == UnmanagedType.LPArray)
58                                         {
59                                                 arraySubType = (UnmanagedType)blob.ReadCompressedInt();
60                                                 if (arraySubType == NATIVE_TYPE_MAX)
61                                                 {
62                                                         arraySubType = null;
63                                                 }
64                                                 if (blob.Length != 0)
65                                                 {
66                                                         sizeParamIndex = (short)blob.ReadCompressedInt();
67                                                         if (blob.Length != 0)
68                                                         {
69                                                                 sizeConst = blob.ReadCompressedInt();
70                                                                 if (blob.Length != 0 && blob.ReadCompressedInt() == 0)
71                                                                 {
72                                                                         sizeParamIndex = null;
73                                                                 }
74                                                         }
75                                                 }
76                                         }
77                                         else if (unmanagedType == UnmanagedType.SafeArray)
78                                         {
79                                                 if (blob.Length != 0)
80                                                 {
81                                                         safeArraySubType = (VarEnum)blob.ReadCompressedInt();
82                                                         if (blob.Length != 0)
83                                                         {
84                                                                 safeArrayUserDefinedSubType = ReadType(module, blob);
85                                                         }
86                                                 }
87                                         }
88                                         else if (unmanagedType == UnmanagedType.ByValArray)
89                                         {
90                                                 sizeConst = blob.ReadCompressedInt();
91                                                 if (blob.Length != 0)
92                                                 {
93                                                         arraySubType = (UnmanagedType)blob.ReadCompressedInt();
94                                                 }
95                                         }
96                                         else if (unmanagedType == UnmanagedType.ByValTStr)
97                                         {
98                                                 sizeConst = blob.ReadCompressedInt();
99                                         }
100                                         else if (unmanagedType == UnmanagedType.Interface
101                                                 || unmanagedType == UnmanagedType.IDispatch
102                                                 || unmanagedType == UnmanagedType.IUnknown)
103                                         {
104                                                 if (blob.Length != 0)
105                                                 {
106                                                         iidParameterIndex = blob.ReadCompressedInt();
107                                                 }
108                                         }
109                                         else if (unmanagedType == UnmanagedType.CustomMarshaler)
110                                         {
111                                                 blob.ReadCompressedInt();
112                                                 blob.ReadCompressedInt();
113                                                 marshalType = ReadString(blob);
114                                                 marshalCookie = ReadString(blob);
115                                                 marshalTypeRef = module.Assembly.GetType(marshalType) ?? module.universe.GetType(marshalType);
116                                         }
117
118                                         Type typeofMarshalAs = module.universe.System_Runtime_InteropServices_MarshalAsAttribute;
119                                         Type typeofUnmanagedType = module.universe.System_Runtime_InteropServices_UnmanagedType;
120                                         Type typeofVarEnum = module.universe.System_Runtime_InteropServices_VarEnum;
121                                         Type typeofType = module.universe.System_Type;
122                                         List<CustomAttributeNamedArgument> named = new List<CustomAttributeNamedArgument>();
123                                         if (arraySubType != null)
124                                         {
125                                                 named.Add(new CustomAttributeNamedArgument(typeofMarshalAs.GetField("ArraySubType"), new CustomAttributeTypedArgument(typeofUnmanagedType, arraySubType.Value)));
126                                         }
127                                         if (sizeParamIndex != null)
128                                         {
129                                                 named.Add(new CustomAttributeNamedArgument(typeofMarshalAs.GetField("SizeParamIndex"), new CustomAttributeTypedArgument(module.universe.System_Int16, sizeParamIndex.Value)));
130                                         }
131                                         if (sizeConst != null)
132                                         {
133                                                 named.Add(new CustomAttributeNamedArgument(typeofMarshalAs.GetField("SizeConst"), new CustomAttributeTypedArgument(module.universe.System_Int32, sizeConst.Value)));
134                                         }
135                                         if (safeArraySubType != null)
136                                         {
137                                                 named.Add(new CustomAttributeNamedArgument(typeofMarshalAs.GetField("SafeArraySubType"), new CustomAttributeTypedArgument(typeofVarEnum, safeArraySubType.Value)));
138                                         }
139                                         if (safeArrayUserDefinedSubType != null)
140                                         {
141                                                 named.Add(new CustomAttributeNamedArgument(typeofMarshalAs.GetField("SafeArrayUserDefinedSubType"), new CustomAttributeTypedArgument(typeofType, safeArrayUserDefinedSubType)));
142                                         }
143                                         if (iidParameterIndex != null)
144                                         {
145                                                 named.Add(new CustomAttributeNamedArgument(typeofMarshalAs.GetField("IidParameterIndex"), new CustomAttributeTypedArgument(module.universe.System_Int32, iidParameterIndex.Value)));
146                                         }
147                                         if (marshalType != null)
148                                         {
149                                                 named.Add(new CustomAttributeNamedArgument(typeofMarshalAs.GetField("MarshalType"), new CustomAttributeTypedArgument(module.universe.System_String, marshalType)));
150                                         }
151                                         if (marshalTypeRef != null)
152                                         {
153                                                 named.Add(new CustomAttributeNamedArgument(typeofMarshalAs.GetField("MarshalTypeRef"), new CustomAttributeTypedArgument(module.universe.System_Type, marshalTypeRef)));
154                                         }
155                                         if (marshalCookie != null)
156                                         {
157                                                 named.Add(new CustomAttributeNamedArgument(typeofMarshalAs.GetField("MarshalCookie"), new CustomAttributeTypedArgument(module.universe.System_String, marshalCookie)));
158                                         }
159                                         ConstructorInfo constructor = typeofMarshalAs.GetConstructor(new Type[] { typeofUnmanagedType });
160                                         return new CustomAttributeData(constructor, new object[] { unmanagedType }, named);
161                                 }
162                         }
163                         throw new BadImageFormatException();
164                 }
165
166                 internal static void SetMarshalAsAttribute(ModuleBuilder module, int token, CustomAttributeBuilder attribute)
167                 {
168                         attribute = attribute.DecodeBlob(module.Assembly);
169                         FieldMarshalTable.Record rec = new FieldMarshalTable.Record();
170                         rec.Parent = token;
171                         rec.NativeType = WriteMarshallingDescriptor(module, attribute);
172                         module.FieldMarshal.AddRecord(rec);
173                 }
174
175                 private static int WriteMarshallingDescriptor(ModuleBuilder module, CustomAttributeBuilder attribute)
176                 {
177                         UnmanagedType unmanagedType;
178                         object val = attribute.GetConstructorArgument(0);
179                         if (val is short)
180                         {
181                                 unmanagedType = (UnmanagedType)(short)val;
182                         }
183                         else if (val is int)
184                         {
185                                 unmanagedType = (UnmanagedType)(int)val;
186                         }
187                         else
188                         {
189                                 unmanagedType = (UnmanagedType)val;
190                         }
191
192                         ByteBuffer bb = new ByteBuffer(5);
193                         bb.WriteCompressedInt((int)unmanagedType);
194
195                         if (unmanagedType == UnmanagedType.LPArray)
196                         {
197                                 UnmanagedType arraySubType = attribute.GetFieldValue<UnmanagedType>("ArraySubType") ?? NATIVE_TYPE_MAX;
198                                 bb.WriteCompressedInt((int)arraySubType);
199                                 int? sizeParamIndex = attribute.GetFieldValue<short>("SizeParamIndex");
200                                 int? sizeConst = attribute.GetFieldValue<int>("SizeConst");
201                                 if (sizeParamIndex != null)
202                                 {
203                                         bb.WriteCompressedInt(sizeParamIndex.Value);
204                                         if (sizeConst != null)
205                                         {
206                                                 bb.WriteCompressedInt(sizeConst.Value);
207                                                 bb.WriteCompressedInt(1); // flag that says that SizeParamIndex was specified
208                                         }
209                                 }
210                                 else if (sizeConst != null)
211                                 {
212                                         bb.WriteCompressedInt(0); // SizeParamIndex
213                                         bb.WriteCompressedInt(sizeConst.Value);
214                                         bb.WriteCompressedInt(0); // flag that says that SizeParamIndex was not specified
215                                 }
216                         }
217                         else if (unmanagedType == UnmanagedType.SafeArray)
218                         {
219                                 VarEnum? safeArraySubType = attribute.GetFieldValue<VarEnum>("SafeArraySubType");
220                                 if (safeArraySubType != null)
221                                 {
222                                         bb.WriteCompressedInt((int)safeArraySubType);
223                                         Type safeArrayUserDefinedSubType = (Type)attribute.GetFieldValue("SafeArrayUserDefinedSubType");
224                                         if (safeArrayUserDefinedSubType != null)
225                                         {
226                                                 WriteType(module, bb, safeArrayUserDefinedSubType);
227                                         }
228                                 }
229                         }
230                         else if (unmanagedType == UnmanagedType.ByValArray)
231                         {
232                                 bb.WriteCompressedInt(attribute.GetFieldValue<int>("SizeConst") ?? 1);
233                                 UnmanagedType? arraySubType = attribute.GetFieldValue<UnmanagedType>("ArraySubType");
234                                 if (arraySubType != null)
235                                 {
236                                         bb.WriteCompressedInt((int)arraySubType);
237                                 }
238                         }
239                         else if (unmanagedType == UnmanagedType.ByValTStr)
240                         {
241                                 bb.WriteCompressedInt(attribute.GetFieldValue<int>("SizeConst").Value);
242                         }
243                         else if (unmanagedType == UnmanagedType.Interface
244                                 || unmanagedType == UnmanagedType.IDispatch
245                                 || unmanagedType == UnmanagedType.IUnknown)
246                         {
247                                 int? iidParameterIndex = attribute.GetFieldValue<int>("IidParameterIndex");
248                                 if (iidParameterIndex != null)
249                                 {
250                                         bb.WriteCompressedInt(iidParameterIndex.Value);
251                                 }
252                         }
253                         else if (unmanagedType == UnmanagedType.CustomMarshaler)
254                         {
255                                 bb.WriteCompressedInt(0);
256                                 bb.WriteCompressedInt(0);
257                                 string marshalType = (string)attribute.GetFieldValue("MarshalType");
258                                 if (marshalType != null)
259                                 {
260                                         WriteString(bb, marshalType);
261                                 }
262                                 else
263                                 {
264                                         WriteType(module, bb, (Type)attribute.GetFieldValue("MarshalTypeRef"));
265                                 }
266                                 WriteString(bb, (string)attribute.GetFieldValue("MarshalCookie") ?? "");
267                         }
268
269                         return module.Blobs.Add(bb);
270                 }
271
272                 private static Type ReadType(Module module, ByteReader br)
273                 {
274                         string str = ReadString(br);
275                         if (str == "")
276                         {
277                                 return null;
278                         }
279                         return module.Assembly.GetType(str) ?? module.universe.GetType(str, true);
280                 }
281
282                 private static void WriteType(Module module, ByteBuffer bb, Type type)
283                 {
284                         WriteString(bb, type.Assembly == module.Assembly ? type.FullName : type.AssemblyQualifiedName);
285                 }
286
287                 private static string ReadString(ByteReader br)
288                 {
289                         return Encoding.UTF8.GetString(br.ReadBytes(br.ReadCompressedInt()));
290                 }
291
292                 private static void WriteString(ByteBuffer bb, string str)
293                 {
294                         byte[] buf = Encoding.UTF8.GetBytes(str);
295                         bb.WriteCompressedInt(buf.Length);
296                         bb.Write(buf);
297                 }
298         }
299 }