update Mono.Cecil
[mono.git] / mcs / class / Mono.Cecil / Mono.Cecil.Metadata / Utilities.cs
1 //
2 // Utilities.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@gmail.com)
6 //
7 // Copyright (c) 2008 - 2011 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 using System;
30
31 using Mono.Cecil.Metadata;
32
33 namespace Mono.Cecil {
34
35         static partial class Mixin {
36
37                 public static uint ReadCompressedUInt32 (this byte [] data, ref int position)
38                 {
39                         uint integer;
40                         if ((data [position] & 0x80) == 0) {
41                                 integer = data [position];
42                                 position++;
43                         } else if ((data [position] & 0x40) == 0) {
44                                 integer = (uint) (data [position] & ~0x80) << 8;
45                                 integer |= data [position + 1];
46                                 position += 2;
47                         } else {
48                                 integer = (uint) (data [position] & ~0xc0) << 24;
49                                 integer |= (uint) data [position + 1] << 16;
50                                 integer |= (uint) data [position + 2] << 8;
51                                 integer |= (uint) data [position + 3];
52                                 position += 4;
53                         }
54                         return integer;
55                 }
56
57                 public static MetadataToken GetMetadataToken (this CodedIndex self, uint data)
58                 {
59                         uint rid;
60                         TokenType token_type;
61                         switch (self) {
62                         case CodedIndex.TypeDefOrRef:
63                                 rid = data >> 2;
64                                 switch (data & 3) {
65                                 case 0:
66                                         token_type = TokenType.TypeDef; goto ret;
67                                 case 1:
68                                         token_type = TokenType.TypeRef; goto ret;
69                                 case 2:
70                                         token_type = TokenType.TypeSpec; goto ret;
71                                 default:
72                                         goto exit;
73                                 }
74                         case CodedIndex.HasConstant:
75                                 rid = data >> 2;
76                                 switch (data & 3) {
77                                 case 0:
78                                         token_type = TokenType.Field; goto ret;
79                                 case 1:
80                                         token_type = TokenType.Param; goto ret;
81                                 case 2:
82                                         token_type = TokenType.Property; goto ret;
83                                 default:
84                                         goto exit;
85                                 }
86                         case CodedIndex.HasCustomAttribute:
87                                 rid = data >> 5;
88                                 switch (data & 31) {
89                                 case 0:
90                                         token_type = TokenType.Method; goto ret;
91                                 case 1:
92                                         token_type = TokenType.Field; goto ret;
93                                 case 2:
94                                         token_type = TokenType.TypeRef; goto ret;
95                                 case 3:
96                                         token_type = TokenType.TypeDef; goto ret;
97                                 case 4:
98                                         token_type = TokenType.Param; goto ret;
99                                 case 5:
100                                         token_type = TokenType.InterfaceImpl; goto ret;
101                                 case 6:
102                                         token_type = TokenType.MemberRef; goto ret;
103                                 case 7:
104                                         token_type = TokenType.Module; goto ret;
105                                 case 8:
106                                         token_type = TokenType.Permission; goto ret;
107                                 case 9:
108                                         token_type = TokenType.Property; goto ret;
109                                 case 10:
110                                         token_type = TokenType.Event; goto ret;
111                                 case 11:
112                                         token_type = TokenType.Signature; goto ret;
113                                 case 12:
114                                         token_type = TokenType.ModuleRef; goto ret;
115                                 case 13:
116                                         token_type = TokenType.TypeSpec; goto ret;
117                                 case 14:
118                                         token_type = TokenType.Assembly; goto ret;
119                                 case 15:
120                                         token_type = TokenType.AssemblyRef; goto ret;
121                                 case 16:
122                                         token_type = TokenType.File; goto ret;
123                                 case 17:
124                                         token_type = TokenType.ExportedType; goto ret;
125                                 case 18:
126                                         token_type = TokenType.ManifestResource; goto ret;
127                                 case 19:
128                                         token_type = TokenType.GenericParam; goto ret;
129                                 default:
130                                         goto exit;
131                                 }
132                         case CodedIndex.HasFieldMarshal:
133                                 rid = data >> 1;
134                                 switch (data & 1) {
135                                 case 0:
136                                         token_type = TokenType.Field; goto ret;
137                                 case 1:
138                                         token_type = TokenType.Param; goto ret;
139                                 default:
140                                         goto exit;
141                                 }
142                         case CodedIndex.HasDeclSecurity:
143                                 rid = data >> 2;
144                                 switch (data & 3) {
145                                 case 0:
146                                         token_type = TokenType.TypeDef; goto ret;
147                                 case 1:
148                                         token_type = TokenType.Method; goto ret;
149                                 case 2:
150                                         token_type = TokenType.Assembly; goto ret;
151                                 default:
152                                         goto exit;
153                                 }
154                         case CodedIndex.MemberRefParent:
155                                 rid = data >> 3;
156                                 switch (data & 7) {
157                                 case 0:
158                                         token_type = TokenType.TypeDef; goto ret;
159                                 case 1:
160                                         token_type = TokenType.TypeRef; goto ret;
161                                 case 2:
162                                         token_type = TokenType.ModuleRef; goto ret;
163                                 case 3:
164                                         token_type = TokenType.Method; goto ret;
165                                 case 4:
166                                         token_type = TokenType.TypeSpec; goto ret;
167                                 default:
168                                         goto exit;
169                                 }
170                         case CodedIndex.HasSemantics:
171                                 rid = data >> 1;
172                                 switch (data & 1) {
173                                 case 0:
174                                         token_type = TokenType.Event; goto ret;
175                                 case 1:
176                                         token_type = TokenType.Property; goto ret;
177                                 default:
178                                         goto exit;
179                                 }
180                         case CodedIndex.MethodDefOrRef:
181                                 rid = data >> 1;
182                                 switch (data & 1) {
183                                 case 0:
184                                         token_type = TokenType.Method; goto ret;
185                                 case 1:
186                                         token_type = TokenType.MemberRef; goto ret;
187                                 default:
188                                         goto exit;
189                                 }
190                         case CodedIndex.MemberForwarded:
191                                 rid = data >> 1;
192                                 switch (data & 1) {
193                                 case 0:
194                                         token_type = TokenType.Field; goto ret;
195                                 case 1:
196                                         token_type = TokenType.Method; goto ret;
197                                 default:
198                                         goto exit;
199                                 }
200                         case CodedIndex.Implementation:
201                                 rid = data >> 2;
202                                 switch (data & 3) {
203                                 case 0:
204                                         token_type = TokenType.File; goto ret;
205                                 case 1:
206                                         token_type = TokenType.AssemblyRef; goto ret;
207                                 case 2:
208                                         token_type = TokenType.ExportedType; goto ret;
209                                 default:
210                                         goto exit;
211                                 }
212                         case CodedIndex.CustomAttributeType:
213                                 rid = data >> 3;
214                                 switch (data & 7) {
215                                 case 2:
216                                         token_type = TokenType.Method; goto ret;
217                                 case 3:
218                                         token_type = TokenType.MemberRef; goto ret;
219                                 default:
220                                         goto exit;
221                                 }
222                         case CodedIndex.ResolutionScope:
223                                 rid = data >> 2;
224                                 switch (data & 3) {
225                                 case 0:
226                                         token_type = TokenType.Module; goto ret;
227                                 case 1:
228                                         token_type = TokenType.ModuleRef; goto ret;
229                                 case 2:
230                                         token_type = TokenType.AssemblyRef; goto ret;
231                                 case 3:
232                                         token_type = TokenType.TypeRef; goto ret;
233                                 default:
234                                         goto exit;
235                                 }
236                         case CodedIndex.TypeOrMethodDef:
237                                 rid = data >> 1;
238                                 switch (data & 1) {
239                                 case 0:
240                                         token_type = TokenType.TypeDef; goto ret;
241                                 case 1:
242                                         token_type = TokenType.Method; goto ret;
243                                 default: goto exit;
244                                 }
245                         default:
246                                 goto exit;
247                         }
248                 ret:
249                         return new MetadataToken (token_type, rid);
250                 exit:
251                         return MetadataToken.Zero;
252                 }
253
254 #if !READ_ONLY
255                 public static uint CompressMetadataToken (this CodedIndex self, MetadataToken token)
256                 {
257                         uint ret = 0;
258                         if (token.RID == 0)
259                                 return ret;
260                         switch (self) {
261                         case CodedIndex.TypeDefOrRef:
262                                 ret = token.RID << 2;
263                                 switch (token.TokenType) {
264                                 case TokenType.TypeDef:
265                                         return ret | 0;
266                                 case TokenType.TypeRef:
267                                         return ret | 1;
268                                 case TokenType.TypeSpec:
269                                         return ret | 2;
270                                 default:
271                                         goto exit;
272                                 }
273                         case CodedIndex.HasConstant:
274                                 ret = token.RID << 2;
275                                 switch (token.TokenType) {
276                                 case TokenType.Field:
277                                         return ret | 0;
278                                 case TokenType.Param:
279                                         return ret | 1;
280                                 case TokenType.Property:
281                                         return ret | 2;
282                                 default:
283                                         goto exit;
284                                 }
285                         case CodedIndex.HasCustomAttribute:
286                                 ret = token.RID << 5;
287                                 switch (token.TokenType) {
288                                 case TokenType.Method:
289                                         return ret | 0;
290                                 case TokenType.Field:
291                                         return ret | 1;
292                                 case TokenType.TypeRef:
293                                         return ret | 2;
294                                 case TokenType.TypeDef:
295                                         return ret | 3;
296                                 case TokenType.Param:
297                                         return ret | 4;
298                                 case TokenType.InterfaceImpl:
299                                         return ret | 5;
300                                 case TokenType.MemberRef:
301                                         return ret | 6;
302                                 case TokenType.Module:
303                                         return ret | 7;
304                                 case TokenType.Permission:
305                                         return ret | 8;
306                                 case TokenType.Property:
307                                         return ret | 9;
308                                 case TokenType.Event:
309                                         return ret | 10;
310                                 case TokenType.Signature:
311                                         return ret | 11;
312                                 case TokenType.ModuleRef:
313                                         return ret | 12;
314                                 case TokenType.TypeSpec:
315                                         return ret | 13;
316                                 case TokenType.Assembly:
317                                         return ret | 14;
318                                 case TokenType.AssemblyRef:
319                                         return ret | 15;
320                                 case TokenType.File:
321                                         return ret | 16;
322                                 case TokenType.ExportedType:
323                                         return ret | 17;
324                                 case TokenType.ManifestResource:
325                                         return ret | 18;
326                                 case TokenType.GenericParam:
327                                         return ret | 19;
328                                 default:
329                                         goto exit;
330                                 }
331                         case CodedIndex.HasFieldMarshal:
332                                 ret = token.RID << 1;
333                                 switch (token.TokenType) {
334                                 case TokenType.Field:
335                                         return ret | 0;
336                                 case TokenType.Param:
337                                         return ret | 1;
338                                 default:
339                                         goto exit;
340                                 }
341                         case CodedIndex.HasDeclSecurity:
342                                 ret = token.RID << 2;
343                                 switch (token.TokenType) {
344                                 case TokenType.TypeDef:
345                                         return ret | 0;
346                                 case TokenType.Method:
347                                         return ret | 1;
348                                 case TokenType.Assembly:
349                                         return ret | 2;
350                                 default:
351                                         goto exit;
352                                 }
353                         case CodedIndex.MemberRefParent:
354                                 ret = token.RID << 3;
355                                 switch (token.TokenType) {
356                                 case TokenType.TypeDef:
357                                         return ret | 0;
358                                 case TokenType.TypeRef:
359                                         return ret | 1;
360                                 case TokenType.ModuleRef:
361                                         return ret | 2;
362                                 case TokenType.Method:
363                                         return ret | 3;
364                                 case TokenType.TypeSpec:
365                                         return ret | 4;
366                                 default:
367                                         goto exit;
368                                 }
369                         case CodedIndex.HasSemantics:
370                                 ret = token.RID << 1;
371                                 switch (token.TokenType) {
372                                 case TokenType.Event:
373                                         return ret | 0;
374                                 case TokenType.Property:
375                                         return ret | 1;
376                                 default:
377                                         goto exit;
378                                 }
379                         case CodedIndex.MethodDefOrRef:
380                                 ret = token.RID << 1;
381                                 switch (token.TokenType) {
382                                 case TokenType.Method:
383                                         return ret | 0;
384                                 case TokenType.MemberRef:
385                                         return ret | 1;
386                                 default:
387                                         goto exit;
388                                 }
389                         case CodedIndex.MemberForwarded:
390                                 ret = token.RID << 1;
391                                 switch (token.TokenType) {
392                                 case TokenType.Field:
393                                         return ret | 0;
394                                 case TokenType.Method:
395                                         return ret | 1;
396                                 default:
397                                         goto exit;
398                                 }
399                         case CodedIndex.Implementation:
400                                 ret = token.RID << 2;
401                                 switch (token.TokenType) {
402                                 case TokenType.File:
403                                         return ret | 0;
404                                 case TokenType.AssemblyRef:
405                                         return ret | 1;
406                                 case TokenType.ExportedType:
407                                         return ret | 2;
408                                 default:
409                                         goto exit;
410                                 }
411                         case CodedIndex.CustomAttributeType:
412                                 ret = token.RID << 3;
413                                 switch (token.TokenType) {
414                                 case TokenType.Method:
415                                         return ret | 2;
416                                 case TokenType.MemberRef:
417                                         return ret | 3;
418                                 default:
419                                         goto exit;
420                                 }
421                         case CodedIndex.ResolutionScope:
422                                 ret = token.RID << 2;
423                                 switch (token.TokenType) {
424                                 case TokenType.Module:
425                                         return ret | 0;
426                                 case TokenType.ModuleRef:
427                                         return ret | 1;
428                                 case TokenType.AssemblyRef:
429                                         return ret | 2;
430                                 case TokenType.TypeRef:
431                                         return ret | 3;
432                                 default:
433                                         goto exit;
434                                 }
435                         case CodedIndex.TypeOrMethodDef:
436                                 ret = token.RID << 1;
437                                 switch (token.TokenType) {
438                                 case TokenType.TypeDef:
439                                         return ret | 0;
440                                 case TokenType.Method:
441                                         return ret | 1;
442                                 default:
443                                         goto exit;
444                                 }
445                         default:
446                                 goto exit;
447                         }
448                 exit:
449                         throw new ArgumentException ();
450                 }
451 #endif
452
453                 public static int GetSize (this CodedIndex self, Func<Table, int> counter)
454                 {
455                         int bits;
456                         Table [] tables;
457
458                         switch (self) {
459                         case CodedIndex.TypeDefOrRef:
460                                 bits = 2;
461                                 tables = new [] { Table.TypeDef, Table.TypeRef, Table.TypeSpec };
462                                 break;
463                         case CodedIndex.HasConstant:
464                                 bits = 2;
465                                 tables = new [] { Table.Field, Table.Param, Table.Property };
466                                 break;
467                         case CodedIndex.HasCustomAttribute:
468                                 bits = 5;
469                                 tables = new [] {
470                                         Table.Method, Table.Field, Table.TypeRef, Table.TypeDef, Table.Param, Table.InterfaceImpl, Table.MemberRef,
471                                         Table.Module, Table.DeclSecurity, Table.Property, Table.Event, Table.StandAloneSig, Table.ModuleRef,
472                                         Table.TypeSpec, Table.Assembly, Table.AssemblyRef, Table.File, Table.ExportedType,
473                                         Table.ManifestResource, Table.GenericParam
474                                 };
475                                 break;
476                         case CodedIndex.HasFieldMarshal:
477                                 bits = 1;
478                                 tables = new [] { Table.Field, Table.Param };
479                                 break;
480                         case CodedIndex.HasDeclSecurity:
481                                 bits = 2;
482                                 tables = new [] { Table.TypeDef, Table.Method, Table.Assembly };
483                                 break;
484                         case CodedIndex.MemberRefParent:
485                                 bits = 3;
486                                 tables = new [] { Table.TypeDef, Table.TypeRef, Table.ModuleRef, Table.Method, Table.TypeSpec };
487                                 break;
488                         case CodedIndex.HasSemantics:
489                                 bits = 1;
490                                 tables = new [] { Table.Event, Table.Property };
491                                 break;
492                         case CodedIndex.MethodDefOrRef:
493                                 bits = 1;
494                                 tables = new [] { Table.Method, Table.MemberRef };
495                                 break;
496                         case CodedIndex.MemberForwarded:
497                                 bits = 1;
498                                 tables = new [] { Table.Field, Table.Method };
499                                 break;
500                         case CodedIndex.Implementation:
501                                 bits = 2;
502                                 tables = new [] { Table.File, Table.AssemblyRef, Table.ExportedType };
503                                 break;
504                         case CodedIndex.CustomAttributeType:
505                                 bits = 3;
506                                 tables = new [] { Table.Method, Table.MemberRef };
507                                 break;
508                         case CodedIndex.ResolutionScope:
509                                 bits = 2;
510                                 tables = new [] { Table.Module, Table.ModuleRef, Table.AssemblyRef, Table.TypeRef };
511                                 break;
512                         case CodedIndex.TypeOrMethodDef:
513                                 bits = 1;
514                                 tables = new [] { Table.TypeDef, Table.Method };
515                                 break;
516                         default:
517                                 throw new ArgumentException ();
518                         }
519
520                         int max = 0;
521
522                         for (int i = 0; i < tables.Length; i++) {
523                                 max = System.Math.Max (counter (tables [i]), max);
524                         }
525
526                         return max < (1 << (16 - bits)) ? 2 : 4;
527                 }
528         }
529 }