VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/asn1/oiddb2c.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: 22.2 KB
Line 
1/* $Id: oiddb2c.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * IPRT - OID text database to C converter.
4 *
5 * The output is used by asn1-dump.cpp.
6 */
7
8/*
9 * Copyright (C) 2006-2019 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * The contents of this file may alternatively be used under the terms
20 * of the Common Development and Distribution License Version 1.0
21 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
22 * VirtualBox OSE distribution, in which case the provisions of the
23 * CDDL are applicable instead of those of the GPL.
24 *
25 * You may elect to license modified versions of this file under the
26 * terms and conditions of either the GPL or the CDDL or both.
27 */
28
29
30/*********************************************************************************************************************************
31* Header Files *
32*********************************************************************************************************************************/
33#include <iprt/assert.h>
34#include <iprt/types.h>
35#include <iprt/ctype.h>
36#include <iprt/stdarg.h>
37#include <stdio.h>
38#include <string.h>
39#include <stdlib.h>
40
41/*
42 * Include the string table code.
43 */
44#define BLDPROG_STRTAB_MAX_STRLEN 48
45#define BLDPROG_STRTAB_WITH_COMPRESSION
46#define BLDPROG_STRTAB_PURE_ASCII
47#define BLDPROG_STRTAB_WITH_CAMEL_WORDS
48#include <iprt/bldprog-strtab-template.cpp.h>
49
50
51/*********************************************************************************************************************************
52* Defined Constants And Macros *
53*********************************************************************************************************************************/
54#define OID2C_MAX_COMP_VALUE _1G
55
56
57/*********************************************************************************************************************************
58* Structures and Typedefs *
59*********************************************************************************************************************************/
60/**
61 * Raw OID tree node.
62 *
63 * This is what we produce while loading OID input files.
64 */
65typedef struct RAWOIDNODE
66{
67 /** The component value. */
68 uint32_t uKey;
69 /** Number of children. */
70 uint32_t cChildren;
71 /** Pointer to the children pointers (sorted by key). */
72 struct RAWOIDNODE **papChildren;
73 /** Pointer to the parent. */
74 struct RAWOIDNODE *pParent;
75 /** The string table entry for this node. */
76 BLDPROGSTRING StrTabEntry;
77 /** The table index of the children. */
78 uint32_t idxChildren;
79 /** Set if we've got one or more children with large keys. */
80 bool fChildrenInBigTable;
81} RAWOIDNODE;
82/** Pointer to a raw OID node. */
83typedef RAWOIDNODE *PRAWOIDNODE;
84
85
86/*********************************************************************************************************************************
87* Global Variables *
88*********************************************************************************************************************************/
89/** What to prefix errors with. */
90static const char *g_pszProgName = "oiddb2c";
91
92/** The OID tree. */
93static PRAWOIDNODE g_pOidRoot = NULL;
94/** Number of nodes in the OID tree. */
95static uint32_t g_cOidNodes = 0;
96/** Number of nodes in the OID tree that has strings (for the string table). */
97static uint32_t g_cOidNodesWithStrings = 0;
98/** Max number of children of a node in the OID tree. */
99static uint32_t g_cMaxOidChildren = 0;
100/** Number of nodes which key fits within 6-bits. */
101static uint32_t g_cOidNodiesWith6bitKeys = 0;
102
103
104static RTEXITCODE error(const char *pszFormat, ...)
105{
106 va_list va;
107 va_start(va, pszFormat);
108 fprintf(stderr, "%s: error: ", g_pszProgName);
109 vfprintf(stderr, pszFormat, va);
110 va_end(va);
111 return RTEXITCODE_FAILURE;
112}
113
114static RTEXITCODE warning(const char *pszFormat, ...)
115{
116 va_list va;
117 va_start(va, pszFormat);
118 fprintf(stderr, "%s: warning: ", g_pszProgName);
119 vfprintf(stderr, pszFormat, va);
120 va_end(va);
121 return RTEXITCODE_FAILURE;
122}
123
124
125static void writeDottedOidForNode(PRAWOIDNODE pCurNode, FILE *pOut)
126{
127 if (pCurNode->pParent)
128 {
129 writeDottedOidForNode(pCurNode->pParent, pOut);
130 fprintf(pOut, ".%u", pCurNode->uKey);
131 }
132 else
133 fprintf(pOut, "%u", pCurNode->uKey);
134}
135
136
137static void writeOidTree(PRAWOIDNODE pCurNode, FILE *pOut, bool fBigTable, PBLDPROGSTRTAB pStrTab)
138{
139 /*
140 * First we produce the entries for our children.
141 */
142 if (pCurNode->fChildrenInBigTable == fBigTable)
143 {
144 for (unsigned i = 0; i < pCurNode->cChildren; i++)
145 {
146 PRAWOIDNODE pChild = pCurNode->papChildren[i];
147 fprintf(pOut,
148 fBigTable
149 ? " { %7u, %2u, %u, %2u, %4u, %#06x }, /* "
150 : " { %2u, %2u, %u, %2u, %4u, %#06x }, /* "
151 ,
152 pChild->uKey,
153 (unsigned)pChild->StrTabEntry.cchString,
154 pChild->fChildrenInBigTable,
155 pChild->cChildren,
156 pChild->idxChildren,
157 pChild->StrTabEntry.offStrTab);
158 writeDottedOidForNode(pChild, pOut);
159 if (pChild->StrTabEntry.pszString)
160 {
161 fputs(" = \"", pOut);
162 BldProgStrTab_PrintCStringLitteral(pStrTab, &pChild->StrTabEntry, pOut);
163 fputs("\" */\n", pOut);
164 }
165 else
166 fputs(" */\n", pOut);
167 }
168 }
169
170 /*
171 * Then we decend and let our children do the same.
172 */
173 for (unsigned i = 0; i < pCurNode->cChildren; i++)
174 writeOidTree(pCurNode->papChildren[i], pOut, fBigTable, pStrTab);
175}
176
177
178static uint32_t prepareOidTreeForWriting(PRAWOIDNODE pCurNode, uint32_t idxCur, bool fBigTable)
179{
180 if (pCurNode->fChildrenInBigTable == fBigTable)
181 {
182 pCurNode->idxChildren = pCurNode->cChildren ? idxCur : 0;
183 idxCur += pCurNode->cChildren;
184 }
185
186 for (unsigned i = 0; i < pCurNode->cChildren; i++)
187 idxCur = prepareOidTreeForWriting(pCurNode->papChildren[i], idxCur, fBigTable);
188
189 return idxCur;
190}
191
192
193static void addStringFromOidTree(PRAWOIDNODE pCurNode, PBLDPROGSTRTAB pStrTab)
194{
195 /* Do self. */
196 if (pCurNode->StrTabEntry.pszString)
197 BldProgStrTab_AddString(pStrTab, &pCurNode->StrTabEntry);
198
199 /* Recurse into children. */
200 unsigned i = pCurNode->cChildren;
201 while (i-- > 0)
202 addStringFromOidTree(pCurNode->papChildren[i], pStrTab);
203}
204
205
206static bool isNiceAsciiString(const char *psz)
207{
208 unsigned uch;
209 while ((uch = *psz) != '\0')
210 if ( !(uch & 0x80)
211 && ( uch >= 0x20
212 || uch == '\t') )
213 psz++;
214 else
215 return false;
216 return true;
217}
218
219
220static RTEXITCODE addOidToTree(uint32_t const *pauComponents, unsigned cComponents, const char *pszName,
221 const char *pszFile, unsigned iLineNo)
222{
223 /*
224 * Check preconditions.
225 */
226 size_t cchName = strlen(pszName);
227 if (cchName == '\0')
228 return warning("%s(%d): Empty OID name!\n", pszFile, iLineNo);
229 if (cchName >= BLDPROG_STRTAB_MAX_STRLEN)
230 return warning("%s(%d): OID name is too long (%u)!\n", pszFile, iLineNo, (unsigned)cchName);
231 if (cComponents == 0)
232 return warning("%s(%d): 'Description' without valid OID preceeding it!\n", pszFile, iLineNo);
233 if (!isNiceAsciiString(pszName))
234 return warning("%s(%d): Contains unwanted characters!\n", pszFile, iLineNo);
235
236 /*
237 * Make sure we've got a root node (it has no actual OID componet value,
238 * it's just a place to put the top level children).
239 */
240 if (!g_pOidRoot)
241 {
242 g_pOidRoot = (PRAWOIDNODE)calloc(sizeof(*g_pOidRoot), 1);
243 if (!g_pOidRoot)
244 return error("Out of memory!\n");
245 }
246
247 /*
248 * Decend into the tree, adding any missing nodes as we go along.
249 * We'll end up with the node which is being named.
250 */
251 PRAWOIDNODE pCur = g_pOidRoot;
252 while (cComponents-- > 0)
253 {
254 uint32_t const uKey = *pauComponents++;
255 uint32_t i = pCur->cChildren;
256 while ( i > 0
257 && pCur->papChildren[i - 1]->uKey >= uKey)
258 i--;
259 if ( i < pCur->cChildren
260 && pCur->papChildren[i]->uKey == uKey)
261 pCur = pCur->papChildren[i];
262 else
263 {
264 /* Resize the child pointer array? */
265 if ((pCur->cChildren % 16) == 0)
266 {
267 void *pvNew = realloc(pCur->papChildren, sizeof(pCur->papChildren[0]) * (pCur->cChildren + 16));
268 if (!pvNew)
269 return error("Out of memory!\n");
270 pCur->papChildren = (PRAWOIDNODE *)pvNew;
271 }
272
273 /* Allocate and initialize the node. */
274 PRAWOIDNODE pNew = (PRAWOIDNODE)malloc(sizeof(*pNew));
275 if (!pNew)
276 return error("Out of memory!\n");
277 pNew->uKey = uKey;
278 pNew->pParent = pCur;
279 pNew->papChildren = NULL;
280 pNew->cChildren = 0;
281 pNew->fChildrenInBigTable = false;
282 memset(&pNew->StrTabEntry, 0, sizeof(pNew->StrTabEntry));
283
284 /* Insert it. */
285 if (i < pCur->cChildren)
286 memmove(&pCur->papChildren[i + 1], &pCur->papChildren[i], (pCur->cChildren - i) * sizeof(pCur->papChildren[0]));
287 pCur->papChildren[i] = pNew;
288 pCur->cChildren++;
289
290 if (pCur->cChildren > g_cMaxOidChildren)
291 g_cMaxOidChildren = pCur->cChildren;
292 g_cOidNodes++;
293 if (uKey < 64)
294 g_cOidNodiesWith6bitKeys++;
295 else
296 {
297 pCur->fChildrenInBigTable = true;
298 if (!pCur->pParent)
299 return error("Invalid OID! Top level componet value is out of range: %u (max 2)\n", uKey);
300 }
301
302 /* Decend (could optimize insertion of the remaining nodes, but
303 too much work for very little gain). */
304 pCur = pNew;
305 }
306 }
307
308 /*
309 * Update the node.
310 */
311 if (!pCur->StrTabEntry.pszString)
312 {
313 pCur->StrTabEntry.pszString = (char *)malloc(cchName + 1);
314 if (pCur->StrTabEntry.pszString)
315 memcpy(pCur->StrTabEntry.pszString, pszName, cchName + 1);
316 else
317 return error("Out of memory!\n");
318 pCur->StrTabEntry.cchString = cchName;
319 if (cchName >= 64)
320 pCur->fChildrenInBigTable = true;
321 g_cOidNodesWithStrings++;
322 }
323 /* Ignore duplicates, but warn if different name. */
324 else if ( pCur->StrTabEntry.cchString != cchName
325 || strcmp(pszName, pCur->StrTabEntry.pszString) != 0)
326 warning("%s(%d): Duplicate OID, name differs: '%s' vs '%s'\n", pszFile, iLineNo, pCur->StrTabEntry.pszString, pszName);
327
328 return RTEXITCODE_SUCCESS;
329}
330
331
332static RTEXITCODE parseOid(uint32_t *pauComponents, unsigned *pcComponents, unsigned cMaxComponents, char const *pszOid,
333 const char *pszFile, unsigned iLine)
334{
335 const char *pszInput = pszOid;
336 unsigned i = 0;
337 char ch;
338 for (;;)
339 {
340 /*
341 * Parse the value.
342 */
343 unsigned uValue = 0;
344 if (RT_C_IS_DIGIT((ch = *pszOid)))
345 {
346 do
347 {
348 uValue *= 10;
349 uValue += ch - '0';
350 if (uValue < OID2C_MAX_COMP_VALUE)
351 pszOid++;
352 else
353 return warning("%s(%d): Component %u in OID attribute value '%s' is out side the supported!\n",
354 pszFile, iLine, i, pszInput);
355 } while (RT_C_IS_DIGIT((ch = *pszOid)));
356 if ( ch == '\0'
357 || ch == '.'
358 || RT_C_IS_BLANK(ch))
359 {
360 if (i < cMaxComponents)
361 {
362 pauComponents[i] = uValue;
363 i++;
364 if (ch != '\0')
365 pszOid++;
366 else
367 {
368 *pcComponents = i;
369 return RTEXITCODE_SUCCESS;
370 }
371 }
372 else
373 return warning("%s(%d): Too many OID components in '%s'!\n", pszFile, iLine, pszInput);
374 }
375 else
376 return warning("%s(%d): Invalid OID attribute value '%s' (ch=%c)!\n", pszFile, iLine, pszInput, ch);
377 }
378 else
379 return warning("%s(%d): Invalid OID attribute value '%s' (ch=%c)!\n", pszFile, iLine, pszInput, ch);
380 }
381}
382
383
384static RTEXITCODE loadOidFile(FILE *pIn, const char *pszFile)
385{
386 /*
387 * We share the format used by dumpasn1.cfg, except that we accept
388 * dotted OIDs.
389 *
390 * An OID entry starts with a 'OID = <space or dot separated OID>'.
391 * It is usually followed by an 'Comment = ', which we ignore, and a
392 * 'Description = <name>' which we keep. We save the entry once we
393 * see the description attribute.
394 */
395 unsigned cOidComponents = 0;
396 uint32_t auOidComponents[16];
397 unsigned iLineNo = 0;
398 char szLine[16384];
399 char *pszLine;
400 szLine[sizeof(szLine) - 1] = '\0';
401 while ((pszLine = fgets(szLine, sizeof(szLine) - 1, pIn)) != NULL)
402 {
403 iLineNo++;
404
405 /* Strip leading spaces.*/
406 char ch;
407 while (RT_C_IS_SPACE((ch = *pszLine)) )
408 pszLine++;
409
410 /* We only care about lines starting with 'OID =', 'Description =' or
411 a numbered OID. */
412 if ( ch == 'O' || ch == 'o'
413 || ch == 'D' || ch == 'd'
414 || ch == '0' || ch == '1' || ch == '2')
415 {
416 /* Right strip the line. */
417 size_t cchLine = strlen(pszLine);
418 while (cchLine > 0 && RT_C_IS_SPACE(pszLine[cchLine - 1]))
419 cchLine--;
420 pszLine[cchLine] = '\0';
421
422 /* Separate the attribute name from the value. */
423 char *pszValue = (char *)memchr(pszLine, '=', cchLine);
424 if (pszValue)
425 {
426 size_t cchName = pszValue - pszLine;
427
428 /* Right strip the name. */
429 while (cchName > 0 && RT_C_IS_SPACE(pszLine[cchName - 1]))
430 cchName--;
431 pszLine[cchName] = '\0';
432
433 /* Left strip the value. */
434 do
435 pszValue++;
436 while (RT_C_IS_SPACE(*pszValue));
437
438 /* Attribute switch */
439 if ( cchName == 3
440 && (pszLine[0] == 'O' || pszLine[0] == 'o')
441 && (pszLine[1] == 'I' || pszLine[1] == 'i')
442 && (pszLine[2] == 'D' || pszLine[2] == 'd'))
443 {
444 cOidComponents = 0;
445 parseOid(auOidComponents, &cOidComponents, RT_ELEMENTS(auOidComponents), pszValue, pszFile, iLineNo);
446 }
447 else if ( cchName == 11
448 && (pszLine[0] == 'D' || pszLine[0] == 'd')
449 && (pszLine[1] == 'e' || pszLine[1] == 'E')
450 && (pszLine[2] == 's' || pszLine[2] == 'S')
451 && (pszLine[3] == 'c' || pszLine[3] == 'C')
452 && (pszLine[4] == 'r' || pszLine[4] == 'R')
453 && (pszLine[5] == 'i' || pszLine[5] == 'I')
454 && (pszLine[6] == 'p' || pszLine[6] == 'P')
455 && (pszLine[7] == 't' || pszLine[7] == 'T')
456 && (pszLine[8] == 'i' || pszLine[8] == 'I')
457 && (pszLine[9] == 'o' || pszLine[9] == 'O')
458 && (pszLine[10] == 'n' || pszLine[10] == 'N'))
459 {
460 if ( addOidToTree(auOidComponents, cOidComponents, pszValue, pszFile, iLineNo)
461 != RTEXITCODE_SUCCESS)
462 return RTEXITCODE_FAILURE;
463 cOidComponents = 0;
464 }
465 else
466 {
467 /* <OID> = <Value> */
468 cOidComponents = 0;
469 if ( parseOid(auOidComponents, &cOidComponents, RT_ELEMENTS(auOidComponents), pszLine, pszLine, iLineNo)
470 == RTEXITCODE_SUCCESS)
471 {
472 if ( addOidToTree(auOidComponents, cOidComponents, pszValue, pszFile, iLineNo)
473 != RTEXITCODE_SUCCESS)
474 return RTEXITCODE_FAILURE;
475 }
476 cOidComponents = 0;
477 }
478 }
479 }
480
481 }
482 if (feof(pIn))
483 return RTEXITCODE_SUCCESS;
484 return error("error or something reading '%s'.\n", pszFile);
485}
486
487
488
489static RTEXITCODE usage(FILE *pOut, const char *argv0, RTEXITCODE rcExit)
490{
491 fprintf(pOut, "usage: %s <out-file.c> <oid-file> [oid-file2 [...]]\n", argv0);
492 return rcExit;
493}
494
495int main(int argc, char **argv)
496{
497 /*
498 * Process arguments and input files.
499 */
500 bool fVerbose = false;
501 unsigned cInFiles = 0;
502 const char *pszOutFile = NULL;
503 for (int i = 1; i < argc; i++)
504 {
505 const char *pszFile = NULL;
506 if (argv[i][0] != '-')
507 pszFile = argv[i];
508 else if (!strcmp(argv[i], "-"))
509 pszFile = argv[i];
510 else
511 return usage(stderr, argv[0], RTEXITCODE_SYNTAX);
512
513 if (!pszOutFile)
514 pszOutFile = pszFile;
515 else
516 {
517 cInFiles++;
518 FILE *pInFile = fopen(pszFile, "r");
519 if (!pInFile)
520 return error("opening '%s' for reading.\n", pszFile);
521 RTEXITCODE rcExit = loadOidFile(pInFile, pszFile);
522 fclose(pInFile);
523 if (rcExit != RTEXITCODE_SUCCESS)
524 return rcExit;
525 }
526 }
527
528 /*
529 * Check that the user specified at least one input and an output file.
530 */
531 if (!pszOutFile)
532 return error("No output file specified specified!\n");
533 if (!cInFiles)
534 return error("No input files specified!\n");
535 if (!g_cOidNodes)
536 return error("No OID found!\n");
537 if (fVerbose)
538 printf("debug: %u nodes with strings; %u nodes without strings; %u nodes in total;\n"
539 "debug: max %u children; %u nodes with 6-bit keys (%u others)\n",
540 g_cOidNodesWithStrings, g_cOidNodes - g_cOidNodesWithStrings, g_cOidNodes,
541 g_cMaxOidChildren, g_cOidNodiesWith6bitKeys, g_cOidNodes - g_cOidNodiesWith6bitKeys);
542
543 /*
544 * Compile the string table.
545 */
546 BLDPROGSTRTAB StrTab;
547 if (!BldProgStrTab_Init(&StrTab, g_cOidNodesWithStrings))
548 return error("Out of memory!\n");
549
550 addStringFromOidTree(g_pOidRoot, &StrTab);
551
552 if (!BldProgStrTab_CompileIt(&StrTab, fVerbose))
553 return error("BldProgStrTab_CompileIt failed!\n");
554
555 /*
556 * Open the output file and write out the stuff.
557 */
558 FILE *pOut;
559 if (!strcmp(pszOutFile, "-"))
560 pOut = stdout;
561 else
562 pOut = fopen(pszOutFile, "w");
563 if (!pOut)
564 return error("opening '%s' for writing.\n", pszOutFile);
565
566 /* Write the string table. */
567 BldProgStrTab_WriteStringTable(&StrTab, pOut, "static ", "g_", "OidDbStrTab");
568
569 prepareOidTreeForWriting(g_pOidRoot, 0, false /*fBigTable*/);
570 prepareOidTreeForWriting(g_pOidRoot, 0, true /*fBigTable*/);
571
572 fprintf(pOut,
573 "\n"
574 "#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)\n"
575 "# pragma pack(2)\n"
576 "#endif\n"
577 "typedef struct RTOIDENTRYSMALL\n"
578 "{\n"
579 " uint32_t uKey : 6;\n"
580 " uint32_t cchString : 6;\n"
581 " uint32_t fBigTable : 1;\n"
582 " uint32_t cChildren : 7;\n"
583 " uint32_t idxChildren : 12;\n"
584 " uint16_t offString;\n"
585 "} RTOIDENTRYSMALL;\n"
586 "#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)\n"
587 "# pragma pack()\n"
588 "AssertCompileSize(RTOIDENTRYSMALL, 6);\n"
589 "#endif\n"
590 "typedef RTOIDENTRYSMALL const *PCRTOIDENTRYSMALL;\n"
591 "\n"
592 "static const RTOIDENTRYSMALL g_aSmallOidTable[] = \n{\n");
593 writeOidTree(g_pOidRoot, pOut, false /*fBigTable*/, &StrTab);
594 fprintf(pOut, "};\n");
595
596 fprintf(pOut,
597 "\n"
598 "#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)\n"
599 "# pragma pack(2)\n"
600 "#endif\n"
601 "typedef struct RTOIDENTRYBIG\n"
602 "{\n"
603 " uint32_t uKey;\n"
604 " uint8_t cchString;\n"
605 " uint8_t fBigTable : 1;\n"
606 " uint8_t cChildren : 7;\n"
607 " uint16_t idxChildren;\n"
608 " uint16_t offString;\n"
609 "} RTOIDENTRYBIG;\n"
610 "#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)\n"
611 "# pragma pack()\n"
612 "AssertCompileSize(RTOIDENTRYBIG, 10);\n"
613 "#endif\n"
614 "typedef RTOIDENTRYBIG const *PCRTOIDENTRYBIG;\n"
615 "\n"
616 "static const RTOIDENTRYBIG g_aBigOidTable[] = \n{\n");
617 writeOidTree(g_pOidRoot, pOut, true /*fBigTable*/, &StrTab);
618 fprintf(pOut, "};\n");
619
620 /* Carefully close the output file. */
621 if (ferror(pOut))
622 return error("problem writing '%s'!\n", pszOutFile);
623 if (fclose(pOut) != 0)
624 return error("closing '%s' after writing it.\n", pszOutFile);
625
626 return RTEXITCODE_SUCCESS;
627}
628
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