actually fix the varargs handling
[mono.git] / mcs / class / Mono.Cecil / Mono.Cecil.Signatures / SignatureWriter.cs
1 //
2 // SignatureWriter.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@gmail.com)
6 //
7 // (C) 2005 - 2007 Jb Evain
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 namespace Mono.Cecil.Signatures {
30
31         using System;
32         using System.Text;
33
34         using Mono.Cecil;
35         using Mono.Cecil.Binary;
36         using Mono.Cecil.Metadata;
37
38         internal sealed class SignatureWriter : BaseSignatureVisitor {
39
40                 MetadataWriter m_mdWriter;
41                 MemoryBinaryWriter m_sigWriter;
42
43                 public SignatureWriter (MetadataWriter mdWriter)
44                 {
45                         m_mdWriter = mdWriter;
46                         m_sigWriter = new MemoryBinaryWriter ();
47                 }
48
49                 uint GetPointer ()
50                 {
51                         return m_mdWriter.AddBlob (m_sigWriter.ToArray ());
52                 }
53
54                 public uint AddMethodDefSig (MethodDefSig methSig)
55                 {
56                         return AddSignature (methSig);
57                 }
58
59                 public uint AddMethodRefSig (MethodRefSig methSig)
60                 {
61                         return AddSignature (methSig);
62                 }
63
64                 public uint AddPropertySig (PropertySig ps)
65                 {
66                         return AddSignature (ps);
67                 }
68
69                 public uint AddFieldSig (FieldSig fSig)
70                 {
71                         return AddSignature (fSig);
72                 }
73
74                 public uint AddLocalVarSig (LocalVarSig lvs)
75                 {
76                         return AddSignature (lvs);
77                 }
78
79                 uint AddSignature (Signature s)
80                 {
81                         m_sigWriter.Empty ();
82                         s.Accept (this);
83                         return GetPointer ();
84                 }
85
86                 public uint AddTypeSpec (TypeSpec ts)
87                 {
88                         m_sigWriter.Empty ();
89                         Write (ts);
90                         return GetPointer ();
91                 }
92
93                 public uint AddMethodSpec (MethodSpec ms)
94                 {
95                         m_sigWriter.Empty ();
96                         Write (ms);
97                         return GetPointer ();
98                 }
99
100                 public uint AddMarshalSig (MarshalSig ms)
101                 {
102                         m_sigWriter.Empty ();
103                         Write (ms);
104                         return GetPointer ();
105                 }
106
107                 public uint AddCustomAttribute (CustomAttrib ca, MethodReference ctor)
108                 {
109                         CompressCustomAttribute (ca, ctor, m_sigWriter);
110                         return GetPointer ();
111                 }
112
113                 public byte [] CompressCustomAttribute (CustomAttrib ca, MethodReference ctor)
114                 {
115                         MemoryBinaryWriter writer = new MemoryBinaryWriter ();
116                         CompressCustomAttribute (ca, ctor, writer);
117                         return writer.ToArray ();
118                 }
119
120                 public byte [] CompressFieldSig (FieldSig field)
121                 {
122                         m_sigWriter.Empty ();
123                         VisitFieldSig (field);
124                         return m_sigWriter.ToArray ();
125                 }
126
127                 void CompressCustomAttribute (CustomAttrib ca, MethodReference ctor, MemoryBinaryWriter writer)
128                 {
129                         m_sigWriter.Empty ();
130                         Write (ca, ctor, writer);
131                 }
132
133                 public override void VisitMethodDefSig (MethodDefSig methodDef)
134                 {
135                         m_sigWriter.Write (methodDef.CallingConvention);
136                         if (methodDef.GenericParameterCount > 0)
137                                 Write (methodDef.GenericParameterCount);
138                         Write (methodDef.ParamCount);
139                         Write (methodDef.RetType);
140                         Write (methodDef.Parameters, methodDef.Sentinel);
141                 }
142
143                 public override void VisitMethodRefSig (MethodRefSig methodRef)
144                 {
145                         m_sigWriter.Write (methodRef.CallingConvention);
146                         Write (methodRef.ParamCount);
147                         Write (methodRef.RetType);
148                         Write (methodRef.Parameters, methodRef.Sentinel);
149                 }
150
151                 public override void VisitFieldSig (FieldSig field)
152                 {
153                         m_sigWriter.Write (field.CallingConvention);
154                         Write (field.CustomMods);
155                         Write (field.Type);
156                 }
157
158                 public override void VisitPropertySig (PropertySig property)
159                 {
160                         m_sigWriter.Write (property.CallingConvention);
161                         Write (property.ParamCount);
162                         Write (property.CustomMods);
163                         Write (property.Type);
164                         Write (property.Parameters);
165                 }
166
167                 public override void VisitLocalVarSig (LocalVarSig localvar)
168                 {
169                         m_sigWriter.Write (localvar.CallingConvention);
170                         Write (localvar.Count);
171                         Write (localvar.LocalVariables);
172                 }
173
174                 void Write (LocalVarSig.LocalVariable [] vars)
175                 {
176                         foreach (LocalVarSig.LocalVariable var in vars)
177                                 Write (var);
178                 }
179
180                 void Write (LocalVarSig.LocalVariable var)
181                 {
182                         Write (var.CustomMods);
183                         if ((var.Constraint & Constraint.Pinned) != 0)
184                                 Write (ElementType.Pinned);
185                         if (var.ByRef)
186                                 Write (ElementType.ByRef);
187                         Write (var.Type);
188                 }
189
190                 void Write (RetType retType)
191                 {
192                         Write (retType.CustomMods);
193                         if (retType.Void)
194                                 Write (ElementType.Void);
195                         else if (retType.TypedByRef)
196                                 Write (ElementType.TypedByRef);
197                         else if (retType.ByRef) {
198                                 Write (ElementType.ByRef);
199                                 Write (retType.Type);
200                         } else
201                                 Write (retType.Type);
202                 }
203
204                 void Write (Param [] parameters, int sentinel)
205                 {
206                         for (int i = 0; i < parameters.Length; i++) {
207                                 if (i == sentinel)
208                                         Write (ElementType.Sentinel);
209
210                                 Write (parameters [i]);
211                         }
212                 }
213
214                 void Write (Param [] parameters)
215                 {
216                         foreach (Param p in parameters)
217                                 Write (p);
218                 }
219
220                 void Write (ElementType et)
221                 {
222                         Write ((int) et);
223                 }
224
225                 void Write (SigType t)
226                 {
227                         Write ((int) t.ElementType);
228
229                         switch (t.ElementType) {
230                         case ElementType.ValueType :
231                                 Write ((int) Utilities.CompressMetadataToken (
232                                                 CodedIndex.TypeDefOrRef, ((VALUETYPE) t).Type));
233                                 break;
234                         case ElementType.Class :
235                                 Write ((int) Utilities.CompressMetadataToken (
236                                                 CodedIndex.TypeDefOrRef, ((CLASS) t).Type));
237                                 break;
238                         case ElementType.Ptr :
239                                 PTR p = (PTR) t;
240                                 if (p.Void)
241                                         Write (ElementType.Void);
242                                 else {
243                                         Write (p.CustomMods);
244                                         Write (p.PtrType);
245                                 }
246                                 break;
247                         case ElementType.FnPtr :
248                                 FNPTR fp = (FNPTR) t;
249                                 if (fp.Method is MethodRefSig)
250                                         (fp.Method as MethodRefSig).Accept (this);
251                                 else
252                                         (fp.Method as MethodDefSig).Accept (this);
253                                 break;
254                         case ElementType.Array :
255                                 ARRAY ary = (ARRAY) t;
256                                 Write (ary.CustomMods);
257                                 ArrayShape shape = ary.Shape;
258                                 Write (ary.Type);
259                                 Write (shape.Rank);
260                                 Write (shape.NumSizes);
261                                 foreach (int size in shape.Sizes)
262                                         Write (size);
263                                 Write (shape.NumLoBounds);
264                                 foreach (int loBound in shape.LoBounds)
265                                         Write (loBound);
266                                 break;
267                         case ElementType.SzArray :
268                                 SZARRAY sa = (SZARRAY) t;
269                                 Write (sa.CustomMods);
270                                 Write (sa.Type);
271                                 break;
272                         case ElementType.Var :
273                                 Write (((VAR) t).Index);
274                                 break;
275                         case ElementType.MVar :
276                                 Write (((MVAR) t).Index);
277                                 break;
278                         case ElementType.GenericInst :
279                                 GENERICINST gi = t as GENERICINST;
280                                 Write (gi.ValueType ? ElementType.ValueType : ElementType.Class);
281                                 Write ((int) Utilities.CompressMetadataToken (
282                                                 CodedIndex.TypeDefOrRef, gi.Type));
283                                 Write (gi.Signature);
284                                 break;
285                         }
286                 }
287
288                 void Write (TypeSpec ts)
289                 {
290                         Write (ts.Type);
291                 }
292
293                 void Write (MethodSpec ms)
294                 {
295                         Write (0x0a);
296                         Write (ms.Signature);
297                 }
298
299                 void Write (GenericInstSignature gis)
300                 {
301                         Write (gis.Arity);
302                         for (int i = 0; i < gis.Arity; i++)
303                                 Write (gis.Types [i]);
304                 }
305
306                 void Write (GenericArg arg)
307                 {
308                         Write (arg.CustomMods);
309                         Write (arg.Type);
310                 }
311
312                 void Write (Param p)
313                 {
314                         Write (p.CustomMods);
315                         if (p.TypedByRef)
316                                 Write (ElementType.TypedByRef);
317                         else if (p.ByRef) {
318                                 Write (ElementType.ByRef);
319                                 Write (p.Type);
320                         } else
321                                 Write (p.Type);
322                 }
323
324                 void Write (CustomMod [] customMods)
325                 {
326                         foreach (CustomMod cm in customMods)
327                                 Write (cm);
328                 }
329
330                 void Write (CustomMod cm)
331                 {
332                         switch (cm.CMOD) {
333                         case CustomMod.CMODType.OPT :
334                                 Write (ElementType.CModOpt);
335                                 break;
336                         case CustomMod.CMODType.REQD :
337                                 Write (ElementType.CModReqD);
338                                 break;
339                         }
340
341                         Write ((int) Utilities.CompressMetadataToken (
342                                         CodedIndex.TypeDefOrRef, cm.TypeDefOrRef));
343                 }
344
345                 void Write (MarshalSig ms)
346                 {
347                         Write ((int) ms.NativeInstrinsic);
348                         switch (ms.NativeInstrinsic) {
349                         case NativeType.ARRAY :
350                                 MarshalSig.Array ar = (MarshalSig.Array) ms.Spec;
351                                 Write ((int) ar.ArrayElemType);
352                                 if (ar.ParamNum != -1)
353                                         Write (ar.ParamNum);
354                                 if (ar.NumElem != -1)
355                                         Write (ar.NumElem);
356                                 if (ar.ElemMult != -1)
357                                         Write (ar.ElemMult);
358                                 break;
359                         case NativeType.CUSTOMMARSHALER :
360                                 MarshalSig.CustomMarshaler cm = (MarshalSig.CustomMarshaler) ms.Spec;
361                                 Write (cm.Guid);
362                                 Write (cm.UnmanagedType);
363                                 Write (cm.ManagedType);
364                                 Write (cm.Cookie);
365                                 break;
366                         case NativeType.FIXEDARRAY :
367                                 MarshalSig.FixedArray fa = (MarshalSig.FixedArray) ms.Spec;
368                                 Write (fa.NumElem);
369                                 if (fa.ArrayElemType != NativeType.NONE)
370                                         Write ((int) fa.ArrayElemType);
371                                 break;
372                         case NativeType.SAFEARRAY :
373                                 Write ((int) ((MarshalSig.SafeArray) ms.Spec).ArrayElemType);
374                                 break;
375                         case NativeType.FIXEDSYSSTRING :
376                                 Write (((MarshalSig.FixedSysString) ms.Spec).Size);
377                                 break;
378                         }
379                 }
380
381                 void Write (CustomAttrib ca, MethodReference ctor, MemoryBinaryWriter writer)
382                 {
383                         if (ca == null)
384                                 return;
385
386                         if (ca.Prolog != CustomAttrib.StdProlog)
387                                 return;
388
389                         writer.Write (ca.Prolog);
390
391                         for (int i = 0; i < ctor.Parameters.Count; i++)
392                                 Write (ca.FixedArgs [i], writer);
393
394                         writer.Write (ca.NumNamed);
395
396                         for (int i = 0; i < ca.NumNamed; i++)
397                                 Write (ca.NamedArgs [i], writer);
398                 }
399
400                 void Write (CustomAttrib.FixedArg fa, MemoryBinaryWriter writer)
401                 {
402                         if (fa.SzArray)
403                                 writer.Write (fa.NumElem);
404
405                         foreach (CustomAttrib.Elem elem in fa.Elems)
406                                 Write (elem, writer);
407                 }
408
409                 void Write (CustomAttrib.NamedArg na, MemoryBinaryWriter writer)
410                 {
411                         if (na.Field)
412                                 writer.Write ((byte) 0x53);
413                         else if (na.Property)
414                                 writer.Write ((byte) 0x54);
415                         else
416                                 throw new MetadataFormatException ("Unknown kind of namedarg");
417
418                         if (na.FixedArg.SzArray)
419                                 writer.Write ((byte) ElementType.SzArray);
420
421                         if (na.FieldOrPropType == ElementType.Object)
422                                 writer.Write ((byte) ElementType.Boxed);
423                         else
424                                 writer.Write ((byte) na.FieldOrPropType);
425
426                         if (na.FieldOrPropType == ElementType.Enum)
427                                 Write (na.FixedArg.Elems [0].ElemType.FullName);
428
429                         Write (na.FieldOrPropName);
430
431                         Write (na.FixedArg, writer);
432                 }
433
434                 void Write (CustomAttrib.Elem elem, MemoryBinaryWriter writer) // TODO
435                 {
436                         if (elem.String)
437                                 elem.FieldOrPropType = ElementType.String;
438                         else if (elem.Type)
439                                 elem.FieldOrPropType = ElementType.Type;
440                         else if (elem.BoxedValueType)
441                                 Write (elem.FieldOrPropType);
442
443                         switch (elem.FieldOrPropType) {
444                         case ElementType.Boolean :
445                                 writer.Write ((byte) ((bool) elem.Value ? 1 : 0));
446                                 break;
447                         case ElementType.Char :
448                                 writer.Write ((ushort) (char) elem.Value);
449                                 break;
450                         case ElementType.R4 :
451                                 writer.Write ((float) elem.Value);
452                                 break;
453                         case ElementType.R8 :
454                                 writer.Write ((double) elem.Value);
455                                 break;
456                         case ElementType.I1 :
457                                 writer.Write ((sbyte) elem.Value);
458                                 break;
459                         case ElementType.I2 :
460                                 writer.Write ((short) elem.Value);
461                                 break;
462                         case ElementType.I4 :
463                                 writer.Write ((int) elem.Value);
464                                 break;
465                         case ElementType.I8 :
466                                 writer.Write ((long) elem.Value);
467                                 break;
468                         case ElementType.U1 :
469                                 writer.Write ((byte) elem.Value);
470                                 break;
471                         case ElementType.U2 :
472                                 writer.Write ((ushort) elem.Value);
473                                 break;
474                         case ElementType.U4 :
475                                 writer.Write ((uint) elem.Value);
476                                 break;
477                         case ElementType.U8 :
478                                 writer.Write ((long) elem.Value);
479                                 break;
480                         case ElementType.String :
481                         case ElementType.Type :
482                                 string s = elem.Value as string;
483                                 if (s == null)
484                                         writer.Write ((byte) 0xff);
485                                 else if (s.Length == 0)
486                                         writer.Write ((byte) 0x00);
487                                 else
488                                         Write (s);
489                                 break;
490                         case ElementType.Object :
491                                 if (elem.Value != null)
492                                         throw new NotSupportedException ("Unknown state");
493                                 writer.Write ((byte) 0xff);
494                                 break;
495                         default :
496                                 throw new NotImplementedException ("WriteElem " + elem.FieldOrPropType.ToString ());
497                         }
498                 }
499
500                 void Write (string s)
501                 {
502                         byte [] str = Encoding.UTF8.GetBytes (s);
503                         Write (str.Length);
504                         m_sigWriter.Write (str);
505                 }
506
507                 void Write (int i)
508                 {
509                         Utilities.WriteCompressedInteger (m_sigWriter, i);
510                 }
511         }
512 }