VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/asn1/asn1-dump.cpp@ 78365

Last change on this file since 78365 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.6 KB
Line 
1/* $Id: asn1-dump.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * IPRT - ASN.1, Structure Dumper.
4 */
5
6/*
7 * Copyright (C) 2006-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include "internal/iprt.h"
32#include <iprt/asn1.h>
33
34#include <iprt/errcore.h>
35#include <iprt/log.h>
36#ifdef IN_RING3
37# include <iprt/stream.h>
38#endif
39#include <iprt/string.h>
40
41#include <iprt/formats/asn1.h>
42
43
44/*********************************************************************************************************************************
45* Structures and Typedefs *
46*********************************************************************************************************************************/
47/**
48 * Dump data structure.
49 */
50typedef struct RTASN1DUMPDATA
51{
52 /** RTASN1DUMP_F_XXX. */
53 uint32_t fFlags;
54 /** The printfv like output function. */
55 PFNRTDUMPPRINTFV pfnPrintfV;
56 /** PrintfV user argument. */
57 void *pvUser;
58} RTASN1DUMPDATA;
59/** Pointer to a dump data structure. */
60typedef RTASN1DUMPDATA *PRTASN1DUMPDATA;
61
62
63#ifndef IN_SUP_HARDENED_R3
64
65/*
66 * Since we're the only user of OIDs, this stuff lives here.
67 * Should that ever change, this code needs to move elsewhere and get it's own public API.
68 */
69# include "oiddb.h"
70
71
72/**
73 * Searches a range in the big table for a key.
74 *
75 * @returns Pointer to the matching entry. NULL if not found.
76 * @param iEntry The start of the range.
77 * @param cEntries The number of entries in the range.
78 * @param uKey The key to find.
79 */
80DECLINLINE(PCRTOIDENTRYBIG) rtOidDbLookupBig(uint32_t iEntry, uint32_t cEntries, uint32_t uKey)
81{
82 /* Not worth doing binary search here, too few entries. */
83 while (cEntries-- > 0)
84 {
85 uint32_t const uThisKey = g_aBigOidTable[iEntry].uKey;
86 if (uThisKey >= uKey)
87 {
88 if (uThisKey == uKey)
89 return &g_aBigOidTable[iEntry];
90 break;
91 }
92 iEntry++;
93 }
94 return NULL;
95}
96
97
98/**
99 * Searches a range in the small table for a key.
100 *
101 * @returns Pointer to the matching entry. NULL if not found.
102 * @param iEntry The start of the range.
103 * @param cEntries The number of entries in the range.
104 * @param uKey The key to find.
105 */
106DECLINLINE(PCRTOIDENTRYSMALL) rtOidDbLookupSmall(uint32_t iEntry, uint32_t cEntries, uint32_t uKey)
107{
108 if (cEntries < 6)
109 {
110 /* Linear search for small ranges. */
111 while (cEntries-- > 0)
112 {
113 uint32_t const uThisKey = g_aSmallOidTable[iEntry].uKey;
114 if (uThisKey >= uKey)
115 {
116 if (uThisKey == uKey)
117 return &g_aSmallOidTable[iEntry];
118 break;
119 }
120 iEntry++;
121 }
122 }
123 else
124 {
125 /* Binary search. */
126 uint32_t iEnd = iEntry + cEntries;
127 for (;;)
128 {
129 uint32_t const i = iEntry + (iEnd - iEntry) / 2;
130 uint32_t const uThisKey = g_aSmallOidTable[i].uKey;
131 if (uThisKey < uKey)
132 {
133 iEntry = i + 1;
134 if (iEntry >= iEnd)
135 break;
136 }
137 else if (uThisKey > uKey)
138 {
139 iEnd = i;
140 if (iEnd <= iEntry)
141 break;
142 }
143 else
144 return &g_aSmallOidTable[i];
145 }
146 }
147 return NULL;
148}
149
150
151/**
152 * Queries the name for an object identifier.
153 *
154 * @returns IPRT status code (VINF_SUCCESS, VERR_NOT_FOUND,
155 * VERR_BUFFER_OVERFLOW)
156 * @param pauComponents The components making up the object ID.
157 * @param cComponents The number of components.
158 * @param pszDst Where to store the name if found.
159 * @param cbDst The size of the destination buffer.
160 */
161static int rtOidDbQueryObjIdName(uint32_t const *pauComponents, uint8_t cComponents, char *pszDst, size_t cbDst)
162{
163 int rc = VERR_NOT_FOUND;
164 if (cComponents > 0)
165 {
166 /*
167 * The top level is always in the small table as the range is restricted to 0,1,2.
168 */
169 bool fBigTable = false;
170 uint32_t cEntries = RT_MIN(RT_ELEMENTS(g_aSmallOidTable), 3);
171 uint32_t iEntry = 0;
172 for (;;)
173 {
174 uint32_t const uKey = *pauComponents++;
175 if (!fBigTable)
176 {
177 PCRTOIDENTRYSMALL pSmallHit = rtOidDbLookupSmall(iEntry, cEntries, uKey);
178 if (pSmallHit)
179 {
180 if (--cComponents == 0)
181 {
182 if (RTBldProgStrTabQueryString(&g_OidDbStrTab, pSmallHit->offString,
183 pSmallHit->cchString, pszDst, cbDst) >= 0)
184 return VINF_SUCCESS;
185 rc = VERR_BUFFER_OVERFLOW;
186 break;
187 }
188 cEntries = pSmallHit->cChildren;
189 if (cEntries)
190 {
191 iEntry = pSmallHit->idxChildren;
192 fBigTable = pSmallHit->fBigTable;
193 continue;
194 }
195 }
196 }
197 else
198 {
199 PCRTOIDENTRYBIG pBigHit = rtOidDbLookupBig(iEntry, cEntries, uKey);
200 if (pBigHit)
201 {
202 if (--cComponents == 0)
203 {
204 if (RTBldProgStrTabQueryString(&g_OidDbStrTab, pBigHit->offString,
205 pBigHit->cchString, pszDst, cbDst) >= 0)
206 return VINF_SUCCESS;
207 rc = VERR_BUFFER_OVERFLOW;
208 break;
209 }
210 cEntries = pBigHit->cChildren;
211 if (cEntries)
212 {
213 iEntry = pBigHit->idxChildren;
214 fBigTable = pBigHit->fBigTable;
215 continue;
216 }
217 }
218 }
219 break;
220 }
221 }
222
223 return rc;
224}
225
226
227/**
228 * Queries the name for an object identifier.
229 *
230 * This API is simple and more or less requires a
231 *
232 * @returns IPRT status code.
233 * @retval VINF_SUCCESS on success.
234 * @retval VERR_NOT_FOUND if not found.
235 * @retval VERR_BUFFER_OVERFLOW if more buffer space is required.
236 *
237 * @param pauComponents The components making up the object ID.
238 * @param cComponents The number of components.
239 * @param pszDst Where to store the name if found.
240 * @param cbDst The size of the destination buffer.
241 */
242RTDECL(int) RTAsn1QueryObjIdName(PCRTASN1OBJID pObjId, char *pszDst, size_t cbDst)
243{
244 return rtOidDbQueryObjIdName(pObjId->pauComponents, pObjId->cComponents, pszDst, cbDst);
245}
246
247#endif /* !IN_SUP_HARDENED_R3 */
248
249
250
251/**
252 * Wrapper around FNRTASN1DUMPPRINTFV.
253 *
254 * @param pData The dump data structure.
255 * @param pszFormat Format string.
256 * @param ... Format arguments.
257 */
258static void rtAsn1DumpPrintf(PRTASN1DUMPDATA pData, const char *pszFormat, ...)
259{
260 va_list va;
261 va_start(va, pszFormat);
262 pData->pfnPrintfV(pData->pvUser, pszFormat, va);
263 va_end(va);
264}
265
266
267/**
268 * Prints indentation.
269 *
270 * @param pData The dump data structure.
271 * @param uDepth The indentation depth.
272 */
273static void rtAsn1DumpPrintIdent(PRTASN1DUMPDATA pData, uint32_t uDepth)
274{
275 uint32_t cchLeft = uDepth * 2;
276 while (cchLeft > 0)
277 {
278 static char const s_szSpaces[] = " ";
279 uint32_t cch = RT_MIN(cchLeft, sizeof(s_szSpaces) - 1);
280 rtAsn1DumpPrintf(pData, &s_szSpaces[sizeof(s_szSpaces) - 1 - cch]);
281 cchLeft -= cch;
282 }
283}
284
285
286/**
287 * Dumps UTC TIME and GENERALIZED TIME
288 *
289 * @param pData The dump data structure.
290 * @param pAsn1Core The ASN.1 core object representation.
291 * @param pszType The time type name.
292 */
293static void rtAsn1DumpTime(PRTASN1DUMPDATA pData, PCRTASN1CORE pAsn1Core, const char *pszType)
294{
295 if ((pAsn1Core->fFlags & RTASN1CORE_F_PRIMITE_TAG_STRUCT))
296 {
297 PCRTASN1TIME pTime = (PCRTASN1TIME)pAsn1Core;
298 rtAsn1DumpPrintf(pData, "%s -- %04u-%02u-%02u %02u:%02u:%02.%09Z\n",
299 pszType,
300 pTime->Time.i32Year, pTime->Time.u8Month, pTime->Time.u8MonthDay,
301 pTime->Time.u8Hour, pTime->Time.u8Minute, pTime->Time.u8Second,
302 pTime->Time.u32Nanosecond);
303 }
304 else if (pAsn1Core->cb > 0 && pAsn1Core->cb < 32 && pAsn1Core->uData.pch)
305 rtAsn1DumpPrintf(pData, "%s '%.*s'\n", pszType, (size_t)pAsn1Core->cb, pAsn1Core->uData.pch);
306 else
307 rtAsn1DumpPrintf(pData, "%s -- cb=%u\n", pszType, pAsn1Core->cb);
308}
309
310
311/**
312 * Dumps strings sharing the RTASN1STRING structure.
313 *
314 * @param pData The dump data structure.
315 * @param pAsn1Core The ASN.1 core object representation.
316 * @param pszType The string type name.
317 * @param uDepth The current identation level.
318 */
319static void rtAsn1DumpString(PRTASN1DUMPDATA pData, PCRTASN1CORE pAsn1Core, const char *pszType, uint32_t uDepth)
320{
321 rtAsn1DumpPrintf(pData, "%s", pszType);
322
323 const char *pszPostfix = "'\n";
324 bool fUtf8 = false;
325 const char *pch = pAsn1Core->uData.pch;
326 uint32_t cch = pAsn1Core->cb;
327 PCRTASN1STRING pString = (PCRTASN1STRING)pAsn1Core;
328 if ( (pAsn1Core->fFlags & RTASN1CORE_F_PRIMITE_TAG_STRUCT)
329 && pString->pszUtf8
330 && pString->cchUtf8)
331 {
332 fUtf8 = true;
333 pszPostfix = "' -- utf-8\n";
334 }
335
336 if (cch == 0 || !pch)
337 rtAsn1DumpPrintf(pData, "-- cb=%u\n", pszType, pAsn1Core->cb);
338 else
339 {
340 if (cch >= 48)
341 {
342 rtAsn1DumpPrintf(pData, "\n");
343 rtAsn1DumpPrintIdent(pData, uDepth + 1);
344 }
345 rtAsn1DumpPrintf(pData, " '");
346
347 /** @todo Handle BMP and UNIVERSIAL strings specially. */
348 do
349 {
350 const char *pchStart = pch;
351 while ( cch > 0
352 && (uint8_t)*pch >= 0x20
353 && (!fUtf8 ? (uint8_t)*pch < 0x7f : (uint8_t)*pch != 0x7f)
354 && *pch != '\'')
355 cch--, pch++;
356 if (pchStart != pch)
357 rtAsn1DumpPrintf(pData, "%.*s", pch - pchStart, pchStart);
358
359 while ( cch > 0
360 && ( (uint8_t)*pch < 0x20
361 || (!fUtf8 ? (uint8_t)*pch >= 0x7f : (uint8_t)*pch == 0x7f)
362 || (uint8_t)*pch == '\'') )
363 {
364 rtAsn1DumpPrintf(pData, "\\x%02x", *pch);
365 cch--;
366 pch++;
367 }
368 } while (cch > 0);
369
370 rtAsn1DumpPrintf(pData, pszPostfix);
371 }
372}
373
374
375/**
376 * Dumps the type and value of an universal ASN.1 type.
377 *
378 * @returns True if it opens a child, false if not.
379 * @param pData The dumper data.
380 * @param pAsn1Core The ASN.1 object to dump.
381 * @param uDepth The current depth (for indentation).
382 */
383static bool rtAsn1DumpUniversalTypeAndValue(PRTASN1DUMPDATA pData, PCRTASN1CORE pAsn1Core, uint32_t uDepth)
384{
385 const char *pszValuePrefix = "-- value:";
386 const char *pszDefault = "";
387 if (pAsn1Core->fFlags & RTASN1CORE_F_DEFAULT)
388 {
389 pszValuePrefix = "DEFAULT";
390 pszDefault = "DEFAULT ";
391 }
392
393 bool fOpen = false;
394 switch (pAsn1Core->uRealTag)
395 {
396 case ASN1_TAG_BOOLEAN:
397 if (pAsn1Core->fFlags & RTASN1CORE_F_PRIMITE_TAG_STRUCT)
398 rtAsn1DumpPrintf(pData, "BOOLEAN %s %RTbool\n", pszValuePrefix, ((PCRTASN1BOOLEAN)pAsn1Core)->fValue);
399 else if (pAsn1Core->cb == 1 && pAsn1Core->uData.pu8)
400 rtAsn1DumpPrintf(pData, "BOOLEAN %s %u\n", pszValuePrefix, *pAsn1Core->uData.pu8);
401 else
402 rtAsn1DumpPrintf(pData, "BOOLEAN -- cb=%u\n", pAsn1Core->cb);
403 break;
404
405 case ASN1_TAG_INTEGER:
406 if ((pAsn1Core->fFlags & RTASN1CORE_F_PRIMITE_TAG_STRUCT) && pAsn1Core->cb <= 8)
407 rtAsn1DumpPrintf(pData, "INTEGER %s %llu / %#llx\n", pszValuePrefix,
408 ((PCRTASN1INTEGER)pAsn1Core)->uValue, ((PCRTASN1INTEGER)pAsn1Core)->uValue);
409 else if (pAsn1Core->cb == 0 || pAsn1Core->cb >= 512 || !pAsn1Core->uData.pu8)
410 rtAsn1DumpPrintf(pData, "INTEGER -- cb=%u\n", pAsn1Core->cb);
411 else if (pAsn1Core->cb <= 32)
412 rtAsn1DumpPrintf(pData, "INTEGER %s %.*Rhxs\n", pszValuePrefix, (size_t)pAsn1Core->cb, pAsn1Core->uData.pu8);
413 else
414 rtAsn1DumpPrintf(pData, "INTEGER %s\n%.*Rhxd\n", pszValuePrefix, (size_t)pAsn1Core->cb, pAsn1Core->uData.pu8);
415 break;
416
417 case ASN1_TAG_BIT_STRING:
418 if ((pAsn1Core->fFlags & RTASN1CORE_F_PRIMITE_TAG_STRUCT))
419 {
420 PCRTASN1BITSTRING pBitString = (PCRTASN1BITSTRING)pAsn1Core;
421 rtAsn1DumpPrintf(pData, "BIT STRING %s-- cb=%u cBits=%#x cMaxBits=%#x",
422 pszDefault, pBitString->Asn1Core.cb, pBitString->cBits, pBitString->cMaxBits);
423 if (pBitString->cBits <= 64)
424 rtAsn1DumpPrintf(pData, " value=%#llx\n", RTAsn1BitString_GetAsUInt64(pBitString));
425 else
426 rtAsn1DumpPrintf(pData, "\n");
427 }
428 else
429 rtAsn1DumpPrintf(pData, "BIT STRING %s-- cb=%u\n", pszDefault, pAsn1Core->cb);
430 fOpen = pAsn1Core->pOps != NULL;
431 break;
432
433 case ASN1_TAG_OCTET_STRING:
434 rtAsn1DumpPrintf(pData, "OCTET STRING %s-- cb=%u\n", pszDefault, pAsn1Core->cb);
435 fOpen = pAsn1Core->pOps != NULL;
436 break;
437
438 case ASN1_TAG_NULL:
439 rtAsn1DumpPrintf(pData, "NULL\n");
440 break;
441
442 case ASN1_TAG_OID:
443 if ((pAsn1Core->fFlags & RTASN1CORE_F_PRIMITE_TAG_STRUCT))
444 {
445#ifndef IN_SUP_HARDENED_R3
446 PCRTASN1OBJID pObjId = (PCRTASN1OBJID)pAsn1Core;
447 char szName[64];
448 if (rtOidDbQueryObjIdName(pObjId->pauComponents, pObjId->cComponents, szName, sizeof(szName)) == VINF_SUCCESS)
449 rtAsn1DumpPrintf(pData, "OBJECT IDENTIFIER %s%s ('%s')\n",
450 pszDefault, szName, ((PCRTASN1OBJID)pAsn1Core)->szObjId);
451 else
452#endif
453 rtAsn1DumpPrintf(pData, "OBJECT IDENTIFIER %s'%s'\n", pszDefault, ((PCRTASN1OBJID)pAsn1Core)->szObjId);
454 }
455 else
456 rtAsn1DumpPrintf(pData, "OBJECT IDENTIFIER %s -- cb=%u\n", pszDefault, pAsn1Core->cb);
457 break;
458
459 case ASN1_TAG_OBJECT_DESCRIPTOR:
460 rtAsn1DumpPrintf(pData, "OBJECT DESCRIPTOR -- cb=%u TODO\n", pAsn1Core->cb);
461 break;
462
463 case ASN1_TAG_EXTERNAL:
464 rtAsn1DumpPrintf(pData, "EXTERNAL -- cb=%u TODO\n", pAsn1Core->cb);
465 break;
466
467 case ASN1_TAG_REAL:
468 rtAsn1DumpPrintf(pData, "REAL -- cb=%u TODO\n", pAsn1Core->cb);
469 break;
470
471 case ASN1_TAG_ENUMERATED:
472 rtAsn1DumpPrintf(pData, "ENUMERATED -- cb=%u TODO\n", pAsn1Core->cb);
473 break;
474
475 case ASN1_TAG_EMBEDDED_PDV:
476 rtAsn1DumpPrintf(pData, "EMBEDDED PDV -- cb=%u TODO\n", pAsn1Core->cb);
477 break;
478
479 case ASN1_TAG_UTF8_STRING:
480 rtAsn1DumpString(pData, pAsn1Core, "UTF8 STRING", uDepth);
481 break;
482
483 case ASN1_TAG_RELATIVE_OID:
484 rtAsn1DumpPrintf(pData, "RELATIVE OBJECT IDENTIFIER -- cb=%u TODO\n", pAsn1Core->cb);
485 break;
486
487 case ASN1_TAG_SEQUENCE:
488 rtAsn1DumpPrintf(pData, "SEQUENCE -- cb=%u\n", pAsn1Core->cb);
489 fOpen = true;
490 break;
491 case ASN1_TAG_SET:
492 rtAsn1DumpPrintf(pData, "SET -- cb=%u\n", pAsn1Core->cb);
493 fOpen = true;
494 break;
495
496 case ASN1_TAG_NUMERIC_STRING:
497 rtAsn1DumpString(pData, pAsn1Core, "NUMERIC STRING", uDepth);
498 break;
499
500 case ASN1_TAG_PRINTABLE_STRING:
501 rtAsn1DumpString(pData, pAsn1Core, "PRINTABLE STRING", uDepth);
502 break;
503
504 case ASN1_TAG_T61_STRING:
505 rtAsn1DumpString(pData, pAsn1Core, "T61 STRING", uDepth);
506 break;
507
508 case ASN1_TAG_VIDEOTEX_STRING:
509 rtAsn1DumpString(pData, pAsn1Core, "VIDEOTEX STRING", uDepth);
510 break;
511
512 case ASN1_TAG_IA5_STRING:
513 rtAsn1DumpString(pData, pAsn1Core, "IA5 STRING", uDepth);
514 break;
515
516 case ASN1_TAG_GRAPHIC_STRING:
517 rtAsn1DumpString(pData, pAsn1Core, "GRAPHIC STRING", uDepth);
518 break;
519
520 case ASN1_TAG_VISIBLE_STRING:
521 rtAsn1DumpString(pData, pAsn1Core, "VISIBLE STRING", uDepth);
522 break;
523
524 case ASN1_TAG_GENERAL_STRING:
525 rtAsn1DumpString(pData, pAsn1Core, "GENERAL STRING", uDepth);
526 break;
527
528 case ASN1_TAG_UNIVERSAL_STRING:
529 rtAsn1DumpString(pData, pAsn1Core, "UNIVERSAL STRING", uDepth);
530 break;
531
532 case ASN1_TAG_BMP_STRING:
533 rtAsn1DumpString(pData, pAsn1Core, "BMP STRING", uDepth);
534 break;
535
536 case ASN1_TAG_UTC_TIME:
537 rtAsn1DumpTime(pData, pAsn1Core, "UTC TIME");
538 break;
539
540 case ASN1_TAG_GENERALIZED_TIME:
541 rtAsn1DumpTime(pData, pAsn1Core, "GENERALIZED TIME");
542 break;
543
544 case ASN1_TAG_CHARACTER_STRING:
545 rtAsn1DumpPrintf(pData, "CHARACTER STRING -- cb=%u TODO\n", pAsn1Core->cb);
546 break;
547
548 default:
549 rtAsn1DumpPrintf(pData, "[UNIVERSAL %u]\n", pAsn1Core->uTag);
550 break;
551 }
552 return fOpen;
553}
554
555
556/** @callback_method_impl{FNRTASN1ENUMCALLBACK} */
557static DECLCALLBACK(int) rtAsn1DumpEnumCallback(PRTASN1CORE pAsn1Core, const char *pszName, uint32_t uDepth, void *pvUser)
558{
559 PRTASN1DUMPDATA pData = (PRTASN1DUMPDATA)pvUser;
560 if (!pAsn1Core->fFlags)
561 return VINF_SUCCESS;
562
563 bool fOpen = false;
564 rtAsn1DumpPrintIdent(pData, uDepth);
565 switch (pAsn1Core->fClass & ASN1_TAGCLASS_MASK)
566 {
567 case ASN1_TAGCLASS_UNIVERSAL:
568 rtAsn1DumpPrintf(pData, "%-16s ", pszName);
569 fOpen = rtAsn1DumpUniversalTypeAndValue(pData, pAsn1Core, uDepth);
570 break;
571
572 case ASN1_TAGCLASS_CONTEXT:
573 if ((pAsn1Core->fRealClass & ASN1_TAGCLASS_MASK) == ASN1_TAGCLASS_UNIVERSAL)
574 {
575 rtAsn1DumpPrintf(pData, "%-16s [%u] ", pszName, pAsn1Core->uTag);
576 fOpen = rtAsn1DumpUniversalTypeAndValue(pData, pAsn1Core, uDepth);
577 }
578 else
579 {
580 rtAsn1DumpPrintf(pData, "%-16s [%u]\n", pszName, pAsn1Core->uTag);
581 fOpen = true;
582 }
583 break;
584
585 case ASN1_TAGCLASS_APPLICATION:
586 if ((pAsn1Core->fRealClass & ASN1_TAGCLASS_MASK) == ASN1_TAGCLASS_UNIVERSAL)
587 {
588 rtAsn1DumpPrintf(pData, "%-16s [APPLICATION %u] ", pszName, pAsn1Core->uTag);
589 fOpen = rtAsn1DumpUniversalTypeAndValue(pData, pAsn1Core, uDepth);
590 }
591 else
592 {
593 rtAsn1DumpPrintf(pData, "%-16s [APPLICATION %u]\n", pszName, pAsn1Core->uTag);
594 fOpen = true;
595 }
596 break;
597
598 case ASN1_TAGCLASS_PRIVATE:
599 if (RTASN1CORE_IS_DUMMY(pAsn1Core))
600 rtAsn1DumpPrintf(pData, "%-16s DUMMY\n", pszName);
601 else
602 {
603 rtAsn1DumpPrintf(pData, "%-16s [PRIVATE %u]\n", pszName, pAsn1Core->uTag);
604 fOpen = true;
605 }
606 break;
607 }
608 /** @todo {} */
609
610 /*
611 * Recurse.
612 */
613 if ( pAsn1Core->pOps
614 && pAsn1Core->pOps->pfnEnum)
615 pAsn1Core->pOps->pfnEnum(pAsn1Core, rtAsn1DumpEnumCallback, uDepth, pData);
616 return VINF_SUCCESS;
617}
618
619
620RTDECL(int) RTAsn1Dump(PCRTASN1CORE pAsn1Core, uint32_t fFlags, uint32_t uLevel, PFNRTDUMPPRINTFV pfnPrintfV, void *pvUser)
621{
622 if ( pAsn1Core->pOps
623 && pAsn1Core->pOps->pfnEnum)
624 {
625 RTASN1DUMPDATA Data;
626 Data.fFlags = fFlags;
627 Data.pfnPrintfV = pfnPrintfV;
628 Data.pvUser = pvUser;
629
630 return pAsn1Core->pOps->pfnEnum((PRTASN1CORE)pAsn1Core, rtAsn1DumpEnumCallback, uLevel, &Data);
631 }
632 return VINF_SUCCESS;
633}
634
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette