Merge remote branch 'upstream/master'
[mono.git] / mcs / class / IKVM.Reflection / Writer / MetadataWriter.cs
1 /*
2   Copyright (C) 2008 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.IO;
26 using System.Collections.Generic;
27 using System.Text;
28 using IKVM.Reflection.Emit;
29 using IKVM.Reflection.Metadata;
30
31 namespace IKVM.Reflection.Writer
32 {
33         sealed class MetadataWriter : MetadataRW
34         {
35                 private readonly ModuleBuilder moduleBuilder;
36                 private readonly Stream stream;
37                 private readonly byte[] buffer = new byte[8];
38
39                 internal MetadataWriter(ModuleBuilder module, Stream stream)
40                         : base(module, module.Strings.IsBig, module.Guids.IsBig, module.Blobs.IsBig)
41                 {
42                         this.moduleBuilder = module;
43                         this.stream = stream;
44                 }
45
46                 internal ModuleBuilder ModuleBuilder
47                 {
48                         get { return moduleBuilder; }
49                 }
50
51                 internal int Position
52                 {
53                         get { return (int)stream.Position; }
54                 }
55
56                 internal void Write(ByteBuffer bb)
57                 {
58                         bb.WriteTo(stream);
59                 }
60
61                 internal void Write(byte[] value)
62                 {
63                         stream.Write(value, 0, value.Length);
64                 }
65
66                 internal void Write(byte value)
67                 {
68                         stream.WriteByte(value);
69                 }
70
71                 internal void Write(ushort value)
72                 {
73                         Write((short)value);
74                 }
75
76                 internal void Write(short value)
77                 {
78                         buffer[0] = (byte)value;
79                         buffer[1] = (byte)(value >> 8);
80                         stream.Write(buffer, 0, 2);
81                 }
82
83                 internal void Write(uint value)
84                 {
85                         Write((int)value);
86                 }
87
88                 internal void Write(int value)
89                 {
90                         buffer[0] = (byte)value;
91                         buffer[1] = (byte)(value >> 8);
92                         buffer[2] = (byte)(value >> 16);
93                         buffer[3] = (byte)(value >> 24);
94                         stream.Write(buffer, 0, 4);
95                 }
96
97                 internal void Write(ulong value)
98                 {
99                         Write((long)value);
100                 }
101
102                 internal void Write(long value)
103                 {
104                         buffer[0] = (byte)value;
105                         buffer[1] = (byte)(value >> 8);
106                         buffer[2] = (byte)(value >> 16);
107                         buffer[3] = (byte)(value >> 24);
108                         buffer[4] = (byte)(value >> 32);
109                         buffer[5] = (byte)(value >> 40);
110                         buffer[6] = (byte)(value >> 48);
111                         buffer[7] = (byte)(value >> 56);
112                         stream.Write(buffer, 0, 8);
113                 }
114
115                 internal void WriteCompressedInt(int value)
116                 {
117                         if (value <= 0x7F)
118                         {
119                                 Write((byte)value);
120                         }
121                         else if (value <= 0x3FFF)
122                         {
123                                 Write((byte)(0x80 | (value >> 8)));
124                                 Write((byte)value);
125                         }
126                         else
127                         {
128                                 Write((byte)(0xC0 | (value >> 24)));
129                                 Write((byte)(value >> 16));
130                                 Write((byte)(value >> 8));
131                                 Write((byte)value);
132                         }
133                 }
134
135                 internal static int GetCompressedIntLength(int value)
136                 {
137                         if (value <= 0x7F)
138                         {
139                                 return 1;
140                         }
141                         else if (value <= 0x3FFF)
142                         {
143                                 return 2;
144                         }
145                         else
146                         {
147                                 return 4;
148                         }
149                 }
150
151                 internal void WriteStringIndex(int index)
152                 {
153                         if (bigStrings)
154                         {
155                                 Write(index);
156                         }
157                         else
158                         {
159                                 Write((short)index);
160                         }
161                 }
162
163                 internal void WriteGuidIndex(int index)
164                 {
165                         if (bigGuids)
166                         {
167                                 Write(index);
168                         }
169                         else
170                         {
171                                 Write((short)index);
172                         }
173                 }
174
175                 internal void WriteBlobIndex(int index)
176                 {
177                         if (bigBlobs)
178                         {
179                                 Write(index);
180                         }
181                         else
182                         {
183                                 Write((short)index);
184                         }
185                 }
186
187                 internal void WriteTypeDefOrRef(int token)
188                 {
189                         switch (token >> 24)
190                         {
191                                 case 0:
192                                         break;
193                                 case TypeDefTable.Index:
194                                         token = (token & 0xFFFFFF) << 2 | 0;
195                                         break;
196                                 case TypeRefTable.Index:
197                                         token = (token & 0xFFFFFF) << 2 | 1;
198                                         break;
199                                 case TypeSpecTable.Index:
200                                         token = (token & 0xFFFFFF) << 2 | 2;
201                                         break;
202                                 default:
203                                         throw new InvalidOperationException();
204                         }
205                         if (bigTypeDefOrRef)
206                         {
207                                 Write(token);
208                         }
209                         else
210                         {
211                                 Write((short)token);
212                         }
213                 }
214
215                 internal void WriteEncodedTypeDefOrRef(int encodedToken)
216                 {
217                         if (bigTypeDefOrRef)
218                         {
219                                 Write(encodedToken);
220                         }
221                         else
222                         {
223                                 Write((short)encodedToken);
224                         }
225                 }
226
227                 internal void WriteHasCustomAttribute(int encodedToken)
228                 {
229                         // NOTE because we've already had to do the encoding (to be able to sort the table)
230                         // here we simple write the value
231                         if (bigHasCustomAttribute)
232                         {
233                                 Write(encodedToken);
234                         }
235                         else
236                         {
237                                 Write((short)encodedToken);
238                         }
239                 }
240
241                 internal void WriteCustomAttributeType(int token)
242                 {
243                         switch (token >> 24)
244                         {
245                                 case MethodDefTable.Index:
246                                         token = (token & 0xFFFFFF) << 3 | 2;
247                                         break;
248                                 case MemberRefTable.Index:
249                                         token = (token & 0xFFFFFF) << 3 | 3;
250                                         break;
251                                 default:
252                                         throw new InvalidOperationException();
253                         }
254                         if (bigCustomAttributeType)
255                         {
256                                 Write(token);
257                         }
258                         else
259                         {
260                                 Write((short)token);
261                         }
262                 }
263
264                 internal void WriteField(int index)
265                 {
266                         if (bigField)
267                         {
268                                 Write(index & 0xFFFFFF);
269                         }
270                         else
271                         {
272                                 Write((short)index);
273                         }
274                 }
275
276                 internal void WriteMethodDef(int index)
277                 {
278                         if (bigMethodDef)
279                         {
280                                 Write(index & 0xFFFFFF);
281                         }
282                         else
283                         {
284                                 Write((short)index);
285                         }
286                 }
287
288                 internal void WriteParam(int index)
289                 {
290                         if (bigParam)
291                         {
292                                 Write(index & 0xFFFFFF);
293                         }
294                         else
295                         {
296                                 Write((short)index);
297                         }
298                 }
299
300                 internal void WriteTypeDef(int index)
301                 {
302                         if (bigTypeDef)
303                         {
304                                 Write(index & 0xFFFFFF);
305                         }
306                         else
307                         {
308                                 Write((short)index);
309                         }
310                 }
311
312                 internal void WriteEvent(int index)
313                 {
314                         if (bigEvent)
315                         {
316                                 Write(index & 0xFFFFFF);
317                         }
318                         else
319                         {
320                                 Write((short)index);
321                         }
322                 }
323
324                 internal void WriteProperty(int index)
325                 {
326                         if (bigProperty)
327                         {
328                                 Write(index & 0xFFFFFF);
329                         }
330                         else
331                         {
332                                 Write((short)index);
333                         }
334                 }
335
336                 internal void WriteGenericParam(int index)
337                 {
338                         if (bigGenericParam)
339                         {
340                                 Write(index & 0xFFFFFF);
341                         }
342                         else
343                         {
344                                 Write((short)index);
345                         }
346                 }
347
348                 internal void WriteModuleRef(int index)
349                 {
350                         if (bigModuleRef)
351                         {
352                                 Write(index & 0xFFFFFF);
353                         }
354                         else
355                         {
356                                 Write((short)index);
357                         }
358                 }
359
360                 internal void WriteResolutionScope(int token)
361                 {
362                         switch (token >> 24)
363                         {
364                                 case ModuleTable.Index:
365                                         token = (token & 0xFFFFFF) << 2 | 0;
366                                         break;
367                                 case ModuleRefTable.Index:
368                                         token = (token & 0xFFFFFF) << 2 | 1;
369                                         break;
370                                 case AssemblyRefTable.Index:
371                                         token = (token & 0xFFFFFF) << 2 | 2;
372                                         break;
373                                 case TypeRefTable.Index:
374                                         token = (token & 0xFFFFFF) << 2 | 3;
375                                         break;
376                                 default:
377                                         throw new InvalidOperationException();
378                         }
379                         if (bigResolutionScope)
380                         {
381                                 Write(token);
382                         }
383                         else
384                         {
385                                 Write((short)token);
386                         }
387                 }
388
389                 internal void WriteMemberRefParent(int token)
390                 {
391                         switch (token >> 24)
392                         {
393                                 case TypeDefTable.Index:
394                                         token = (token & 0xFFFFFF) << 3 | 0;
395                                         break;
396                                 case TypeRefTable.Index:
397                                         token = (token & 0xFFFFFF) << 3 | 1;
398                                         break;
399                                 case ModuleRefTable.Index:
400                                         token = (token & 0xFFFFFF) << 3 | 2;
401                                         break;
402                                 case MethodDefTable.Index:
403                                         token = (token & 0xFFFFFF) << 3 | 3;
404                                         break;
405                                 case TypeSpecTable.Index:
406                                         token = (token & 0xFFFFFF) << 3 | 4;
407                                         break;
408                                 default:
409                                         throw new InvalidOperationException();
410                         }
411                         if (bigMemberRefParent)
412                         {
413                                 Write(token);
414                         }
415                         else
416                         {
417                                 Write((short)token);
418                         }
419                 }
420
421                 internal void WriteMethodDefOrRef(int token)
422                 {
423                         switch (token >> 24)
424                         {
425                                 case MethodDefTable.Index:
426                                         token = (token & 0xFFFFFF) << 1 | 0;
427                                         break;
428                                 case MemberRefTable.Index:
429                                         token = (token & 0xFFFFFF) << 1 | 1;
430                                         break;
431                                 default:
432                                         throw new InvalidOperationException();
433                         }
434                         if (bigMethodDefOrRef)
435                         {
436                                 Write(token);
437                         }
438                         else
439                         {
440                                 Write((short)token);
441                         }
442                 }
443
444                 internal void WriteHasConstant(int encodedToken)
445                 {
446                         // NOTE because we've already had to do the encoding (to be able to sort the table)
447                         // here we simple write the value
448                         if (bigHasConstant)
449                         {
450                                 Write(encodedToken);
451                         }
452                         else
453                         {
454                                 Write((short)encodedToken);
455                         }
456                 }
457
458                 internal void WriteHasSemantics(int encodedToken)
459                 {
460                         // NOTE because we've already had to do the encoding (to be able to sort the table)
461                         // here we simple write the value
462                         if (bigHasSemantics)
463                         {
464                                 Write(encodedToken);
465                         }
466                         else
467                         {
468                                 Write((short)encodedToken);
469                         }
470                 }
471
472                 internal void WriteImplementation(int token)
473                 {
474                         switch (token >> 24)
475                         {
476                                 case 0:
477                                         break;
478                                 case FileTable.Index:
479                                         token = (token & 0xFFFFFF) << 2 | 0;
480                                         break;
481                                 case AssemblyRefTable.Index:
482                                         token = (token & 0xFFFFFF) << 2 | 1;
483                                         break;
484                                 case ExportedTypeTable.Index:
485                                         token = (token & 0xFFFFFF) << 2 | 2;
486                                         break;
487                                 default:
488                                         throw new InvalidOperationException();
489                         }
490                         if (bigImplementation)
491                         {
492                                 Write(token);
493                         }
494                         else
495                         {
496                                 Write((short)token);
497                         }
498                 }
499
500                 internal void WriteTypeOrMethodDef(int encodedToken)
501                 {
502                         // NOTE because we've already had to do the encoding (to be able to sort the table)
503                         // here we simple write the value
504                         if (bigTypeOrMethodDef)
505                         {
506                                 Write(encodedToken);
507                         }
508                         else
509                         {
510                                 Write((short)encodedToken);
511                         }
512                 }
513
514                 internal void WriteHasDeclSecurity(int encodedToken)
515                 {
516                         // NOTE because we've already had to do the encoding (to be able to sort the table)
517                         // here we simple write the value
518                         if (bigHasDeclSecurity)
519                         {
520                                 Write(encodedToken);
521                         }
522                         else
523                         {
524                                 Write((short)encodedToken);
525                         }
526                 }
527
528                 internal void WriteMemberForwarded(int token)
529                 {
530                         switch (token >> 24)
531                         {
532                                 case FieldTable.Index:
533                                         token = (token & 0xFFFFFF) << 1 | 0;
534                                     break;
535                                 case MethodDefTable.Index:
536                                         token = (token & 0xFFFFFF) << 1 | 1;
537                                         break;
538                                 default:
539                                         throw new InvalidOperationException();
540                         }
541                         if (bigMemberForwarded)
542                         {
543                                 Write(token);
544                         }
545                         else
546                         {
547                                 Write((short)token);
548                         }
549                 }
550
551                 internal void WriteHasFieldMarshal(int encodedToken)
552                 {
553                         // NOTE because we've already had to do the encoding (to be able to sort the table)
554                         // here we simple write the value
555                         if (bigHasFieldMarshal)
556                         {
557                                 Write(encodedToken & 0xFFFFFF);
558                         }
559                         else
560                         {
561                                 Write((short)encodedToken);
562                         }
563                 }
564         }
565 }