VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/asn1/asn1-ut-objid.cpp

Last change on this file was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.6 KB
Line 
1/* $Id: asn1-ut-objid.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * IPRT - ASN.1, OBJECT IDENTIFIER Type.
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include "internal/iprt.h"
42#include <iprt/asn1.h>
43
44#include <iprt/alloca.h>
45#include <iprt/bignum.h>
46#include <iprt/ctype.h>
47#include <iprt/err.h>
48#include <iprt/string.h>
49#include <iprt/uni.h>
50
51#include <iprt/formats/asn1.h>
52
53
54/*********************************************************************************************************************************
55* Global Variables *
56*********************************************************************************************************************************/
57static char const g_szDefault[] = "2.16.840.1.113894";
58static uint32_t const g_auDefault[] = { 2, 16, 840, 1, 113894 };
59static uint8_t const g_abDefault[] =
60{
61 2*40 + 16, 0x80 | (840 >> 7), 840 & 0x7f, 1, 0x80 | (113894 >> 14), 0x80 | ((113894 >> 7) & 0x7f), 113894 & 0x7f
62};
63
64
65/*********************************************************************************************************************************
66* Internal Functions *
67*********************************************************************************************************************************/
68DECLHIDDEN(int) rtAsn1ObjId_InternalFormatComponent(uint32_t uValue, char **ppszObjId, size_t *pcbObjId); /* asn1-ut-objid.cpp */
69/** @todo check if we really need this. */
70
71
72
73/*
74 * ASN.1 OBJECT IDENTIFIER - Special Methods.
75 */
76
77/**
78 * Encodes the ASN.1 byte sequence for a set of components.
79 *
80 * @returns IPRT status code.
81 * @param cComponents The number of components. Must be at least two.
82 * @param pauComponents The components array.
83 * @param pbEncoded The output buffer.
84 * @param pcbEncoded On input, this holds the size of the output buffer.
85 * On successful return it's the encoded size in bytes.
86 */
87static int rtAsn1ObjId_EncodeComponents(uint32_t cComponents, uint32_t const *pauComponents,
88 uint8_t *pbEncoded, uint32_t *pcbEncoded)
89{
90 uint8_t *pbCur = pbEncoded;
91 uint32_t cbLeft = *pcbEncoded;
92
93 /* The first two componets are encoded together to save a byte, so the loop
94 organization is a little special. */
95 AssertReturn(cComponents >= 2, VERR_ASN1_INTERNAL_ERROR_1);
96 AssertReturn(pauComponents[0] <= 2, VERR_ASN1_INTERNAL_ERROR_1);
97 AssertReturn(pauComponents[1] <= (pauComponents[0] < 2 ? 39 : UINT32_MAX - 80), VERR_ASN1_INTERNAL_ERROR_1);
98 uint32_t i = 1;
99 uint32_t uValue = pauComponents[0] * 40 + pauComponents[1];
100
101 for (;;)
102 {
103 if (uValue < 0x80)
104 {
105 if (RT_UNLIKELY(cbLeft < 1))
106 return VERR_BUFFER_OVERFLOW;
107 cbLeft -= 1;
108 *pbCur++ = (uint8_t)uValue;
109 }
110 else if (uValue < 0x4000)
111 {
112 if (RT_UNLIKELY(cbLeft < 2))
113 return VERR_BUFFER_OVERFLOW;
114 cbLeft -= 2;
115 pbCur[0] = (uValue >> 7) | 0x80;
116 pbCur[1] = uValue & 0x7f;
117 pbCur += 2;
118 }
119 else if (uValue < 0x200000)
120 {
121 if (RT_UNLIKELY(cbLeft < 3))
122 return VERR_BUFFER_OVERFLOW;
123 cbLeft -= 3;
124 pbCur[0] = (uValue >> 14) | 0x80;
125 pbCur[1] = ((uValue >> 7) & 0x7f) | 0x80;
126 pbCur[2] = uValue & 0x7f;
127 pbCur += 3;
128 }
129 else if (uValue < 0x10000000)
130 {
131 if (RT_UNLIKELY(cbLeft < 4))
132 return VERR_BUFFER_OVERFLOW;
133 cbLeft -= 4;
134 pbCur[0] = (uValue >> 21) | 0x80;
135 pbCur[1] = ((uValue >> 14) & 0x7f) | 0x80;
136 pbCur[2] = ((uValue >> 7) & 0x7f) | 0x80;
137 pbCur[3] = uValue & 0x7f;
138 pbCur += 4;
139 }
140 else
141 {
142 if (RT_UNLIKELY(cbLeft < 5))
143 return VERR_BUFFER_OVERFLOW;
144 cbLeft -= 5;
145 pbCur[0] = (uValue >> 28) | 0x80;
146 pbCur[1] = ((uValue >> 21) & 0x7f) | 0x80;
147 pbCur[2] = ((uValue >> 14) & 0x7f) | 0x80;
148 pbCur[3] = ((uValue >> 7) & 0x7f) | 0x80;
149 pbCur[4] = uValue & 0x7f;
150 pbCur += 5;
151 }
152
153 /* Advance / return. */
154 i++;
155 if (i >= cComponents)
156 {
157 *pcbEncoded = (uint32_t)(pbCur - pbEncoded);
158 return VINF_SUCCESS;
159 }
160 uValue = pauComponents[i];
161 }
162}
163
164
165RTDECL(int) RTAsn1ObjId_InitFromString(PRTASN1OBJID pThis, const char *pszObjId, PCRTASN1ALLOCATORVTABLE pAllocator)
166{
167 RT_ZERO(*pThis);
168
169 /*
170 * Check the string, counting the number of components and checking their validity.
171 */
172 size_t cbObjId = strlen(pszObjId) + 1;
173 AssertReturn(cbObjId < sizeof(pThis->szObjId), VERR_ASN1_OBJID_TOO_LONG_STRING_FORM);
174
175 const char *psz = pszObjId;
176
177 /* Special checking of the first component. It has only three valid values: 0,1,2. */
178 char ch = *psz++;
179 if (RT_UNLIKELY(ch < '0' || ch > '2'))
180 return VERR_ASN1_OBJID_INVALID_DOTTED_STRING;
181 char const chFirst = ch;
182 ch = *psz++;
183 if (RT_UNLIKELY(ch != '.'))
184 return VERR_ASN1_OBJID_INVALID_DOTTED_STRING;
185
186 /* The 2nd component. It the first is 0 or 1, it has a max of 39. */
187 uint32_t cComponents = 1;
188 if (chFirst < '2')
189 {
190 ch = *psz++;
191 if (*psz == '.')
192 {
193 if (RT_UNLIKELY(!RT_C_IS_DIGIT(ch)))
194 return VERR_ASN1_OBJID_INVALID_DOTTED_STRING;
195 }
196 else
197 {
198 if (RT_UNLIKELY(ch < '0' || ch > '3'))
199 return VERR_ASN1_OBJID_INVALID_DOTTED_STRING;
200 ch = *psz++;
201 if (RT_UNLIKELY(!RT_C_IS_DIGIT(ch)))
202 return VERR_ASN1_OBJID_INVALID_DOTTED_STRING;
203 if (*psz != '.')
204 return VERR_ASN1_OBJID_INVALID_DOTTED_STRING;
205 }
206 cComponents++;
207 }
208 else
209 psz--;
210
211 /* Subsequent components have max values of UINT32_MAX - 80. */
212 while ((ch = *psz++) != '\0')
213 {
214 if (RT_UNLIKELY(ch != '.'))
215 return VERR_ASN1_OBJID_INVALID_DOTTED_STRING;
216 const char *pszStart = psz;
217
218 /* Special treatment of the first digit. Need to make sure it isn't an
219 unnecessary leading 0. */
220 ch = *psz++;
221 if (RT_UNLIKELY(!RT_C_IS_DIGIT(ch)))
222 return VERR_ASN1_OBJID_INVALID_DOTTED_STRING;
223 if (RT_UNLIKELY(ch == '0' && RT_C_IS_DIGIT(*psz)))
224 return VERR_ASN1_OBJID_INVALID_DOTTED_STRING;
225
226 /* The rest of the digits. */
227 while ((ch = *psz) != '.' && ch != '\0')
228 {
229 if (RT_UNLIKELY(!RT_C_IS_DIGIT(ch)))
230 return VERR_ASN1_OBJID_INVALID_DOTTED_STRING;
231 psz++;
232 }
233
234 /* Check the value range. */
235 if (RT_UNLIKELY(psz - pszStart >= 9))
236 if ( psz - pszStart > 9
237 || strncmp(pszStart, "4294967216", 9) >= 0) /* 2^32 - 80 */
238 return VERR_ASN1_OBJID_INVALID_DOTTED_STRING;
239
240 cComponents++;
241 }
242
243 if (RT_UNLIKELY(cComponents >= 128))
244 return VERR_ASN1_OBJID_TOO_MANY_COMPONENTS;
245 pThis->cComponents = (uint8_t)cComponents;
246
247 /*
248 * Find space for the component array, either at the unused end of szObjId
249 * or on the heap.
250 */
251 int rc;
252 RTAsn1MemInitAllocation(&pThis->Allocation, pAllocator);
253#if 0 /** @todo breaks with arrays of ObjIds or structs containing them. They get resized and repositioned in memory, thus invalidating the pointer. Add recall-pointers callback, or just waste memory? Or maybe make all arrays pointer-arrays? */
254 size_t cbLeft = sizeof(pThis->szObjId) - cbObjId;
255 if (cbLeft >= cComponents * sizeof(uint32_t))
256 {
257 pThis->pauComponents = (uint32_t *)&pThis->szObjId[sizeof(pThis->szObjId) - cComponents * sizeof(uint32_t)];
258 cbLeft -= cComponents * sizeof(uint32_t);
259 rc = VINF_SUCCESS;
260 }
261 else
262#endif
263 rc = RTAsn1MemAllocZ(&pThis->Allocation, (void **)&pThis->pauComponents, cComponents * sizeof(uint32_t));
264 if (RT_SUCCESS(rc))
265 {
266 /*
267 * Fill the elements array.
268 */
269 uint32_t *pauComponents = (uint32_t *)pThis->pauComponents;
270 rc = VINF_SUCCESS;
271 psz = pszObjId;
272 for (uint32_t i = 0; i < cComponents; i++)
273 {
274 uint32_t uValue = 0;
275 rc = RTStrToUInt32Ex(psz, (char **)&psz, 10, &uValue);
276 if (rc == VWRN_TRAILING_CHARS)
277 {
278 pauComponents[i] = uValue;
279 AssertBreakStmt(*psz == '.', rc = VERR_TRAILING_CHARS);
280 psz++;
281 }
282 else if (rc == VINF_SUCCESS)
283 {
284 pauComponents[i] = uValue;
285 Assert(*psz == '\0');
286 }
287 else if (RT_FAILURE(rc))
288 break;
289 else
290 {
291 rc = -rc;
292 break;
293 }
294 }
295 if (rc == VINF_SUCCESS && *psz == '\0')
296 {
297 /*
298 * Initialize the core structure before we start on the encoded bytes.
299 */
300 RTAsn1Core_InitEx(&pThis->Asn1Core,
301 ASN1_TAG_OID,
302 ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_PRIMITIVE,
303 &g_RTAsn1ObjId_Vtable,
304 RTASN1CORE_F_PRESENT | RTASN1CORE_F_PRIMITE_TAG_STRUCT);
305
306 /*
307 * Encode the value into the string buffer. This will NOT overflow
308 * because the string representation is much less efficient than the
309 * binary ASN.1 representation (base-10 + separators vs. base-128).
310 */
311 pThis->Asn1Core.cb = (uint32_t)cbObjId;
312 rc = rtAsn1ObjId_EncodeComponents(cComponents, pThis->pauComponents,
313 (uint8_t *)&pThis->szObjId[0], &pThis->Asn1Core.cb);
314 if (RT_SUCCESS(rc))
315 {
316 /*
317 * Now, find a place for the encoded bytes. There might be
318 * enough room left in the szObjId for it if we're lucky.
319 */
320#if 0 /** @todo breaks with arrays of ObjIds or structs containing them. They get resized and repositioned in memory, thus invalidating the pointer. Add recall-pointers callback, or just waste memory? Or maybe make all arrays pointer-arrays? */
321 if (pThis->Asn1Core.cb >= cbLeft)
322 pThis->Asn1Core.uData.pv = memmove(&pThis->szObjId[cbObjId], &pThis->szObjId[0], pThis->Asn1Core.cb);
323 else
324#endif
325 rc = RTAsn1ContentDup(&pThis->Asn1Core, pThis->szObjId, pThis->Asn1Core.cb, pAllocator);
326 if (RT_SUCCESS(rc))
327 {
328 /*
329 * Finally, copy the dotted string.
330 */
331 memcpy(pThis->szObjId, pszObjId, cbObjId);
332 return VINF_SUCCESS;
333 }
334 }
335 else
336 {
337 AssertMsgFailed(("%Rrc\n", rc));
338 rc = VERR_ASN1_INTERNAL_ERROR_3;
339 }
340 }
341 else
342 rc = VERR_ASN1_OBJID_INVALID_DOTTED_STRING;
343 }
344 RT_ZERO(*pThis);
345 return rc;
346}
347
348
349RTDECL(int) RTAsn1ObjId_SetFromString(PRTASN1OBJID pThis, const char *pszObjId, PCRTASN1ALLOCATORVTABLE pAllocator)
350{
351 RTAsn1ObjId_Delete(pThis);
352 int rc = RTAsn1ObjId_InitFromString(pThis, pszObjId, pAllocator);
353 if (RT_FAILURE(rc))
354 RTAsn1ObjId_Init(pThis, pAllocator);
355 return rc;
356}
357
358
359RTDECL(int) RTAsn1ObjId_CompareWithString(PCRTASN1OBJID pThis, const char *pszRight)
360{
361 return strcmp(pThis->szObjId, pszRight);
362}
363
364
365RTDECL(bool) RTAsn1ObjId_StartsWith(PCRTASN1OBJID pThis, const char *pszStartsWith)
366{
367 size_t cchStartsWith = strlen(pszStartsWith);
368 return !strncmp(pThis->szObjId, pszStartsWith, cchStartsWith)
369 && ( pszStartsWith[cchStartsWith] == '.'
370 || pszStartsWith[cchStartsWith] == '\0');
371}
372
373
374RTDECL(uint8_t) RTAsn1ObjIdCountComponents(PCRTASN1OBJID pThis)
375{
376 return pThis->cComponents;
377}
378
379
380RTDECL(uint32_t) RTAsn1ObjIdGetComponentsAsUInt32(PCRTASN1OBJID pThis, uint8_t iComponent)
381{
382 if (iComponent < pThis->cComponents)
383 return pThis->pauComponents[iComponent];
384 return UINT32_MAX;
385}
386
387
388RTDECL(uint32_t) RTAsn1ObjIdGetLastComponentsAsUInt32(PCRTASN1OBJID pThis)
389{
390 return pThis->pauComponents[pThis->cComponents - 1];
391}
392
393
394/*
395 * ASN.1 OBJECT IDENTIFIER - Standard Methods.
396 */
397
398RT_DECL_DATA_CONST(RTASN1COREVTABLE const) g_RTAsn1ObjId_Vtable =
399{
400 "RTAsn1ObjId",
401 sizeof(RTASN1OBJID),
402 ASN1_TAG_OID,
403 ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_PRIMITIVE,
404 0,
405 (PFNRTASN1COREVTDTOR)RTAsn1ObjId_Delete,
406 NULL,
407 (PFNRTASN1COREVTCLONE)RTAsn1ObjId_Clone,
408 (PFNRTASN1COREVTCOMPARE)RTAsn1ObjId_Compare,
409 (PFNRTASN1COREVTCHECKSANITY)RTAsn1ObjId_CheckSanity,
410 NULL,
411 NULL
412};
413
414
415RTDECL(int) RTAsn1ObjId_Init(PRTASN1OBJID pThis, PCRTASN1ALLOCATORVTABLE pAllocator)
416{
417 RT_NOREF_PV(pAllocator);
418 RTAsn1Core_InitEx(&pThis->Asn1Core,
419 ASN1_TAG_OID,
420 ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_PRIMITIVE,
421 &g_RTAsn1ObjId_Vtable,
422 RTASN1CORE_F_PRESENT | RTASN1CORE_F_PRIMITE_TAG_STRUCT);
423 pThis->Asn1Core.cb = sizeof(g_abDefault);
424 pThis->Asn1Core.uData.pv = (void *)&g_abDefault[0];
425 pThis->cComponents = RT_ELEMENTS(g_auDefault);
426 pThis->pauComponents = g_auDefault;
427 AssertCompile(sizeof(g_szDefault) <= sizeof(pThis->szObjId));
428 memcpy(pThis->szObjId, g_szDefault, sizeof(g_szDefault));
429 return VINF_SUCCESS;
430}
431
432
433RTDECL(int) RTAsn1ObjId_Clone(PRTASN1OBJID pThis, PCRTASN1OBJID pSrc, PCRTASN1ALLOCATORVTABLE pAllocator)
434{
435 AssertPtr(pSrc); AssertPtr(pThis); AssertPtr(pAllocator);
436 RT_ZERO(*pThis);
437 if (RTAsn1ObjId_IsPresent(pSrc))
438 {
439 AssertReturn(pSrc->Asn1Core.pOps == &g_RTAsn1ObjId_Vtable, VERR_INTERNAL_ERROR_3);
440
441 /* Copy the dotted string representation. */
442 size_t cbObjId = strlen(pSrc->szObjId) + 1;
443 AssertReturn(cbObjId <= sizeof(pThis->szObjId), VERR_INTERNAL_ERROR_5);
444 memcpy(pThis->szObjId, pSrc->szObjId, cbObjId);
445
446 /* Copy the integer component array. Try fit it in the unused space of
447 the dotted object string buffer. We place it at the end of the
448 buffer as that is simple alignment wise and avoid wasting bytes that
449 could be used to sequueze in the content bytes (see below). */
450 int rc;
451 RTAsn1MemInitAllocation(&pThis->Allocation, pAllocator);
452 pThis->cComponents = pSrc->cComponents;
453#if 0 /** @todo breaks with arrays of ObjIds or structs containing them. They get resized and repositioned in memory, thus invalidating the pointer. Add recall-pointers callback, or just waste memory? Or maybe make all arrays pointer-arrays? */
454 size_t cbLeft = sizeof(pThis->szObjId);
455 if (pSrc->cComponents * sizeof(uint32_t) <= cbLeft)
456 {
457 pThis->pauComponents = (uint32_t *)&pThis->szObjId[sizeof(pThis->szObjId) - pSrc->cComponents * sizeof(uint32_t)];
458 memcpy((uint32_t *)pThis->pauComponents, pSrc->pauComponents, pSrc->cComponents * sizeof(uint32_t));
459 cbLeft -= pSrc->cComponents * sizeof(uint32_t);
460 rc = VINF_SUCCESS;
461 }
462 else
463#endif
464 {
465 rc = RTAsn1MemDup(&pThis->Allocation, (void **)&pThis->pauComponents, pSrc->pauComponents,
466 pSrc->cComponents * sizeof(uint32_t));
467 }
468 if (RT_SUCCESS(rc))
469 {
470 /* See if we can fit the content value into the szObjId as well.
471 It will follow immediately after the string as the component
472 array is the end of the string buffer, when present. */
473#if 0 /** @todo breaks with arrays of ObjIds or structs containing them. They get resized and repositioned in memory, thus invalidating the pointer. Add recall-pointers callback, or just waste memory? Or maybe make all arrays pointer-arrays? */
474 uint32_t cbContent = pSrc->Asn1Core.cb;
475 if (cbContent <= cbLeft)
476 {
477 rc = RTAsn1Core_CloneNoContent(&pThis->Asn1Core, &pSrc->Asn1Core);
478 if (RT_SUCCESS(rc))
479 {
480 pThis->Asn1Core.uData.pv = memcpy(&pThis->szObjId[cbObjId], pSrc->Asn1Core.uData.pv, cbContent);
481 return VINF_SUCCESS;
482 }
483 }
484 else
485#endif
486 {
487 rc = RTAsn1Core_CloneContent(&pThis->Asn1Core, &pSrc->Asn1Core, pAllocator);
488 if (RT_SUCCESS(rc))
489 return VINF_SUCCESS;
490 }
491 }
492
493 /* failed, clean up. */
494 if (pThis->Allocation.cbAllocated)
495 RTAsn1MemFree(&pThis->Allocation, (uint32_t *)pThis->pauComponents);
496 RT_ZERO(*pThis);
497 return rc;
498 }
499 return VINF_SUCCESS;
500}
501
502
503RTDECL(void) RTAsn1ObjId_Delete(PRTASN1OBJID pThis)
504{
505 if ( pThis
506 && RTAsn1ObjId_IsPresent(pThis))
507 {
508 Assert(pThis->Asn1Core.pOps == &g_RTAsn1ObjId_Vtable);
509
510 if (pThis->Allocation.cbAllocated)
511 RTAsn1MemFree(&pThis->Allocation, (uint32_t *)pThis->pauComponents);
512 RTAsn1ContentFree(&pThis->Asn1Core);
513 RT_ZERO(*pThis);
514 }
515}
516
517
518RTDECL(int) RTAsn1ObjId_Enum(PRTASN1OBJID pThis, PFNRTASN1ENUMCALLBACK pfnCallback, uint32_t uDepth, void *pvUser)
519{
520 RT_NOREF_PV(pThis); RT_NOREF_PV(pfnCallback); RT_NOREF_PV(uDepth); RT_NOREF_PV(pvUser);
521 Assert(pThis && (!RTAsn1ObjId_IsPresent(pThis) || pThis->Asn1Core.pOps == &g_RTAsn1ObjId_Vtable));
522
523 /* No children to enumerate. */
524 return VINF_SUCCESS;
525}
526
527
528RTDECL(int) RTAsn1ObjId_Compare(PCRTASN1OBJID pLeft, PCRTASN1OBJID pRight)
529{
530 if (RTAsn1ObjId_IsPresent(pLeft))
531 {
532 if (RTAsn1ObjId_IsPresent(pRight))
533 {
534 uint8_t cComponents = RT_MIN(pLeft->cComponents, pRight->cComponents);
535 for (uint32_t i = 0; i < cComponents; i++)
536 if (pLeft->pauComponents[i] != pRight->pauComponents[i])
537 return pLeft->pauComponents[i] < pRight->pauComponents[i] ? -1 : 1;
538
539 if (pLeft->cComponents == pRight->cComponents)
540 return 0;
541 return pLeft->cComponents < pRight->cComponents ? -1 : 1;
542 }
543 return 1;
544 }
545 return 0 - (int)RTAsn1ObjId_IsPresent(pRight);
546}
547
548
549RTDECL(int) RTAsn1ObjId_CheckSanity(PCRTASN1OBJID pThis, uint32_t fFlags, PRTERRINFO pErrInfo, const char *pszErrorTag)
550{
551 RT_NOREF_PV(fFlags);
552 if (RT_UNLIKELY(!RTAsn1ObjId_IsPresent(pThis)))
553 return RTErrInfoSetF(pErrInfo, VERR_ASN1_NOT_PRESENT, "%s: Missing (OBJID).", pszErrorTag);
554 return VINF_SUCCESS;
555}
556
557
558/*
559 * Generate code for the associated collection types.
560 */
561#define RTASN1TMPL_TEMPLATE_FILE "../common/asn1/asn1-ut-objid-template.h"
562#include <iprt/asn1-generator-internal-header.h>
563#include <iprt/asn1-generator-core.h>
564#include <iprt/asn1-generator-init.h>
565#include <iprt/asn1-generator-sanity.h>
566
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