Update mcs/class/System.Core/System/TimeZoneInfo.cs
[mono.git] / mcs / class / IKVM.Reflection / MarshalSpec.cs
1 /*
2   Copyright (C) 2008-2012 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         public struct FieldMarshal
36         {
37                 private const UnmanagedType NATIVE_TYPE_MAX = (UnmanagedType)0x50;
38                 public UnmanagedType UnmanagedType;
39                 public UnmanagedType? ArraySubType;
40                 public short? SizeParamIndex;
41                 public int? SizeConst;
42                 public VarEnum? SafeArraySubType;
43                 public Type SafeArrayUserDefinedSubType;
44                 public int? IidParameterIndex;
45                 public string MarshalType;
46                 public string MarshalCookie;
47                 public Type MarshalTypeRef;
48
49                 internal static bool ReadFieldMarshal(Module module, int token, out FieldMarshal fm)
50                 {
51                         fm = new FieldMarshal();
52                         foreach (int i in module.FieldMarshal.Filter(token))
53                         {
54                                 ByteReader blob = module.GetBlob(module.FieldMarshal.records[i].NativeType);
55                                 fm.UnmanagedType = (UnmanagedType)blob.ReadCompressedInt();
56                                 if (fm.UnmanagedType == UnmanagedType.LPArray)
57                                 {
58                                         fm.ArraySubType = (UnmanagedType)blob.ReadCompressedInt();
59                                         if (fm.ArraySubType == NATIVE_TYPE_MAX)
60                                         {
61                                                 fm.ArraySubType = null;
62                                         }
63                                         if (blob.Length != 0)
64                                         {
65                                                 fm.SizeParamIndex = (short)blob.ReadCompressedInt();
66                                                 if (blob.Length != 0)
67                                                 {
68                                                         fm.SizeConst = blob.ReadCompressedInt();
69                                                         if (blob.Length != 0 && blob.ReadCompressedInt() == 0)
70                                                         {
71                                                                 fm.SizeParamIndex = null;
72                                                         }
73                                                 }
74                                         }
75                                 }
76                                 else if (fm.UnmanagedType == UnmanagedType.SafeArray)
77                                 {
78                                         if (blob.Length != 0)
79                                         {
80                                                 fm.SafeArraySubType = (VarEnum)blob.ReadCompressedInt();
81                                                 if (blob.Length != 0)
82                                                 {
83                                                         fm.SafeArrayUserDefinedSubType = ReadType(module, blob);
84                                                 }
85                                         }
86                                 }
87                                 else if (fm.UnmanagedType == UnmanagedType.ByValArray)
88                                 {
89                                         fm.SizeConst = blob.ReadCompressedInt();
90                                         if (blob.Length != 0)
91                                         {
92                                                 fm.ArraySubType = (UnmanagedType)blob.ReadCompressedInt();
93                                         }
94                                 }
95                                 else if (fm.UnmanagedType == UnmanagedType.ByValTStr)
96                                 {
97                                         fm.SizeConst = blob.ReadCompressedInt();
98                                 }
99                                 else if (fm.UnmanagedType == UnmanagedType.Interface
100                                         || fm.UnmanagedType == UnmanagedType.IDispatch
101                                         || fm.UnmanagedType == UnmanagedType.IUnknown)
102                                 {
103                                         if (blob.Length != 0)
104                                         {
105                                                 fm.IidParameterIndex = blob.ReadCompressedInt();
106                                         }
107                                 }
108                                 else if (fm.UnmanagedType == UnmanagedType.CustomMarshaler)
109                                 {
110                                         blob.ReadCompressedInt();
111                                         blob.ReadCompressedInt();
112                                         fm.MarshalType = ReadString(blob);
113                                         fm.MarshalCookie = ReadString(blob);
114
115                                         TypeNameParser parser = TypeNameParser.Parse(fm.MarshalType, false);
116                                         if (!parser.Error)
117                                         {
118                                                 fm.MarshalTypeRef = parser.GetType(module.universe, module.Assembly, false, fm.MarshalType, false, false);
119                                         }
120                                 }
121                                 return true;
122                         }
123                         return false;
124                 }
125
126                 internal static void SetMarshalAsAttribute(ModuleBuilder module, int token, CustomAttributeBuilder attribute)
127                 {
128                         attribute = attribute.DecodeBlob(module.Assembly);
129                         FieldMarshalTable.Record rec = new FieldMarshalTable.Record();
130                         rec.Parent = token;
131                         rec.NativeType = WriteMarshallingDescriptor(module, attribute);
132                         module.FieldMarshal.AddRecord(rec);
133                 }
134
135                 private static int WriteMarshallingDescriptor(ModuleBuilder module, CustomAttributeBuilder attribute)
136                 {
137                         UnmanagedType unmanagedType;
138                         object val = attribute.GetConstructorArgument(0);
139                         if (val is short)
140                         {
141                                 unmanagedType = (UnmanagedType)(short)val;
142                         }
143                         else if (val is int)
144                         {
145                                 unmanagedType = (UnmanagedType)(int)val;
146                         }
147                         else
148                         {
149                                 unmanagedType = (UnmanagedType)val;
150                         }
151
152                         ByteBuffer bb = new ByteBuffer(5);
153                         bb.WriteCompressedInt((int)unmanagedType);
154
155                         if (unmanagedType == UnmanagedType.LPArray)
156                         {
157                                 UnmanagedType arraySubType = attribute.GetFieldValue<UnmanagedType>("ArraySubType") ?? NATIVE_TYPE_MAX;
158                                 bb.WriteCompressedInt((int)arraySubType);
159                                 int? sizeParamIndex = attribute.GetFieldValue<short>("SizeParamIndex");
160                                 int? sizeConst = attribute.GetFieldValue<int>("SizeConst");
161                                 if (sizeParamIndex != null)
162                                 {
163                                         bb.WriteCompressedInt(sizeParamIndex.Value);
164                                         if (sizeConst != null)
165                                         {
166                                                 bb.WriteCompressedInt(sizeConst.Value);
167                                                 bb.WriteCompressedInt(1); // flag that says that SizeParamIndex was specified
168                                         }
169                                 }
170                                 else if (sizeConst != null)
171                                 {
172                                         bb.WriteCompressedInt(0); // SizeParamIndex
173                                         bb.WriteCompressedInt(sizeConst.Value);
174                                         bb.WriteCompressedInt(0); // flag that says that SizeParamIndex was not specified
175                                 }
176                         }
177                         else if (unmanagedType == UnmanagedType.SafeArray)
178                         {
179                                 VarEnum? safeArraySubType = attribute.GetFieldValue<VarEnum>("SafeArraySubType");
180                                 if (safeArraySubType != null)
181                                 {
182                                         bb.WriteCompressedInt((int)safeArraySubType);
183                                         Type safeArrayUserDefinedSubType = (Type)attribute.GetFieldValue("SafeArrayUserDefinedSubType");
184                                         if (safeArrayUserDefinedSubType != null)
185                                         {
186                                                 WriteType(module, bb, safeArrayUserDefinedSubType);
187                                         }
188                                 }
189                         }
190                         else if (unmanagedType == UnmanagedType.ByValArray)
191                         {
192                                 bb.WriteCompressedInt(attribute.GetFieldValue<int>("SizeConst") ?? 1);
193                                 UnmanagedType? arraySubType = attribute.GetFieldValue<UnmanagedType>("ArraySubType");
194                                 if (arraySubType != null)
195                                 {
196                                         bb.WriteCompressedInt((int)arraySubType);
197                                 }
198                         }
199                         else if (unmanagedType == UnmanagedType.ByValTStr)
200                         {
201                                 bb.WriteCompressedInt(attribute.GetFieldValue<int>("SizeConst").Value);
202                         }
203                         else if (unmanagedType == UnmanagedType.Interface
204                                 || unmanagedType == UnmanagedType.IDispatch
205                                 || unmanagedType == UnmanagedType.IUnknown)
206                         {
207                                 int? iidParameterIndex = attribute.GetFieldValue<int>("IidParameterIndex");
208                                 if (iidParameterIndex != null)
209                                 {
210                                         bb.WriteCompressedInt(iidParameterIndex.Value);
211                                 }
212                         }
213                         else if (unmanagedType == UnmanagedType.CustomMarshaler)
214                         {
215                                 bb.WriteCompressedInt(0);
216                                 bb.WriteCompressedInt(0);
217                                 string marshalType = (string)attribute.GetFieldValue("MarshalType");
218                                 if (marshalType != null)
219                                 {
220                                         WriteString(bb, marshalType);
221                                 }
222                                 else
223                                 {
224                                         WriteType(module, bb, (Type)attribute.GetFieldValue("MarshalTypeRef"));
225                                 }
226                                 WriteString(bb, (string)attribute.GetFieldValue("MarshalCookie") ?? "");
227                         }
228
229                         return module.Blobs.Add(bb);
230                 }
231
232                 private static Type ReadType(Module module, ByteReader br)
233                 {
234                         string str = ReadString(br);
235                         if (str == "")
236                         {
237                                 return null;
238                         }
239                         return module.Assembly.GetType(str) ?? module.universe.GetType(str, true);
240                 }
241
242                 private static void WriteType(Module module, ByteBuffer bb, Type type)
243                 {
244                         WriteString(bb, type.Assembly == module.Assembly ? type.FullName : type.AssemblyQualifiedName);
245                 }
246
247                 private static string ReadString(ByteReader br)
248                 {
249                         return Encoding.UTF8.GetString(br.ReadBytes(br.ReadCompressedInt()));
250                 }
251
252                 private static void WriteString(ByteBuffer bb, string str)
253                 {
254                         byte[] buf = Encoding.UTF8.GetBytes(str);
255                         bb.WriteCompressedInt(buf.Length);
256                         bb.Write(buf);
257                 }
258         }
259 }