1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | |
5 | //***************************************************************************** |
6 | // This code supports formatting a method and it's signature in a friendly |
7 | // and consistent format. |
8 | // |
9 | //***************************************************************************** |
10 | #include "stdafx.h" |
11 | #include "prettyprintsig.h" |
12 | #include "utilcode.h" |
13 | #include "metadata.h" |
14 | #include "corpriv.h" |
15 | |
16 | /***********************************************************************/ |
17 | // Null-terminates the string held in "out" |
18 | |
19 | static WCHAR* asStringW(CQuickBytes *out) |
20 | { |
21 | CONTRACTL |
22 | { |
23 | NOTHROW; |
24 | INJECT_FAULT(return NULL;); |
25 | } |
26 | CONTRACTL_END |
27 | |
28 | SIZE_T oldSize = out->Size(); |
29 | if (FAILED(out->ReSizeNoThrow(oldSize + 1))) |
30 | return 0; |
31 | WCHAR * cur = (WCHAR *) ((BYTE *) out->Ptr() + oldSize); |
32 | *cur = 0; |
33 | return((WCHAR*) out->Ptr()); |
34 | } // static WCHAR* asStringW() |
35 | |
36 | // Null-terminates the string held in "out" |
37 | |
38 | static CHAR* asStringA(CQuickBytes *out) |
39 | { |
40 | CONTRACTL |
41 | { |
42 | NOTHROW; |
43 | INJECT_FAULT(return NULL;); |
44 | } |
45 | CONTRACTL_END |
46 | |
47 | SIZE_T oldSize = out->Size(); |
48 | if (FAILED(out->ReSizeNoThrow(oldSize + 1))) |
49 | return 0; |
50 | CHAR * cur = (CHAR *) ((BYTE *) out->Ptr() + oldSize); |
51 | *cur = 0; |
52 | return((CHAR*) out->Ptr()); |
53 | } // static CHAR* asStringA() |
54 | |
55 | /***********************************************************************/ |
56 | // Appends the str to "out" |
57 | // The string held in "out" is not NULL-terminated. asStringW() needs to |
58 | // be called for the NULL-termination |
59 | |
60 | static HRESULT appendStrW(CQuickBytes *out, const WCHAR* str) |
61 | { |
62 | CONTRACTL |
63 | { |
64 | NOTHROW; |
65 | INJECT_FAULT(return E_OUTOFMEMORY;); |
66 | } |
67 | CONTRACTL_END |
68 | |
69 | SIZE_T len = wcslen(str) * sizeof(WCHAR); |
70 | SIZE_T oldSize = out->Size(); |
71 | if (FAILED(out->ReSizeNoThrow(oldSize + len))) |
72 | return E_OUTOFMEMORY; |
73 | WCHAR * cur = (WCHAR *) ((BYTE *) out->Ptr() + oldSize); |
74 | memcpy(cur, str, len); |
75 | // Note no trailing null! |
76 | return S_OK; |
77 | } // static HRESULT appendStrW() |
78 | |
79 | // Appends the str to "out" |
80 | // The string held in "out" is not NULL-terminated. asStringA() needs to |
81 | // be called for the NULL-termination |
82 | |
83 | static HRESULT appendStrA(CQuickBytes *out, const CHAR* str) |
84 | { |
85 | CONTRACTL |
86 | { |
87 | NOTHROW; |
88 | INJECT_FAULT(return E_OUTOFMEMORY;); |
89 | } |
90 | CONTRACTL_END |
91 | |
92 | SIZE_T len = strlen(str) * sizeof(CHAR); |
93 | SIZE_T oldSize = out->Size(); |
94 | if (FAILED(out->ReSizeNoThrow(oldSize + len))) |
95 | return E_OUTOFMEMORY; |
96 | CHAR * cur = (CHAR *) ((BYTE *) out->Ptr() + oldSize); |
97 | memcpy(cur, str, len); |
98 | // Note no trailing null! |
99 | return S_OK; |
100 | } // static HRESULT appendStrA() |
101 | |
102 | |
103 | static HRESULT appendStrNumW(CQuickBytes *out, int num) |
104 | { |
105 | CONTRACTL |
106 | { |
107 | NOTHROW; |
108 | INJECT_FAULT(return E_OUTOFMEMORY;); |
109 | } |
110 | CONTRACTL_END |
111 | |
112 | WCHAR buff[32]; |
113 | swprintf_s(buff, 32, W("%d" ), num); |
114 | return appendStrW(out, buff); |
115 | } // static HRESULT appendStrNumW() |
116 | |
117 | static HRESULT appendStrNumA(CQuickBytes *out, int num) |
118 | { |
119 | CONTRACTL |
120 | { |
121 | NOTHROW; |
122 | INJECT_FAULT(return E_OUTOFMEMORY;); |
123 | } |
124 | CONTRACTL_END |
125 | |
126 | CHAR buff[32]; |
127 | sprintf_s(buff, 32, "%d" , num); |
128 | return appendStrA(out, buff); |
129 | } // static HRESULT appendStrNumA() |
130 | |
131 | static HRESULT appendStrHexW(CQuickBytes *out, int num) |
132 | { |
133 | CONTRACTL |
134 | { |
135 | NOTHROW; |
136 | INJECT_FAULT(return E_OUTOFMEMORY;); |
137 | } |
138 | CONTRACTL_END |
139 | |
140 | WCHAR buff[32]; |
141 | swprintf_s(buff, 32, W("%08X" ), num); |
142 | return appendStrW(out, buff); |
143 | } // static HRESULT appendStrHexW() |
144 | |
145 | static HRESULT appendStrHexA(CQuickBytes *out, int num) |
146 | { |
147 | CONTRACTL |
148 | { |
149 | NOTHROW; |
150 | INJECT_FAULT(return E_OUTOFMEMORY;); |
151 | } |
152 | CONTRACTL_END |
153 | |
154 | CHAR buff[32]; |
155 | sprintf_s(buff, 32, "%08X" , num); |
156 | return appendStrA(out, buff); |
157 | } // static HRESULT appendStrHexA() |
158 | |
159 | /***********************************************************************/ |
160 | |
161 | LPCWSTR PrettyPrintSigWorker( |
162 | PCCOR_SIGNATURE & typePtr, // type to convert, |
163 | size_t typeLen, // length of type |
164 | const WCHAR * name, // can be "", the name of the method for this sig |
165 | CQuickBytes * out, // where to put the pretty printed string |
166 | IMetaDataImport * pIMDI); // Import api to use. |
167 | |
168 | //***************************************************************************** |
169 | //***************************************************************************** |
170 | // pretty prints 'type' to the buffer 'out' returns a pointer to the next type, |
171 | // or 0 on a format failure |
172 | |
173 | static PCCOR_SIGNATURE PrettyPrintType( |
174 | PCCOR_SIGNATURE typePtr, // type to convert, |
175 | size_t typeLen, // Maximum length of the type |
176 | CQuickBytes * out, // where to put the pretty printed string |
177 | IMetaDataImport * pIMDI) // ptr to IMDInternal class with ComSig |
178 | { |
179 | mdToken tk; |
180 | const WCHAR * str; |
181 | WCHAR rcname[MAX_CLASS_NAME]; |
182 | HRESULT hr; |
183 | unsigned __int8 elt = *typePtr++; |
184 | PCCOR_SIGNATURE typeEnd = typePtr + typeLen; |
185 | |
186 | switch(elt) |
187 | { |
188 | case ELEMENT_TYPE_VOID: |
189 | str = W("void" ); |
190 | goto APPEND; |
191 | |
192 | case ELEMENT_TYPE_BOOLEAN: |
193 | str = W("bool" ); |
194 | goto APPEND; |
195 | |
196 | case ELEMENT_TYPE_CHAR: |
197 | str = W("wchar" ); |
198 | goto APPEND; |
199 | |
200 | case ELEMENT_TYPE_I1: |
201 | str = W("int8" ); |
202 | goto APPEND; |
203 | |
204 | case ELEMENT_TYPE_U1: |
205 | str = W("unsigned int8" ); |
206 | goto APPEND; |
207 | |
208 | case ELEMENT_TYPE_I2: |
209 | str = W("int16" ); |
210 | goto APPEND; |
211 | |
212 | case ELEMENT_TYPE_U2: |
213 | str = W("unsigned int16" ); |
214 | goto APPEND; |
215 | |
216 | case ELEMENT_TYPE_I4: |
217 | str = W("int32" ); |
218 | goto APPEND; |
219 | |
220 | case ELEMENT_TYPE_U4: |
221 | str = W("unsigned int32" ); |
222 | goto APPEND; |
223 | |
224 | case ELEMENT_TYPE_I8: |
225 | str = W("int64" ); |
226 | goto APPEND; |
227 | |
228 | case ELEMENT_TYPE_U8: |
229 | str = W("unsigned int64" ); |
230 | goto APPEND; |
231 | |
232 | case ELEMENT_TYPE_R4: |
233 | str = W("float32" ); |
234 | goto APPEND; |
235 | |
236 | case ELEMENT_TYPE_R8: |
237 | str = W("float64" ); |
238 | goto APPEND; |
239 | |
240 | case ELEMENT_TYPE_U: |
241 | str = W("unsigned int" ); |
242 | goto APPEND; |
243 | |
244 | case ELEMENT_TYPE_I: |
245 | str = W("int" ); |
246 | goto APPEND; |
247 | |
248 | case ELEMENT_TYPE_OBJECT: |
249 | str = W("class System.Object" ); |
250 | goto APPEND; |
251 | |
252 | case ELEMENT_TYPE_STRING: |
253 | str = W("class System.String" ); |
254 | goto APPEND; |
255 | |
256 | case ELEMENT_TYPE_CANON_ZAPSIG: |
257 | str = W("class System.__Canon" ); |
258 | goto APPEND; |
259 | |
260 | case ELEMENT_TYPE_TYPEDBYREF: |
261 | str = W("refany" ); |
262 | goto APPEND; |
263 | |
264 | APPEND: |
265 | appendStrW(out, str); |
266 | break; |
267 | |
268 | case ELEMENT_TYPE_VALUETYPE: |
269 | str = W("value class " ); |
270 | goto DO_CLASS; |
271 | |
272 | case ELEMENT_TYPE_CLASS: |
273 | str = W("class " ); |
274 | goto DO_CLASS; |
275 | |
276 | DO_CLASS: |
277 | typePtr += CorSigUncompressToken(typePtr, &tk); |
278 | appendStrW(out, str); |
279 | rcname[0] = 0; |
280 | str = rcname; |
281 | |
282 | if (TypeFromToken(tk) == mdtTypeRef) |
283 | { |
284 | hr = pIMDI->GetTypeRefProps(tk, 0, rcname, NumItems(rcname), 0); |
285 | } |
286 | else if (TypeFromToken(tk) == mdtTypeDef) |
287 | { |
288 | hr = pIMDI->GetTypeDefProps(tk, rcname, NumItems(rcname), 0, 0, 0); |
289 | } |
290 | else |
291 | { |
292 | _ASSERTE(!"Unknown token type encountered in signature." ); |
293 | str = W("<UNKNOWN>" ); |
294 | } |
295 | |
296 | appendStrW(out, str); |
297 | break; |
298 | |
299 | case ELEMENT_TYPE_SZARRAY: |
300 | typePtr = PrettyPrintType(typePtr, (typeEnd - typePtr), out, pIMDI); |
301 | appendStrW(out, W("[]" )); |
302 | break; |
303 | |
304 | case ELEMENT_TYPE_ARRAY: |
305 | { |
306 | typePtr = PrettyPrintType(typePtr, (typeEnd - typePtr), out, pIMDI); |
307 | unsigned rank = CorSigUncompressData(typePtr); |
308 | PREFIX_ASSUME(rank <= 0xffffff); |
309 | |
310 | // <TODO>TODO what is the syntax for the rank 0 case? </TODO> |
311 | if (rank == 0) |
312 | { |
313 | appendStrW(out, W("[??]" )); |
314 | } |
315 | else |
316 | { |
317 | _ASSERTE(rank != 0); |
318 | int* lowerBounds = (int*) _alloca(sizeof(int)*2*rank); |
319 | int* sizes = &lowerBounds[rank]; |
320 | memset(lowerBounds, 0, sizeof(int)*2*rank); |
321 | |
322 | unsigned numSizes = CorSigUncompressData(typePtr); |
323 | _ASSERTE(numSizes <= rank); |
324 | unsigned int i; |
325 | for(i =0; i < numSizes; i++) |
326 | sizes[i] = CorSigUncompressData(typePtr); |
327 | |
328 | unsigned numLowBounds = CorSigUncompressData(typePtr); |
329 | _ASSERTE(numLowBounds <= rank); |
330 | for(i = 0; i < numLowBounds; i++) |
331 | lowerBounds[i] = CorSigUncompressData(typePtr); |
332 | |
333 | appendStrW(out, W("[" )); |
334 | for(i = 0; i < rank; i++) |
335 | { |
336 | if (sizes[i] != 0 && lowerBounds[i] != 0) |
337 | { |
338 | if (lowerBounds[i] == 0) |
339 | appendStrNumW(out, sizes[i]); |
340 | else |
341 | { |
342 | appendStrNumW(out, lowerBounds[i]); |
343 | appendStrW(out, W("..." )); |
344 | if (sizes[i] != 0) |
345 | appendStrNumW(out, lowerBounds[i] + sizes[i] + 1); |
346 | } |
347 | } |
348 | if (i < rank-1) |
349 | appendStrW(out, W("," )); |
350 | } |
351 | appendStrW(out, W("]" )); |
352 | } |
353 | } |
354 | break; |
355 | |
356 | case ELEMENT_TYPE_MVAR: |
357 | appendStrW(out, W("!!" )); |
358 | appendStrNumW(out, CorSigUncompressData(typePtr)); |
359 | break; |
360 | |
361 | case ELEMENT_TYPE_VAR: |
362 | appendStrW(out, W("!" )); |
363 | appendStrNumW(out, CorSigUncompressData(typePtr)); |
364 | break; |
365 | |
366 | case ELEMENT_TYPE_GENERICINST: |
367 | { |
368 | typePtr = PrettyPrintType(typePtr, (typeEnd - typePtr), out, pIMDI); |
369 | unsigned ntypars = CorSigUncompressData(typePtr); |
370 | appendStrW(out, W("<" )); |
371 | for (unsigned i = 0; i < ntypars; i++) |
372 | { |
373 | if (i > 0) |
374 | appendStrW(out, W("," )); |
375 | typePtr = PrettyPrintType(typePtr, (typeEnd - typePtr), out, pIMDI); |
376 | } |
377 | appendStrW(out, W(">" )); |
378 | } |
379 | break; |
380 | |
381 | case ELEMENT_TYPE_MODULE_ZAPSIG: |
382 | appendStrW(out, W("[module#" )); |
383 | appendStrNumW(out, CorSigUncompressData(typePtr)); |
384 | appendStrW(out, W(", token#" )); |
385 | typePtr += CorSigUncompressToken(typePtr, &tk); |
386 | appendStrHexW(out, tk); |
387 | appendStrW(out, W("]" )); |
388 | break; |
389 | |
390 | case ELEMENT_TYPE_FNPTR: |
391 | appendStrW(out, W("fnptr " )); |
392 | PrettyPrintSigWorker(typePtr, (typeEnd - typePtr), W("" ), out, pIMDI); |
393 | break; |
394 | |
395 | case ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG: |
396 | case ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG: |
397 | appendStrW(out, W("native " )); |
398 | typePtr = PrettyPrintType(typePtr, (typeEnd - typePtr), out, pIMDI); |
399 | break; |
400 | |
401 | // Modifiers or depedant types |
402 | case ELEMENT_TYPE_PINNED: |
403 | str = W(" pinned" ); |
404 | goto MODIFIER; |
405 | |
406 | case ELEMENT_TYPE_PTR: |
407 | str = W("*" ); |
408 | goto MODIFIER; |
409 | |
410 | case ELEMENT_TYPE_BYREF: |
411 | str = W("&" ); |
412 | goto MODIFIER; |
413 | |
414 | MODIFIER: |
415 | typePtr = PrettyPrintType(typePtr, (typeEnd - typePtr), out, pIMDI); |
416 | appendStrW(out, str); |
417 | break; |
418 | |
419 | default: |
420 | case ELEMENT_TYPE_SENTINEL: |
421 | case ELEMENT_TYPE_END: |
422 | _ASSERTE(!"Unknown Type" ); |
423 | return(typePtr); |
424 | break; |
425 | } |
426 | return(typePtr); |
427 | } // static PCCOR_SIGNATURE PrettyPrintType() |
428 | |
429 | //***************************************************************************** |
430 | // Converts a com signature to a text signature. |
431 | // |
432 | // Note that this function DOES NULL terminate the result signature string. |
433 | //***************************************************************************** |
434 | LPCWSTR PrettyPrintSigLegacy( |
435 | PCCOR_SIGNATURE typePtr, // type to convert, |
436 | unsigned typeLen, // length of type |
437 | const WCHAR * name, // can be "", the name of the method for this sig |
438 | CQuickBytes * out, // where to put the pretty printed string |
439 | IMetaDataImport * pIMDI) // Import api to use. |
440 | { |
441 | return PrettyPrintSigWorker(typePtr, typeLen, name, out, pIMDI); |
442 | } // LPCWSTR PrettyPrintSigLegacy() |
443 | |
444 | LPCWSTR PrettyPrintSigWorker( |
445 | PCCOR_SIGNATURE & typePtr, // type to convert, |
446 | size_t typeLen, // length of type |
447 | const WCHAR * name, // can be "", the name of the method for this sig |
448 | CQuickBytes * out, // where to put the pretty printed string |
449 | IMetaDataImport * pIMDI) // Import api to use. |
450 | { |
451 | out->Shrink(0); |
452 | unsigned numTyArgs = 0; |
453 | unsigned numArgs; |
454 | PCCOR_SIGNATURE typeEnd = typePtr + typeLen; // End of the signature. |
455 | |
456 | if (name != 0) // 0 means a local var sig |
457 | { |
458 | // get the calling convention out |
459 | unsigned callConv = CorSigUncompressData(typePtr); |
460 | |
461 | if (isCallConv(callConv, IMAGE_CEE_CS_CALLCONV_FIELD)) |
462 | { |
463 | PrettyPrintType(typePtr, (typeEnd - typePtr), out, pIMDI); |
464 | if (name != 0 && *name != 0) |
465 | { |
466 | appendStrW(out, W(" " )); |
467 | appendStrW(out, name); |
468 | } |
469 | return(asStringW(out)); |
470 | } |
471 | |
472 | if (callConv & IMAGE_CEE_CS_CALLCONV_HASTHIS) |
473 | appendStrW(out, W("instance " )); |
474 | |
475 | if (callConv & IMAGE_CEE_CS_CALLCONV_GENERIC) |
476 | { |
477 | appendStrW(out, W("generic " )); |
478 | numTyArgs = CorSigUncompressData(typePtr); |
479 | } |
480 | |
481 | static const WCHAR * const callConvNames[IMAGE_CEE_CS_CALLCONV_MAX] = |
482 | { |
483 | W("" ), |
484 | W("unmanaged cdecl " ), |
485 | W("unmanaged stdcall " ), |
486 | W("unmanaged thiscall " ), |
487 | W("unmanaged fastcall " ), |
488 | W("vararg " ), |
489 | W("<error> " ), |
490 | W("<error> " ), |
491 | W("" ), |
492 | W("" ), |
493 | W("" ), |
494 | W("native vararg " ) |
495 | }; |
496 | |
497 | if ((callConv & IMAGE_CEE_CS_CALLCONV_MASK) < IMAGE_CEE_CS_CALLCONV_MAX) |
498 | { |
499 | appendStrW(out, callConvNames[callConv & IMAGE_CEE_CS_CALLCONV_MASK]); |
500 | } |
501 | |
502 | |
503 | numArgs = CorSigUncompressData(typePtr); |
504 | // do return type |
505 | typePtr = PrettyPrintType(typePtr, (typeEnd - typePtr), out, pIMDI); |
506 | |
507 | } |
508 | else |
509 | { |
510 | numArgs = CorSigUncompressData(typePtr); |
511 | } |
512 | |
513 | if (name != 0 && *name != 0) |
514 | { |
515 | appendStrW(out, W(" " )); |
516 | appendStrW(out, name); |
517 | } |
518 | appendStrW(out, W("(" )); |
519 | |
520 | bool needComma = false; |
521 | |
522 | while (numArgs) |
523 | { |
524 | if (typePtr >= typeEnd) |
525 | break; |
526 | |
527 | if (*typePtr == ELEMENT_TYPE_SENTINEL) |
528 | { |
529 | if (needComma) |
530 | appendStrW(out, W("," )); |
531 | appendStrW(out, W("..." )); |
532 | typePtr++; |
533 | } |
534 | else |
535 | { |
536 | if (numArgs <= 0) |
537 | break; |
538 | if (needComma) |
539 | appendStrW(out, W("," )); |
540 | typePtr = PrettyPrintType(typePtr, (typeEnd - typePtr), out, pIMDI); |
541 | --numArgs; |
542 | } |
543 | needComma = true; |
544 | } |
545 | appendStrW(out, W(")" )); |
546 | return (asStringW(out)); |
547 | } // LPCWSTR PrettyPrintSigWorker() |
548 | |
549 | |
550 | // Internal implementation of PrettyPrintSig(). |
551 | |
552 | HRESULT PrettyPrintSigWorkerInternal( |
553 | PCCOR_SIGNATURE & typePtr, // type to convert, |
554 | size_t typeLen, // length of type |
555 | const CHAR * name, // can be "", the name of the method for this sig |
556 | CQuickBytes * out, // where to put the pretty printed string |
557 | IMDInternalImport * pIMDI); // Import api to use. |
558 | |
559 | static HRESULT PrettyPrintClass( |
560 | PCCOR_SIGNATURE &typePtr, // type to convert |
561 | PCCOR_SIGNATURE typeEnd, // end of the signature. |
562 | CQuickBytes *out, // where to put the pretty printed string |
563 | IMDInternalImport *pIMDI); // ptr to IMDInternal class with ComSig |
564 | |
565 | |
566 | #ifdef _PREFAST_ |
567 | #pragma warning(push) |
568 | #pragma warning(disable:21000) // Suppress PREFast warning about overly large function |
569 | #endif |
570 | //***************************************************************************** |
571 | //***************************************************************************** |
572 | // pretty prints 'type' to the buffer 'out' returns a pointer to the next type, |
573 | // or 0 on a format failure |
574 | |
575 | __checkReturn |
576 | static HRESULT PrettyPrintTypeA( |
577 | PCCOR_SIGNATURE &typePtr, // type to convert, |
578 | size_t typeLen, // Maximum length of the type. |
579 | CQuickBytes *out, // where to put the pretty printed string |
580 | IMDInternalImport *pIMDI) // ptr to IMDInternal class with ComSig |
581 | { |
582 | CONTRACTL |
583 | { |
584 | NOTHROW; |
585 | INJECT_FAULT(return E_OUTOFMEMORY;); |
586 | } |
587 | CONTRACTL_END |
588 | |
589 | mdToken tk; // A type's token. |
590 | const CHAR *str; // Temporary string. |
591 | HRESULT hr; // A result. |
592 | |
593 | PCCOR_SIGNATURE typeEnd = typePtr + typeLen; // End of the signature. |
594 | unsigned __int8 elt = *typePtr++; |
595 | |
596 | switch(elt) { |
597 | case ELEMENT_TYPE_VOID: |
598 | str = "void" ; |
599 | goto APPEND; |
600 | |
601 | case ELEMENT_TYPE_BOOLEAN: |
602 | str = "bool" ; |
603 | goto APPEND; |
604 | |
605 | case ELEMENT_TYPE_CHAR: |
606 | str = "wchar" ; |
607 | goto APPEND; |
608 | |
609 | case ELEMENT_TYPE_I1: |
610 | str = "int8" ; |
611 | goto APPEND; |
612 | |
613 | case ELEMENT_TYPE_U1: |
614 | str = "unsigned int8" ; |
615 | goto APPEND; |
616 | |
617 | case ELEMENT_TYPE_I2: |
618 | str = "int16" ; |
619 | goto APPEND; |
620 | |
621 | case ELEMENT_TYPE_U2: |
622 | str = "unsigned int16" ; |
623 | goto APPEND; |
624 | |
625 | case ELEMENT_TYPE_I4: |
626 | str = "int32" ; |
627 | goto APPEND; |
628 | |
629 | case ELEMENT_TYPE_U4: |
630 | str = "unsigned int32" ; |
631 | goto APPEND; |
632 | |
633 | case ELEMENT_TYPE_I8: |
634 | str = "int64" ; |
635 | goto APPEND; |
636 | |
637 | case ELEMENT_TYPE_U8: |
638 | str = "unsigned int64" ; |
639 | goto APPEND; |
640 | |
641 | case ELEMENT_TYPE_R4: |
642 | str = "float32" ; |
643 | goto APPEND; |
644 | |
645 | case ELEMENT_TYPE_R8: |
646 | str = "float64" ; |
647 | goto APPEND; |
648 | |
649 | case ELEMENT_TYPE_U: |
650 | str = "unsigned int" ; |
651 | goto APPEND; |
652 | |
653 | case ELEMENT_TYPE_I: |
654 | str = "int" ; |
655 | goto APPEND; |
656 | |
657 | case ELEMENT_TYPE_OBJECT: |
658 | str = "class System.Object" ; |
659 | goto APPEND; |
660 | |
661 | case ELEMENT_TYPE_STRING: |
662 | str = "class System.String" ; |
663 | goto APPEND; |
664 | |
665 | case ELEMENT_TYPE_CANON_ZAPSIG: |
666 | str = "class System.__Canon" ; |
667 | goto APPEND; |
668 | |
669 | case ELEMENT_TYPE_TYPEDBYREF: |
670 | str = "refany" ; |
671 | goto APPEND; |
672 | |
673 | APPEND: |
674 | IfFailGo(appendStrA(out, str)); |
675 | break; |
676 | |
677 | case ELEMENT_TYPE_INTERNAL: |
678 | void* pMT; |
679 | pMT = *((void* UNALIGNED *)typePtr); |
680 | typePtr += sizeof(void*); |
681 | CHAR tempBuffer[64]; |
682 | sprintf_s(tempBuffer, 64, "pMT: %p" , pMT); |
683 | IfFailGo(appendStrA(out, tempBuffer)); |
684 | break; |
685 | |
686 | case ELEMENT_TYPE_VALUETYPE: |
687 | str = "value class " ; |
688 | goto DO_CLASS; |
689 | |
690 | case ELEMENT_TYPE_CLASS: |
691 | str = "class " ; |
692 | goto DO_CLASS; |
693 | |
694 | DO_CLASS: |
695 | IfFailGo(appendStrA(out, str)); |
696 | IfFailGo(PrettyPrintClass(typePtr, typeEnd, out, pIMDI)); |
697 | break; |
698 | |
699 | case ELEMENT_TYPE_CMOD_REQD: |
700 | str = "required_modifier " ; |
701 | goto CMOD; |
702 | |
703 | case ELEMENT_TYPE_CMOD_OPT: |
704 | str = "optional_modifier " ; |
705 | goto CMOD; |
706 | |
707 | CMOD: |
708 | IfFailGo(appendStrA(out, str)); |
709 | IfFailGo(PrettyPrintClass(typePtr, typeEnd, out, pIMDI)); |
710 | IfFailGo(appendStrA(out, " " )); |
711 | IfFailGo(PrettyPrintTypeA(typePtr, (typeEnd - typePtr), out, pIMDI)); |
712 | break; |
713 | |
714 | case ELEMENT_TYPE_SZARRAY: |
715 | IfFailGo(PrettyPrintTypeA(typePtr, (typeEnd - typePtr), out, pIMDI)); |
716 | IfFailGo(appendStrA(out, "[]" )); |
717 | break; |
718 | |
719 | case ELEMENT_TYPE_ARRAY: |
720 | { |
721 | IfFailGo(PrettyPrintTypeA(typePtr, (typeEnd - typePtr), out, pIMDI)); |
722 | unsigned rank = CorSigUncompressData(typePtr); |
723 | PREFIX_ASSUME(rank <= 0xffffff); |
724 | // <TODO>TODO what is the syntax for the rank 0 case? </TODO> |
725 | if (rank == 0) |
726 | { |
727 | IfFailGo(appendStrA(out, "[??]" )); |
728 | } |
729 | else |
730 | { |
731 | _ASSERTE(rank != 0); |
732 | int* lowerBounds = (int*) _alloca(sizeof(int)*2*rank); |
733 | int* sizes = &lowerBounds[rank]; |
734 | memset(lowerBounds, 0, sizeof(int)*2*rank); |
735 | |
736 | unsigned numSizes = CorSigUncompressData(typePtr); |
737 | _ASSERTE(numSizes <= rank); |
738 | unsigned int i; |
739 | for(i =0; i < numSizes; i++) |
740 | sizes[i] = CorSigUncompressData(typePtr); |
741 | |
742 | unsigned numLowBounds = CorSigUncompressData(typePtr); |
743 | _ASSERTE(numLowBounds <= rank); |
744 | for(i = 0; i < numLowBounds; i++) |
745 | lowerBounds[i] = CorSigUncompressData(typePtr); |
746 | |
747 | IfFailGo(appendStrA(out, "[" )); |
748 | for(i = 0; i < rank; i++) |
749 | { |
750 | if (sizes[i] != 0 && lowerBounds[i] != 0) |
751 | { |
752 | if (lowerBounds[i] == 0) |
753 | appendStrNumA(out, sizes[i]); |
754 | else |
755 | { |
756 | appendStrNumA(out, lowerBounds[i]); |
757 | IfFailGo(appendStrA(out, "..." )); |
758 | if (sizes[i] != 0) |
759 | appendStrNumA(out, lowerBounds[i] + sizes[i] + 1); |
760 | } |
761 | } |
762 | if (i < rank-1) |
763 | IfFailGo(appendStrA(out, "," )); |
764 | } |
765 | IfFailGo(appendStrA(out, "]" )); |
766 | } |
767 | } |
768 | break; |
769 | |
770 | case ELEMENT_TYPE_MVAR: |
771 | IfFailGo(appendStrA(out, "!!" )); |
772 | appendStrNumA(out, CorSigUncompressData(typePtr)); |
773 | break; |
774 | |
775 | case ELEMENT_TYPE_VAR: |
776 | IfFailGo(appendStrA(out, "!" )); |
777 | appendStrNumA(out, CorSigUncompressData(typePtr)); |
778 | break; |
779 | |
780 | case ELEMENT_TYPE_GENERICINST: |
781 | { |
782 | IfFailGo(PrettyPrintTypeA(typePtr, (typeEnd - typePtr), out, pIMDI)); |
783 | unsigned ntypars = CorSigUncompressData(typePtr); |
784 | IfFailGo(appendStrA(out, "<" )); |
785 | for (unsigned i = 0; i < ntypars; i++) |
786 | { |
787 | if (i > 0) |
788 | IfFailGo(appendStrA(out, "," )); |
789 | IfFailGo(PrettyPrintTypeA(typePtr, (typeEnd - typePtr), out, pIMDI)); |
790 | } |
791 | IfFailGo(appendStrA(out, ">" )); |
792 | } |
793 | break; |
794 | |
795 | case ELEMENT_TYPE_MODULE_ZAPSIG: |
796 | IfFailGo(appendStrA(out, "[module#" )); |
797 | appendStrNumA(out, CorSigUncompressData(typePtr)); |
798 | IfFailGo(appendStrA(out, ", token#" )); |
799 | typePtr += CorSigUncompressToken(typePtr, &tk); |
800 | IfFailGo(appendStrHexA(out, tk)); |
801 | IfFailGo(appendStrA(out, "]" )); |
802 | break; |
803 | |
804 | case ELEMENT_TYPE_FNPTR: |
805 | IfFailGo(appendStrA(out, "fnptr " )); |
806 | IfFailGo(PrettyPrintSigWorkerInternal(typePtr, (typeEnd - typePtr), "" , out,pIMDI)); |
807 | break; |
808 | |
809 | case ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG: |
810 | case ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG: |
811 | IfFailGo(appendStrA(out, "native " )); |
812 | IfFailGo(PrettyPrintTypeA(typePtr, (typeEnd - typePtr), out, pIMDI)); |
813 | break; |
814 | |
815 | // Modifiers or dependent types |
816 | case ELEMENT_TYPE_PINNED: |
817 | str = " pinned" ; |
818 | goto MODIFIER; |
819 | |
820 | case ELEMENT_TYPE_PTR: |
821 | str = "*" ; |
822 | goto MODIFIER; |
823 | |
824 | case ELEMENT_TYPE_BYREF: |
825 | str = "&" ; |
826 | goto MODIFIER; |
827 | |
828 | MODIFIER: |
829 | IfFailGo(PrettyPrintTypeA(typePtr, (typeEnd - typePtr), out, pIMDI)); |
830 | IfFailGo(appendStrA(out, str)); |
831 | break; |
832 | |
833 | default: |
834 | case ELEMENT_TYPE_SENTINEL: |
835 | case ELEMENT_TYPE_END: |
836 | hr = E_INVALIDARG; |
837 | break; |
838 | } |
839 | ErrExit: |
840 | return hr; |
841 | } // PrettyPrintTypeA |
842 | #ifdef _PREFAST_ |
843 | #pragma warning(pop) |
844 | #endif |
845 | |
846 | // pretty prints the class 'type' to the buffer 'out' |
847 | static HRESULT PrettyPrintClass( |
848 | PCCOR_SIGNATURE &typePtr, // type to convert |
849 | PCCOR_SIGNATURE typeEnd, // end of the signature. |
850 | CQuickBytes *out, // where to put the pretty printed string |
851 | IMDInternalImport *pIMDI) // ptr to IMDInternal class with ComSig |
852 | { |
853 | CONTRACTL |
854 | { |
855 | NOTHROW; |
856 | INJECT_FAULT(return E_OUTOFMEMORY;); |
857 | } |
858 | CONTRACTL_END |
859 | |
860 | mdToken tk; |
861 | const CHAR *str; // type's token. |
862 | LPCUTF8 pNS; // type's namespace. |
863 | LPCUTF8 pN; // type's name. |
864 | HRESULT hr; // result |
865 | |
866 | IfFailGo(CorSigUncompressToken_EndPtr(typePtr, typeEnd, &tk)); |
867 | str = "<UNKNOWN>" ; |
868 | |
869 | if (TypeFromToken(tk) == mdtTypeSpec) |
870 | { |
871 | ULONG cSig; |
872 | PCCOR_SIGNATURE sig; |
873 | IfFailGo(pIMDI->GetSigFromToken(tk, &cSig, &sig)); |
874 | IfFailGo(PrettyPrintTypeA(sig, cSig, out, pIMDI)); |
875 | } |
876 | else |
877 | { |
878 | if (TypeFromToken(tk) == mdtTypeRef) |
879 | { |
880 | //<TODO>@consider: assembly name?</TODO> |
881 | if (FAILED(pIMDI->GetNameOfTypeRef(tk, &pNS, &pN))) |
882 | { |
883 | pNS = pN = "Invalid TypeRef record" ; |
884 | } |
885 | } |
886 | else |
887 | { |
888 | _ASSERTE(TypeFromToken(tk) == mdtTypeDef); |
889 | if (FAILED(pIMDI->GetNameOfTypeDef(tk, &pN, &pNS))) |
890 | { |
891 | pNS = pN = "Invalid TypeDef record" ; |
892 | } |
893 | } |
894 | |
895 | if (pNS && *pNS) |
896 | { |
897 | IfFailGo(appendStrA(out, pNS)); |
898 | IfFailGo(appendStrA(out, NAMESPACE_SEPARATOR_STR)); |
899 | } |
900 | IfFailGo(appendStrA(out, pN)); |
901 | } |
902 | return S_OK; |
903 | |
904 | ErrExit: |
905 | return hr; |
906 | } // static HRESULT PrettyPrintClass() |
907 | |
908 | //***************************************************************************** |
909 | // Converts a com signature to a text signature. |
910 | // |
911 | // Note that this function DOES NULL terminate the result signature string. |
912 | //***************************************************************************** |
913 | HRESULT PrettyPrintSigInternalLegacy( |
914 | PCCOR_SIGNATURE typePtr, // type to convert, |
915 | unsigned typeLen, // length of type |
916 | const CHAR * name, // can be "", the name of the method for this sig |
917 | CQuickBytes * out, // where to put the pretty printed string |
918 | IMDInternalImport * pIMDI) // Import api to use. |
919 | { |
920 | CONTRACTL |
921 | { |
922 | NOTHROW; |
923 | INJECT_FAULT(return E_OUTOFMEMORY;); |
924 | } |
925 | CONTRACTL_END |
926 | |
927 | return PrettyPrintSigWorkerInternal(typePtr, typeLen, name, out, pIMDI); |
928 | } // HRESULT PrettyPrintSigInternalLegacy() |
929 | |
930 | HRESULT PrettyPrintSigWorkerInternal( |
931 | PCCOR_SIGNATURE & typePtr, // type to convert, |
932 | size_t typeLen, // length of type |
933 | const CHAR * name, // can be "", the name of the method for this sig |
934 | CQuickBytes * out, // where to put the pretty printed string |
935 | IMDInternalImport * pIMDI) // Import api to use. |
936 | { |
937 | CONTRACTL |
938 | { |
939 | NOTHROW; |
940 | INJECT_FAULT(return E_OUTOFMEMORY;); |
941 | } |
942 | CONTRACTL_END |
943 | |
944 | HRESULT hr = S_OK; |
945 | unsigned numArgs; // Count of arugments to function, or count of local vars. |
946 | unsigned numTyArgs = 0; |
947 | PCCOR_SIGNATURE typeEnd = typePtr + typeLen; |
948 | bool needComma = false; |
949 | |
950 | out->Shrink(0); |
951 | |
952 | if (name != 0) // 0 means a local var sig |
953 | { |
954 | // get the calling convention out |
955 | unsigned callConv = CorSigUncompressData(typePtr); |
956 | |
957 | if (isCallConv(callConv, IMAGE_CEE_CS_CALLCONV_FIELD)) |
958 | { |
959 | IfFailGo(PrettyPrintTypeA(typePtr, (typeEnd - typePtr), out, pIMDI)); |
960 | if (name != 0 && *name != 0) |
961 | |
962 | { |
963 | IfFailGo(appendStrA(out, " " )); |
964 | IfFailGo(appendStrA(out, name)); |
965 | } |
966 | goto ErrExit; |
967 | } |
968 | |
969 | if (callConv & IMAGE_CEE_CS_CALLCONV_HASTHIS) |
970 | IfFailGo(appendStrA(out, "instance " )); |
971 | |
972 | if (callConv & IMAGE_CEE_CS_CALLCONV_GENERIC) |
973 | { |
974 | IfFailGo(appendStrA(out, "generic " )); |
975 | numTyArgs = CorSigUncompressData(typePtr); |
976 | } |
977 | |
978 | static const CHAR* const callConvNames[IMAGE_CEE_CS_CALLCONV_MAX] = |
979 | { |
980 | "" , |
981 | "unmanaged cdecl " , |
982 | "unmanaged stdcall " , |
983 | "unmanaged thiscall " , |
984 | "unmanaged fastcall " , |
985 | "vararg " , |
986 | "<error> " , |
987 | "<error> " , |
988 | "" , |
989 | "" , |
990 | "" , |
991 | "native vararg " |
992 | }; |
993 | |
994 | if ((callConv & IMAGE_CEE_CS_CALLCONV_MASK) < IMAGE_CEE_CS_CALLCONV_MAX) |
995 | { |
996 | appendStrA(out, callConvNames[callConv & IMAGE_CEE_CS_CALLCONV_MASK]); |
997 | } |
998 | |
999 | numArgs = CorSigUncompressData(typePtr); |
1000 | // do return type |
1001 | IfFailGo(PrettyPrintTypeA(typePtr, (typeEnd - typePtr), out, pIMDI)); |
1002 | } |
1003 | else |
1004 | { |
1005 | numArgs = CorSigUncompressData(typePtr); |
1006 | } |
1007 | |
1008 | if (name != 0 && *name != 0) |
1009 | { |
1010 | IfFailGo(appendStrA(out, " " )); |
1011 | IfFailGo(appendStrA(out, name)); |
1012 | } |
1013 | IfFailGo(appendStrA(out, "(" )); |
1014 | |
1015 | while (numArgs) |
1016 | { |
1017 | if (typePtr >= typeEnd) |
1018 | break; |
1019 | |
1020 | if (*typePtr == ELEMENT_TYPE_SENTINEL) |
1021 | { |
1022 | if (needComma) |
1023 | IfFailGo(appendStrA(out, "," )); |
1024 | IfFailGo(appendStrA(out, "..." )); |
1025 | ++typePtr; |
1026 | } |
1027 | else |
1028 | { |
1029 | if (needComma) |
1030 | IfFailGo(appendStrA(out, "," )); |
1031 | IfFailGo(PrettyPrintTypeA(typePtr, (typeEnd - typePtr), out, pIMDI)); |
1032 | --numArgs; |
1033 | } |
1034 | needComma = true; |
1035 | } |
1036 | IfFailGo(appendStrA(out, ")" )); |
1037 | if (asStringA(out) == 0) |
1038 | IfFailGo(E_OUTOFMEMORY); |
1039 | |
1040 | ErrExit: |
1041 | return hr; |
1042 | } // HRESULT PrettyPrintSigWorkerInternal() |
1043 | |