Changeset 59733 in vbox for trunk/src/VBox/Main
- Timestamp:
- Feb 19, 2016 1:42:18 AM (9 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/include/USBIdDatabase.h
r58019 r59733 22 22 #include <iprt/stdint.h> 23 23 #include <iprt/cpp/ministring.h> 24 #include <iprt/bldprog-strtab.h> 24 25 25 26 … … 31 32 32 33 33 /** 34 * USB ID database string table reference. 35 */ 36 typedef struct USBIDDBSTR 37 { 38 /** Offset of the string in the string table. */ 39 uint32_t off : 22; 40 /** The length of the string. */ 41 uint32_t cch : 10; 42 } USBIDDBSTR; 43 AssertCompileSize(USBIDDBSTR, sizeof(uint32_t)); 34 AssertCompileSize(RTBLDPROGSTRREF, sizeof(uint32_t)); 44 35 45 36 … … 76 67 { 77 68 public: // For assertions and statis in the generator. 78 /** String table. */ 79 static const char s_achStrTab[]; 80 /** The size of the string table (for bounds checking). */ 81 static const size_t s_cchStrTab; 82 #ifdef USB_ID_DATABASE_WITH_COMPRESSION 83 /** Dictionary containing the 127 most used substrings (that we managed 84 * to detect without lousy word based searching). */ 85 static const USBIDDBSTR s_aCompDict[127]; 86 #endif 69 /** The compressed string table. */ 70 static RTBLDPROGSTRTAB const s_StrTab; 87 71 88 72 /** Number of vendors in the two parallel arrays. */ 89 static const size_t s_cVendors;73 static const size_t s_cVendors; 90 74 /** Vendor IDs lookup table. */ 91 static const USBIDDBVENDOR s_aVendors[];75 static const USBIDDBVENDOR s_aVendors[]; 92 76 /** Vendor names table running parallel to s_aVendors. */ 93 static const USBIDDBSTRs_aVendorNames[];77 static const RTBLDPROGSTRREF s_aVendorNames[]; 94 78 95 79 /** Number of products in the two parallel arrays. */ 96 static const size_t s_cProducts;80 static const size_t s_cProducts; 97 81 /** Vendor+Product keys for lookup purposes. */ 98 static const USBIDDBPROD s_aProducts[];82 static const USBIDDBPROD s_aProducts[]; 99 83 /** Product names table running parallel to s_aProducts. */ 100 static const USBIDDBSTRs_aProductNames[];84 static const RTBLDPROGSTRREF s_aProductNames[]; 101 85 102 86 public: 103 static RTCString returnString(USBIDDBSTR const *pStr) 104 { 105 Assert(pStr->cch < s_cchStrTab); 106 Assert(pStr->off < s_cchStrTab); 107 Assert(pStr->off + (size_t)pStr->cch < s_cchStrTab); 108 109 #ifdef USB_ID_DATABASE_WITH_COMPRESSION 110 char szTmp[USB_ID_DATABASE_MAX_STRING * 2]; 111 char *pchDst = &szTmp[0]; 112 size_t cchSrc = pStr->cch; 113 const char *pchSrc = &s_achStrTab[pStr->off]; 114 Assert(cchSrc <= USB_ID_DATABASE_MAX_STRING); 115 while (cchSrc-- > 0) 116 { 117 unsigned char uch = *pchSrc++; 118 if (!(uch & 0x80)) 119 { 120 *pchDst++ = (char)uch; 121 Assert(uch != 0); 122 Assert((uintptr_t)(pchDst - &szTmp[0]) < USB_ID_DATABASE_MAX_STRING); 123 } 124 else if (uch == 0xff) 125 { 126 RTUNICP uc = ' '; 127 int rc = RTStrGetCpNEx(&pchSrc, &cchSrc, &uc); 128 AssertStmt(RT_SUCCESS(rc), (uc = '?', pchSrc++, cchSrc--)); 129 pchDst = RTStrPutCp(pchDst, uc); 130 Assert((uintptr_t)(pchDst - &szTmp[0]) < USB_ID_DATABASE_MAX_STRING); 131 } 132 else 133 { 134 /* Dictionary reference. No unescaping necessary here. */ 135 const USBIDDBSTR *pStr2 = &s_aCompDict[uch & 0x7f]; 136 Assert(pStr2->cch < s_cchStrTab); 137 Assert(pStr2->off < s_cchStrTab); 138 Assert(pStr2->off + (size_t)pStr->cch < s_cchStrTab); 139 Assert((uintptr_t)(&pchDst[pStr2->cch] - &szTmp[0]) < USB_ID_DATABASE_MAX_STRING); 140 memcpy(pchDst, &s_achStrTab[pStr2->off], pStr2->cch); 141 pchDst += pStr2->cch; 142 } 143 } 144 *pchDst = '\0'; 145 return RTCString(szTmp, pchDst - &szTmp[0]); 146 #else /* !USB_ID_DATABASE_WITH_COMPRESSION */ 147 return RTCString(&s_achStrTab[pStr->off], pStr->cch); 148 #endif /* !USB_ID_DATABASE_WITH_COMPRESSION */ 87 static RTCString returnString(PCRTBLDPROGSTRREF pStr) 88 { 89 char szTmp[USB_ID_DATABASE_MAX_STRING * 2]; 90 ssize_t cchTmp = RTBldProgStrTabQueryString(&s_StrTab, pStr->off, pStr->cch, szTmp, sizeof(szTmp)); 91 return RTCString(szTmp, RT_MAX(cchTmp, 0)); 149 92 } 150 93 -
trunk/src/VBox/Main/src-server/USBIdDatabaseGenerator.cpp
r58020 r59733 5 5 6 6 /* 7 * Copyright (C) 2015 Oracle Corporation7 * Copyright (C) 2015-2016 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 16 16 */ 17 17 18 18 19 /********************************************************************************************************************************* 19 20 * Header Files * … … 33 34 #include <iprt/string.h> 34 35 #include <iprt/stream.h> 35 #include "../../Runtime/include/internal/strhash.h" /** @todo make this one public */36 36 37 37 #include "../include/USBIdDatabase.h" 38 38 39 39 40 /* 41 * Include the string table generator. 42 */ 43 #define BLDPROG_STRTAB_MAX_STRLEN (USB_ID_DATABASE_MAX_STRING - 1) 44 #ifdef USB_ID_DATABASE_WITH_COMPRESSION 45 # define BLDPROG_STRTAB_WITH_COMPRESSION 46 #else 47 # undef BLDPROG_STRTAB_WITH_COMPRESSION 48 #endif 49 #define BLDPROG_STRTAB_WITH_CAMEL_WORDS 50 #undef BLDPROG_STRTAB_PURE_ASCII 51 #include <iprt/bldprog-strtab-template.cpp.h> 52 53 54 55 /********************************************************************************************************************************* 56 * Global Variables * 57 *********************************************************************************************************************************/ 40 58 /** For verbose output. */ 41 59 static bool g_fVerbose = false; … … 52 70 "\n" 53 71 "/*\n" 54 " * Copyright (C) 2015 Oracle Corporation\n"72 " * Copyright (C) 2015-2016 Oracle Corporation\n" 55 73 " *\n" 56 74 " * This file is part of VirtualBox Open Source Edition(OSE), as\n" … … 74 92 "USBIDDBPROD const USBIdDatabase::s_aProducts[] =\n" 75 93 "{\n"; 76 const char * product_part2 =94 const char * const product_part2 = 77 95 "};\n" 78 96 "\n" 79 "\nconst USBIDDBSTRUSBIdDatabase::s_aProductNames[] =\n"97 "\nconst RTBLDPROGSTRREF USBIdDatabase::s_aProductNames[] =\n" 80 98 "{\n"; 81 const char * product_footer =99 const char * const product_footer = 82 100 "};\n" 83 101 "\n" 84 102 "const size_t USBIdDatabase::s_cProducts = RT_ELEMENTS(USBIdDatabase::s_aProducts);\n"; 85 103 86 const char * vendor_header =104 const char * const vendor_header = 87 105 "\nUSBIDDBVENDOR const USBIdDatabase::s_aVendors[] =\n" 88 106 "{\n"; 89 const char * vendor_part2 =107 const char * const vendor_part2 = 90 108 "};\n" 91 109 "\n" 92 "\nconst USBIDDBSTRUSBIdDatabase::s_aVendorNames[] =\n"110 "\nconst RTBLDPROGSTRREF USBIdDatabase::s_aVendorNames[] =\n" 93 111 "{\n"; 94 const char * vendor_footer =112 const char * const vendor_footer = 95 113 "};\n" 96 114 "\n" 97 115 "const size_t USBIdDatabase::s_cVendors = RT_ELEMENTS(USBIdDatabase::s_aVendors);\n"; 98 116 99 const char *start_block = "# Vendors, devices and interfaces. Please keep sorted."; 100 const char *end_block = "# List of known device classes, subclasses and protocols"; 101 102 117 const char * const start_block = "# Vendors, devices and interfaces. Please keep sorted."; 118 const char * const end_block = "# List of known device classes, subclasses and protocols"; 119 120 121 /********************************************************************************************************************************* 122 * Defined Constants And Macros * 123 *********************************************************************************************************************************/ 103 124 // error codes (complements RTEXITCODE_XXX). 104 125 #define ERROR_OPEN_FILE (12) … … 109 130 110 131 111 /** 112 * String that will end up in the string table. 113 */ 114 struct StrTabString 115 { 116 /** The string. */ 117 std::string str; 118 /** The string hash value. */ 119 uint32_t uHash; 120 /** The string table reference. */ 121 USBIDDBSTR StrRef; 122 /** Pointer to the next string reference (same string table entry). */ 123 struct StrTabString *pNextRef; 124 /** Pointer to the next string with the same hash value (collision). */ 125 struct StrTabString *pNextCollision; 126 127 void printRef(ostream &rStrm) const 128 { 129 rStrm << " { 0x" << setfill('0') << setw(6) << hex << StrRef.off << ", 0x" 130 << setfill('0') << setw(2) << hex << StrRef.cch << " }, "; 131 } 132 133 void printRefLine(ostream &rStrm) const 134 { 135 printRef(rStrm); 136 rStrm << endl; 137 } 138 }; 139 typedef struct StrTabString *PSTRTABSTRING; 140 132 /********************************************************************************************************************************* 133 * Structures and Typedefs * 134 *********************************************************************************************************************************/ 141 135 struct VendorRecord 142 136 { … … 144 138 size_t iProduct; 145 139 size_t cProducts; 146 StrTabString vendor; 140 std::string str; 141 BLDPROGSTRING StrRef; 147 142 }; 148 143 … … 152 147 size_t vendorID; 153 148 size_t productID; 154 StrTabString product; 149 std::string str; 150 BLDPROGSTRING StrRef; 155 151 }; 156 152 157 bool operator < (const ProductRecord& lh, const ProductRecord& rh)158 {159 return lh.key < rh.key;160 }161 162 bool operator < (const VendorRecord& lh, const VendorRecord& rh)163 {164 return lh.vendorID < rh.vendorID;165 }166 167 bool operator == (const ProductRecord& lh, const ProductRecord& rh)168 {169 return lh.key == rh.key;170 }171 172 bool operator == (const VendorRecord& lh, const VendorRecord& rh)173 {174 return lh.vendorID == rh.vendorID;175 }176 177 ostream& operator <<(ostream& stream, const ProductRecord product)178 {179 stream << " { 0x" << setfill('0') << setw(4) << product.productID << " }, " << endl;180 return stream;181 }182 183 ostream& operator <<(ostream& stream, const VendorRecord vendor)184 {185 stream << " { 0x" << setfill('0') << setw(4) << hex << vendor.vendorID186 << ", 0x" << setfill('0') << setw(4) << hex << vendor.iProduct187 << ", 0x" << setfill('0') << setw(4) << hex << vendor.cProducts << " }, " << endl;188 return stream;189 }190 153 191 154 namespace State … … 202 165 typedef vector<ProductRecord> ProductsSet; 203 166 typedef vector<VendorRecord> VendorsSet; 167 168 169 /********************************************************************************************************************************* 170 * Global Variables * 171 *********************************************************************************************************************************/ 204 172 ProductsSet g_products; 205 173 VendorsSet g_vendors; 206 174 207 208 209 /* 210 * String "compression". We replace the 127 most used words with references. 211 */ 212 #ifdef USB_ID_DATABASE_WITH_COMPRESSION 213 214 typedef std::map<std::string, size_t> WORDFREQMAP; 215 typedef WORDFREQMAP::value_type WORDFREQPAIR; 216 217 /** The 127 words we've picked to be indexed by reference. */ 218 static StrTabString g_aCompDict[127]; 219 220 /** 221 * For sorting the frequency fidning in descending order. 222 * 223 * Comparison operators are put outside to make older gcc versions (like 4.1.1 224 * on lnx64-rel) happy. 225 */ 226 class WordFreqSortEntry 227 { 228 public: 229 WORDFREQPAIR const *m_pPair; 230 231 public: 232 WordFreqSortEntry(WORDFREQPAIR const *pPair) : m_pPair(pPair) {} 233 }; 234 235 bool operator == (WordFreqSortEntry const &rLeft, WordFreqSortEntry const &rRight) 236 { 237 return rLeft.m_pPair->second == rRight.m_pPair->second; 238 } 239 240 bool operator < (WordFreqSortEntry const &rLeft, WordFreqSortEntry const &rRight) 241 { 242 return rLeft.m_pPair->second > rRight.m_pPair->second; 243 } 244 245 246 /** 247 * Replaces the dictionary words and escapes non-ascii chars in a string. 248 * 249 * @param pString The string to fixup. 250 * @param pcchOld The old string length is added to this (stats) 251 * @param pcchNew The new string length is added to this (stats) 252 */ 253 static void FixupString(std::string *pString, size_t *pcchOld, size_t *pcchNew) 254 { 255 char szNew[USB_ID_DATABASE_MAX_STRING * 2]; 256 char *pszDst = szNew; 257 const char *pszSrc = pString->c_str(); 258 const char *pszSrcEnd = strchr(pszSrc, '\0'); 259 260 *pcchOld += pszSrcEnd - pszSrc; 261 262 char ch; 263 while ((ch = *pszSrc) != '\0') 264 { 265 /* Spaces. */ 266 while (ch == ' ') 267 { 268 *pszDst++ = ' '; 269 ch = *++pszSrc; 270 } 271 if (!ch) 272 break; 273 274 /* Find the end of the current word. */ 275 size_t cchWord = 1; 276 while ((ch = pszSrc[cchWord]) != ' ' && ch != '\0') 277 cchWord++; 278 279 /* Check for g_aWord matches. */ 280 size_t cchMax = pszSrcEnd - pszSrc; 281 for (unsigned i = 0; i < RT_ELEMENTS(g_aCompDict); i++) 282 { 283 size_t cchLen = g_aCompDict[i].str.length(); 284 if ( cchLen >= cchWord 285 && cchLen <= cchMax 286 && g_aCompDict[i].str.compare(0, cchLen, pszSrc, cchLen) == 0) 287 { 288 *pszDst++ = (unsigned char)(0x80 | i); 289 pszSrc += cchLen; 290 cchWord = 0; 291 break; 292 } 293 } 294 295 if (cchWord) 296 { 297 /* Copy the current word. */ 298 ch = *pszSrc; 299 do 300 { 301 if (!((unsigned char)ch & 0x80)) 302 { 303 *pszDst++ = ch; 304 pszSrc++; 305 } 306 else 307 { 308 RTUNICP uc; 309 int rc = RTStrGetCpEx(&pszSrc, &uc); 310 if (RT_SUCCESS(rc)) 311 { 312 *pszDst++ = (unsigned char)0xff; /* escape single code point. */ 313 pszDst = RTStrPutCp(pszDst, uc); 314 } 315 else 316 { 317 cerr << "Error: RTStrGetCpEx failed with rc=" << rc << endl; 318 exit(3); 319 } 320 } 321 } while ((ch = *pszSrc) != '\0' && ch != ' '); 322 } 323 } 324 *pszDst = '\0'; 325 *pcchNew += pszDst - &szNew[0]; 326 327 *pString = szNew; 328 } 329 330 331 /** 332 * Analyzes a string. 333 * 334 * @param pFrequencies The word frequency map. 335 * @param rString The string to analyze. 336 */ 337 static void AnalyzeString(WORDFREQMAP *pFrequencies, std::string const &rString) 338 { 339 const char *psz = rString.c_str(); 340 341 /* 342 * For now we just consider words. 343 */ 344 char ch; 345 while ((ch = *psz) != '\0') 346 { 347 /* Skip leading spaces. */ 348 while (ch == ' ') 349 ch = *++psz; 350 if (!ch) 351 return; 352 353 /* Find end of word. */ 354 size_t cchWord = 1; 355 while ((ch = psz[cchWord]) != ' ' && ch != '\0') 356 cchWord++; 357 if (cchWord > 1) 358 { 359 std::string strWord(psz, cchWord); 360 WORDFREQMAP::iterator it = pFrequencies->find(strWord); 361 if (it != pFrequencies->end()) 362 it->second += cchWord - 1; 363 else 364 (*pFrequencies)[strWord] = 0; 365 /** @todo could gain hits by including the space after the word, but that 366 * has the same accounting problems as the two words scenario below. */ 367 368 # if 0 /** @todo need better accounting for overlapping alternatives before this can be enabled. */ 369 /* Two words - immediate yields calc may lie when this enabled and we may pick the wrong words. */ 370 if (ch == ' ') 371 { 372 ch = psz[++cchWord]; 373 if (ch != ' ' && ch != '\0') 374 { 375 size_t const cchSaved = cchWord; 376 377 do 378 cchWord++; 379 while ((ch = psz[cchWord]) != ' ' && ch != '\0'); 380 381 strWord = std::string(psz, cchWord); 382 WORDFREQMAP::iterator it = pFrequencies->find(strWord); 383 if (it != pFrequencies->end()) 384 it->second += cchWord - 1; 385 else 386 (*pFrequencies)[strWord] = 0; 387 388 cchWord = cchSaved; 389 } 390 } 391 # endif 392 } 393 394 /* Advance. */ 395 psz += cchWord; 396 } 397 } 398 399 400 /** 401 * Compresses the vendor and product strings. 402 * 403 * This is very very simple (a lot less work that the string table for 404 * instance). 405 */ 406 static void DoStringCompression(void) 407 { 408 /* 409 * Analyze the strings collecting stats on potential sequences to replace. 410 */ 411 WORDFREQMAP Frequencies; 412 413 uint32_t cProducts = 0; 414 for (ProductsSet::iterator it = g_products.begin(); it != g_products.end(); ++it, cProducts++) 415 AnalyzeString(&Frequencies, it->product.str); 416 417 uint32_t cVendors = 0; 418 for (VendorsSet::iterator it = g_vendors.begin(); it != g_vendors.end(); ++it, cVendors++) 419 AnalyzeString(&Frequencies, it->vendor.str); 420 421 if (g_fVerbose) 422 { 423 size_t const cbVendorEntry = sizeof(USBIdDatabase::s_aVendors[0]) + sizeof(USBIdDatabase::s_aVendorNames[0]); 424 size_t const cbVendors = cVendors * cbVendorEntry; 425 cout << INFO_PREF << cVendors << " vendors (" << cbVendors << " bytes)" << endl; 426 427 size_t const cbProductEntry = sizeof(USBIdDatabase::s_aProducts[0]) + sizeof(USBIdDatabase::s_aProductNames[0]); 428 size_t const cbProducts = cProducts * cbProductEntry; 429 cout << INFO_PREF << cProducts << " products (" << cbProducts << " bytes)" << endl; 430 } 431 432 /* 433 * Sort the result and pick the top 127 ones. 434 */ 435 std::vector<WordFreqSortEntry> SortMap; 436 for (WORDFREQMAP::iterator it = Frequencies.begin(); it != Frequencies.end(); ++it) 437 { 438 WORDFREQPAIR const &rPair = *it; 439 SortMap.push_back(WordFreqSortEntry(&rPair)); 440 } 441 442 sort(SortMap.begin(), SortMap.end()); 443 444 size_t cb = 0; 445 unsigned i = 0; 446 for (std::vector<WordFreqSortEntry>::iterator it = SortMap.begin(); 447 it != SortMap.end() && i < RT_ELEMENTS(g_aCompDict); 448 ++it, i++) 449 { 450 g_aCompDict[i].str = it->m_pPair->first; 451 cb += it->m_pPair->second; 452 } 453 454 if (g_fVerbose) 455 cout << INFO_PREF "Estimated compression saving " << cb << " bytes" << endl; 456 457 /* 458 * Rework the strings. 459 */ 460 size_t cchNew = 0; 461 size_t cchOld = 0; 462 for (ProductsSet::iterator it = g_products.begin(); it != g_products.end(); ++it) 463 FixupString(&it->product.str, &cchOld, &cchNew); 464 for (VendorsSet::iterator it = g_vendors.begin(); it != g_vendors.end(); ++it) 465 FixupString(&it->vendor.str, &cchOld, &cchNew); 466 467 for (i = 0; i < RT_ELEMENTS(g_aCompDict); i++) 468 cchNew += g_aCompDict[i].str.length() + 1; 469 470 if (g_fVerbose) 471 { 472 cout << INFO_PREF "Strings: original: " << cchOld << " bytes; compressed: " << cchNew << " bytes;"; 473 if (cchNew < cchOld) 474 cout << " saving " << (cchOld - cchNew) << " bytes (" << ((cchOld - cchNew) * 100 / cchOld) << "%)" << endl; 475 else 476 cout << " wasting " << (cchOld - cchNew) << " bytes!" << endl; 477 cout << INFO_PREF "Average string length is " << (cchOld / (cVendors + cProducts)) << endl; 478 } 479 } 480 481 482 /** 483 * Writes the compression dictionary to the output stream. 484 * 485 * @param rStrm The output stream. 486 */ 487 static void WriteCompressionDictionary(ostream &rStrm) 488 { 489 rStrm << "const USBIDDBSTR USBIdDatabase::s_aCompDict[" << dec << RT_ELEMENTS(g_aCompDict) << "] = " << endl; 490 rStrm << "{" << endl; 491 for (unsigned i = 0; i < RT_ELEMENTS(g_aCompDict); i++) 492 { 493 g_aCompDict[i].printRef(rStrm); 494 rStrm << " // " << g_aCompDict[i].str << endl; 495 } 496 rStrm << "};" << endl << endl; 497 } 498 499 #endif /* USB_ID_DATABASE_WITH_COMPRESSION */ 500 501 502 /* 503 * Compile a string table. 504 */ 505 506 /** The size of g_papStrHash. */ 507 static size_t g_cStrHash = 0; 508 /** String hash table. */ 509 static PSTRTABSTRING *g_papStrHash = NULL; 510 /** Duplicate strings found by AddString. */ 511 static size_t g_cDuplicateStrings = 0; 512 /** Total length of the unique strings (no terminators). */ 513 static size_t g_cchUniqueStrings = 0; 514 /** Number of unique strings after AddString. */ 515 static size_t g_cUniqueStrings = 0; 516 /** Number of collisions. */ 517 static size_t g_cCollisions = 0; 518 519 /** Number of entries in g_apSortedStrings. */ 520 static size_t g_cSortedStrings = 0; 521 /** The sorted string table. */ 522 static PSTRTABSTRING *g_papSortedStrings = NULL; 523 524 /** The string table. */ 525 static char *g_pachStrTab = NULL; 526 /** The actual string table size. */ 527 static size_t g_cchStrTab = 0; 528 529 530 /** 531 * Adds a string to the hash table. 532 * @param pStr The string. 533 */ 534 static void AddString(PSTRTABSTRING pStr) 535 { 536 pStr->pNextRef = NULL; 537 pStr->pNextCollision = NULL; 538 pStr->StrRef.off = 0; 539 pStr->StrRef.cch = pStr->str.length(); 540 size_t cchIgnored; 541 pStr->uHash = sdbm(pStr->str.c_str(), &cchIgnored); 542 Assert(cchIgnored == pStr->str.length()); 543 544 size_t idxHash = pStr->uHash % g_cStrHash; 545 PSTRTABSTRING pCur = g_papStrHash[idxHash]; 546 if (!pCur) 547 g_papStrHash[idxHash] = pStr; 548 else 549 { 550 /* Look for matching string. */ 551 do 552 { 553 if ( pCur->uHash == pStr->uHash 554 && pCur->StrRef.cch == pStr->StrRef.cch 555 && pCur->str == pStr->str) 556 { 557 pStr->pNextRef = pCur->pNextRef; 558 pCur->pNextRef = pStr; 559 g_cDuplicateStrings++; 560 return; 561 } 562 pCur = pCur->pNextCollision; 563 } while (pCur != NULL); 564 565 /* No matching string, insert. */ 566 g_cCollisions++; 567 pStr->pNextCollision = g_papStrHash[idxHash]; 568 g_papStrHash[idxHash] = pStr; 569 } 570 571 g_cUniqueStrings++; 572 g_cchUniqueStrings += pStr->StrRef.cch; 573 } 574 575 576 /** 577 * Inserts a string into g_apUniqueStrings. 578 * @param pStr The string. 579 */ 580 static void InsertUniqueString(PSTRTABSTRING pStr) 581 { 582 size_t iIdx; 583 size_t iEnd = g_cSortedStrings; 584 if (iEnd) 585 { 586 size_t iStart = 0; 587 for (;;) 588 { 589 iIdx = iStart + (iEnd - iStart) / 2; 590 if (g_papSortedStrings[iIdx]->StrRef.cch < pStr->StrRef.cch) 591 { 592 if (iIdx <= iStart) 593 break; 594 iEnd = iIdx; 595 } 596 else if (g_papSortedStrings[iIdx]->StrRef.cch > pStr->StrRef.cch) 597 { 598 if (++iIdx >= iEnd) 599 break; 600 iStart = iIdx; 601 } 602 else 603 break; 604 } 605 606 if (iIdx != g_cSortedStrings) 607 memmove(&g_papSortedStrings[iIdx + 1], &g_papSortedStrings[iIdx], 608 (g_cSortedStrings - iIdx) * sizeof(g_papSortedStrings[iIdx])); 609 } 610 else 611 iIdx = 0; 612 613 g_papSortedStrings[iIdx] = pStr; 614 g_cSortedStrings++; 615 } 616 617 618 /** 619 * Creates a string table. 620 * 621 * This will save space by dropping string terminators, eliminating duplicates 622 * and try find strings that are sub-strings of others. 623 * 624 * Will initialize the StrRef of all StrTabString instances. 625 */ 626 static void CreateStringTable(void) 627 { 628 /* 629 * Allocate a hash table double the size of all strings (to avoid too 630 * many collisions). Add all strings to it, finding duplicates in the 631 * process. 632 */ 633 size_t cMaxStrings = g_products.size() + g_vendors.size(); 634 #ifdef USB_ID_DATABASE_WITH_COMPRESSION 635 cMaxStrings += RT_ELEMENTS(g_aCompDict); 636 #endif 637 cMaxStrings *= 2; 638 g_papStrHash = new PSTRTABSTRING[cMaxStrings]; 639 g_cStrHash = cMaxStrings; 640 memset(g_papStrHash, 0, cMaxStrings * sizeof(g_papStrHash[0])); 641 642 for (ProductsSet::iterator it = g_products.begin(); it != g_products.end(); ++it) 643 AddString(&it->product); 644 for (VendorsSet::iterator it = g_vendors.begin(); it != g_vendors.end(); ++it) 645 AddString(&it->vendor); 646 #ifdef USB_ID_DATABASE_WITH_COMPRESSION 647 for (unsigned i = 0; i < RT_ELEMENTS(g_aCompDict); i++) 648 AddString(&g_aCompDict[i]); 649 #endif 650 if (g_fVerbose) 651 cout << INFO_PREF "" << g_cUniqueStrings << " unique string (" << g_cchUniqueStrings << " bytes), " 652 << g_cDuplicateStrings << " duplicates, " << g_cCollisions << " collisions" << endl; 653 654 /* 655 * Create g_papSortedStrings from the hash table. The table is sorted by 656 * string length, with the longer strings first. 657 */ 658 g_papSortedStrings = new PSTRTABSTRING[g_cUniqueStrings]; 659 g_cSortedStrings = 0; 660 size_t idxHash = g_cStrHash; 661 while (idxHash-- > 0) 662 { 663 PSTRTABSTRING pCur = g_papStrHash[idxHash]; 664 if (pCur) 665 { 666 do 667 { 668 InsertUniqueString(pCur); 669 pCur = pCur->pNextCollision; 670 } while (pCur); 671 } 672 } 673 674 /* 675 * Create the actual string table. 676 */ 677 g_pachStrTab = new char [g_cchUniqueStrings + 1]; 678 g_cchStrTab = 0; 679 for (size_t i = 0; i < g_cSortedStrings; i++) 680 { 681 PSTRTABSTRING pCur = g_papSortedStrings[i]; 682 const char * const pszCur = pCur->str.c_str(); 683 size_t const cchCur = pCur->StrRef.cch; 684 size_t offStrTab = g_cchStrTab; 685 686 /* 687 * See if the string is a substring already found in the string table. 688 * Excluding the zero terminator increases the chances for this. 689 */ 690 size_t cchLeft = g_cchStrTab >= cchCur ? g_cchStrTab - cchCur : 0; 691 const char *pchLeft = g_pachStrTab; 692 char const chFirst = *pszCur; 693 while (cchLeft > 0) 694 { 695 const char *pchCandidate = (const char *)memchr(pchLeft, chFirst, cchLeft); 696 if (!pchCandidate) 697 break; 698 if (memcmp(pchCandidate, pszCur, cchCur) == 0) 699 { 700 offStrTab = pchCandidate - g_pachStrTab; 701 break; 702 } 703 704 cchLeft -= pchCandidate + 1 - pchLeft; 705 pchLeft = pchCandidate + 1; 706 } 707 708 if (offStrTab == g_cchStrTab) 709 { 710 /* 711 * See if the start of the string overlaps the end of the string table. 712 */ 713 if (g_cchStrTab && cchCur > 1) 714 { 715 cchLeft = RT_MIN(g_cchStrTab, cchCur - 1); 716 pchLeft = &g_pachStrTab[g_cchStrTab - cchLeft]; 717 while (cchLeft > 0) 718 { 719 const char *pchCandidate = (const char *)memchr(pchLeft, chFirst, cchLeft); 720 if (!pchCandidate) 721 break; 722 cchLeft -= pchCandidate - pchLeft; 723 pchLeft = pchCandidate; 724 if (memcmp(pchLeft, pszCur, cchLeft) == 0) 725 { 726 size_t cchToCopy = cchCur - cchLeft; 727 memcpy(&g_pachStrTab[offStrTab], &pszCur[cchLeft], cchToCopy); 728 g_cchStrTab += cchToCopy; 729 offStrTab = pchCandidate - g_pachStrTab; 730 break; 731 } 732 cchLeft--; 733 pchLeft++; 734 } 735 } 736 737 /* 738 * If we didn't have any luck above, just append the string. 739 */ 740 if (offStrTab == g_cchStrTab) 741 { 742 memcpy(&g_pachStrTab[offStrTab], pszCur, cchCur); 743 g_cchStrTab += cchCur; 744 } 745 } 746 747 /* 748 * Set the string table offset for all the references to this string. 749 */ 750 do 751 { 752 pCur->StrRef.off = (uint32_t)offStrTab; 753 pCur = pCur->pNextRef; 754 } while (pCur != NULL); 755 } 756 757 if (g_fVerbose) 758 cout << INFO_PREF "String table: " << g_cchStrTab << " bytes" << endl; 759 } 760 761 762 #ifdef VBOX_STRICT 763 /** 764 * Sanity checks a string table string. 765 * @param pStr The string to check. 766 */ 767 static void CheckStrTabString(PSTRTABSTRING pStr) 768 { 769 Assert(pStr->StrRef.cch == pStr->str.length()); 770 Assert(pStr->StrRef.off < g_cchStrTab); 771 Assert(pStr->StrRef.off + pStr->StrRef.cch <= g_cchStrTab); 772 Assert(memcmp(pStr->str.c_str(), &g_pachStrTab[pStr->StrRef.off], pStr->str.length()) == 0); 773 } 774 #endif 775 776 777 /** 778 * Writes the string table code to the output stream. 779 * 780 * @param rStrm The output stream. 781 */ 782 static void WriteStringTable(ostream &rStrm) 783 { 784 #ifdef VBOX_STRICT 785 /* 786 * Do some quick sanity checks while we're here. 787 */ 788 for (ProductsSet::iterator it = g_products.begin(); it != g_products.end(); ++it) 789 CheckStrTabString(&it->product); 790 for (VendorsSet::iterator it = g_vendors.begin(); it != g_vendors.end(); ++it) 791 CheckStrTabString(&it->vendor); 792 # ifdef USB_ID_DATABASE_WITH_COMPRESSION 793 for (unsigned i = 0; i < RT_ELEMENTS(g_aCompDict); i++) 794 CheckStrTabString(&g_aCompDict[i]); 795 # endif 796 #endif 797 798 /* 799 * Create a table for speeding up the character categorization. 800 */ 801 uint8_t abCharCat[256]; 802 RT_ZERO(abCharCat); 803 abCharCat[(unsigned char)'\\'] = 1; 804 abCharCat[(unsigned char)'\''] = 1; 805 for (unsigned i = 0; i < 0x20; i++) 806 abCharCat[i] = 2; 807 for (unsigned i = 0x7f; i < 0x100; i++) 808 abCharCat[i] = 2; 809 810 /* 811 * We follow the sorted string table, one string per line. 812 */ 813 rStrm << endl; 814 rStrm << "const size_t USBIdDatabase::s_cchStrTab = " << g_cchStrTab << ";" << endl; 815 rStrm << "const char USBIdDatabase::s_achStrTab[] =" << endl; 816 rStrm << "{" << endl; 817 818 uint32_t off = 0; 819 for (uint32_t i = 0; i < g_cSortedStrings; i++) 820 { 821 PSTRTABSTRING pCur = g_papSortedStrings[i]; 822 uint32_t offEnd = pCur->StrRef.off + pCur->StrRef.cch; 823 if (offEnd > off) 824 { 825 /* Comment with a more readable version of the string. */ 826 if (off == pCur->StrRef.off) 827 rStrm << " /* 0x"; 828 else 829 rStrm << " /* 0X"; 830 rStrm << hex << setfill('0') << setw(5) << off << " = \""; 831 for (uint32_t offTmp = off; offTmp < offEnd; offTmp++) 832 { 833 unsigned char uch = g_pachStrTab[offTmp]; 834 if (abCharCat[uch] == 0) 835 rStrm << (char)uch; 836 else if (abCharCat[uch] != 1) 837 rStrm << "\\x" << setw(2) << hex << (size_t)uch; 838 else 839 rStrm << "\\" << (char)uch; 840 } 841 rStrm << "\" */" << endl; 842 843 /* Must use char by char here or we may trigger the max string 844 length limit in the compiler, */ 845 rStrm << " "; 846 for (; off < offEnd; off++) 847 { 848 unsigned char uch = g_pachStrTab[off]; 849 rStrm << "'"; 850 if (abCharCat[uch] == 0) 851 rStrm << (char)uch; 852 else if (abCharCat[uch] != 1) 853 rStrm << "\\x" << setw(2) << hex << (size_t)uch; 854 else 855 rStrm << "\\" << (char)uch; 856 rStrm << "',"; 857 } 858 rStrm << endl; 859 } 860 } 861 862 rStrm << "};" << endl; 863 rStrm << "AssertCompile(sizeof(USBIdDatabase::s_achStrTab) == 0x" << hex << g_cchStrTab << ");" << endl << endl; 175 /** The size of all the raw strings, including terminators. */ 176 static size_t g_cbRawStrings = 0; 177 178 179 180 bool operator < (const ProductRecord& lh, const ProductRecord& rh) 181 { 182 return lh.key < rh.key; 183 } 184 185 bool operator < (const VendorRecord& lh, const VendorRecord& rh) 186 { 187 return lh.vendorID < rh.vendorID; 188 } 189 190 bool operator == (const ProductRecord& lh, const ProductRecord& rh) 191 { 192 return lh.key == rh.key; 193 } 194 195 bool operator == (const VendorRecord& lh, const VendorRecord& rh) 196 { 197 return lh.vendorID == rh.vendorID; 864 198 } 865 199 … … 868 202 * Input file parsing. 869 203 */ 870 871 /** The size of all the raw strings, including terminators. */872 static size_t g_cbRawStrings = 0;873 874 204 int ParseAlias(const string& src, size_t& id, string& desc) 875 205 { … … 897 227 } 898 228 899 cerr << "Error: Invalid encoding: '" << desc << "' (rc=" << rc << ")" << endl;229 RTMsgError("Invalid encoding: '%s' (rc=%Rrc)", desc.c_str(), rc); 900 230 } 901 cerr << "Error: String to long (" << cchLength << ")" << endl; 231 else 232 RTMsgError("String to long: %zu", cchLength); 902 233 } 903 234 else 904 cerr << "Error: Error parsing \"" << src << "\"" << endl;235 RTMsgError("Error parsing '%s'", src.c_str()); 905 236 return ERROR_IN_PARSE_LINE; 906 237 } … … 923 254 return true; 924 255 } 925 else if (rc != VERR_EOF) 926 { 927 cerr << "Warning: Invalid line in file. Error: " << rc << endl; 928 } 256 257 if (rc != VERR_EOF) 258 RTMsgWarning("RTStrmGetLine failed: %Rrc", rc); 929 259 return false; 930 260 } … … 960 290 // first line should be vendor 961 291 if (vendor.vendorID == 0) 962 { 963 cerr << "Wrong file format. Product before vendor: " << line.c_str() << "'" << endl; 964 return ERROR_WRONG_FILE_FORMAT; 965 } 292 return RTMsgErrorExit((RTEXITCODE)ERROR_WRONG_FILE_FORMAT, 293 "Wrong file format. Product before vendor: '%s'", line.c_str()); 966 294 ProductRecord product = { 0, vendor.vendorID, 0, "" }; 967 if (ParseAlias(line.substr(1), product.productID, product.product.str) != 0) 968 { 969 cerr << "Error in parsing product line: '" << line.c_str() << "'" << endl; 970 return ERROR_IN_PARSE_LINE; 971 } 295 if (ParseAlias(line.substr(1), product.productID, product.str) != 0) 296 return RTMsgErrorExit((RTEXITCODE)ERROR_IN_PARSE_LINE, 297 "Error in parsing product line: '", line.c_str()); 972 298 product.key = RT_MAKE_U32(product.productID, product.vendorID); 973 299 Assert(product.vendorID == vendor.vendorID); … … 977 303 { 978 304 // Parse vendor line 979 if (ParseAlias(line, vendor.vendorID, vendor.vendor.str) != 0) 980 { 981 cerr << "Error in parsing vendor line: '" 982 << line.c_str() << "'" << endl; 983 return ERROR_IN_PARSE_LINE; 984 } 305 if (ParseAlias(line, vendor.vendorID, vendor.str) != 0) 306 return RTMsgErrorExit((RTEXITCODE)ERROR_IN_PARSE_LINE, 307 "Error in parsing vendor line: '", line.c_str()); 985 308 g_vendors.push_back(vendor); 986 309 } … … 992 315 } 993 316 if (state == State::lookForStartBlock) 994 { 995 cerr << "Error: wrong format of input file. Start line is not found." << endl; 996 return ERROR_WRONG_FILE_FORMAT; 997 } 317 return RTMsgErrorExit((RTEXITCODE)ERROR_WRONG_FILE_FORMAT, 318 "wrong format of input file. Start line is not found."); 998 319 return 0; 999 320 } 1000 321 1001 322 1002 static int usage(ostream &rOut, const char *argv0) 1003 { 1004 rOut << "Usage: " << argv0 1005 << " [linux.org usb list file] [custom usb list file] [-o output file]" << endl; 323 static int usage(FILE *pOut, const char *argv0) 324 { 325 fprintf(pOut, "Usage: %s [linux.org usb list file] [custom usb list file] [-o output file]\n", argv0); 1006 326 return RTEXITCODE_SYNTAX; 1007 327 } 328 1008 329 1009 330 int main(int argc, char *argv[]) … … 1021 342 if (argc < 4) 1022 343 { 1023 usage(cerr, argv[0]); 1024 cerr << "Error: Not enough arguments." << endl; 1025 return RTEXITCODE_SYNTAX; 1026 } 1027 ofstream fout; 1028 PRTSTREAM fin; 344 usage(stderr, argv[0]); 345 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Insufficient arguments."); 346 } 1029 347 g_products.reserve(20000); 1030 348 g_vendors.reserve(3500); 1031 349 1032 const char * outName = NULL;350 const char *pszOutFile = NULL; 1033 351 for (int i = 1; i < argc; i++) 1034 352 { 1035 353 if (strcmp(argv[i], "-o") == 0) 1036 354 { 1037 outName = argv[++i];355 pszOutFile = argv[++i]; 1038 356 continue; 1039 357 } … … 1042 360 || strcmp(argv[i], "--help") == 0) 1043 361 { 1044 usage( cout, argv[0]);362 usage(stdout, argv[0]); 1045 363 return RTEXITCODE_SUCCESS; 1046 364 } 1047 365 1048 rc = RTStrmOpen(argv[i], "r", &fin); 366 PRTSTREAM pInStrm; 367 rc = RTStrmOpen(argv[i], "r", &pInStrm); 1049 368 if (RT_FAILURE(rc)) 1050 { 1051 cerr << "Error: Failed to open file '" << argv[i] << "' for reading. rc=" << rc << endl; 1052 return ERROR_OPEN_FILE; 1053 } 1054 1055 rc = ParseUsbIds(fin); 369 return RTMsgErrorExit((RTEXITCODE)ERROR_OPEN_FILE, 370 "Failed to open file '%s' for reading: %Rrc", argv[i], rc); 371 372 rc = ParseUsbIds(pInStrm); 373 RTStrmClose(pInStrm); 1056 374 if (rc != 0) 1057 375 { 1058 cerr << "Error: Failed parsing USB devices file '" << argv[i] << "'" << endl; 1059 RTStrmClose(fin); 376 RTMsgError("Failed parsing USB devices file '%s'", argv[i]); 1060 377 return rc; 1061 378 } 1062 RTStrmClose(fin);1063 379 } 1064 380 … … 1068 384 */ 1069 385 if (g_products.size() > _64K) 1070 { 1071 cerr << "Error: More than 64K products is not supported (input: " << g_products.size() << ")" << endl; 1072 return ERROR_TOO_MANY_PRODUCTS; 1073 } 386 return RTMsgErrorExit((RTEXITCODE)ERROR_TOO_MANY_PRODUCTS, 387 "More than 64K products is not supported: %u products", g_products.size()); 1074 388 1075 389 /* … … 1093 407 && g_products[iProduct].vendorID == idVendor); 1094 408 else 1095 { 1096 cerr << "Error: product without vendor after sorting. impossible!" << endl; 1097 return ERROR_IN_PARSE_LINE; 1098 } 409 return RTMsgErrorExit((RTEXITCODE)ERROR_IN_PARSE_LINE, "product without vendor after sorting. impossible!"); 1099 410 } 1100 411 g_vendors[iVendor].cProducts = iProduct - g_vendors[iVendor].iProduct; … … 1106 417 ProductsSet::iterator ita = adjacent_find(g_products.begin(), g_products.end()); 1107 418 if (ita != g_products.end()) 1108 { 1109 cerr << "Error: Duplicate alias detected. " << *ita << endl; 1110 return ERROR_DUPLICATE_ENTRY; 1111 } 1112 1113 /* 419 return RTMsgErrorExit((RTEXITCODE)ERROR_DUPLICATE_ENTRY, "Duplicate alias detected: idProduct=%#06x", ita->productID); 420 421 /* 422 * Build the string table. 1114 423 * Do string compression and create the string table. 1115 424 */ 1116 #ifdef USB_ID_DATABASE_WITH_COMPRESSION 1117 DoStringCompression(); 1118 #endif 1119 CreateStringTable(); 425 BLDPROGSTRTAB StrTab; 426 if (!BldProgStrTab_Init(&StrTab, g_products.size() + g_vendors.size())) 427 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Out of memory!"); 428 429 for (ProductsSet::iterator it = g_products.begin(); it != g_products.end(); ++it) 430 { 431 it->StrRef.pszString = (char *)it->str.c_str(); 432 BldProgStrTab_AddString(&StrTab, &it->StrRef); 433 } 434 for (VendorsSet::iterator it = g_vendors.begin(); it != g_vendors.end(); ++it) 435 { 436 it->StrRef.pszString = (char *)it->str.c_str(); 437 BldProgStrTab_AddString(&StrTab, &it->StrRef); 438 } 439 440 if (!BldProgStrTab_CompileIt(&StrTab, g_fVerbose)) 441 return RTMsgErrorExit(RTEXITCODE_FAILURE, "BldProgStrTab_CompileIt failed!\n"); 1120 442 1121 443 /* … … 1127 449 size_t cbOldRaw = (g_products.size() + g_vendors.size()) * sizeof(const char *) * 2 + g_cbRawStrings; 1128 450 size_t cbRaw = g_vendors.size() * cbVendorEntry + g_products.size() * cbProductEntry + g_cbRawStrings; 1129 size_t cbActual = g_vendors.size() * cbVendorEntry + g_products.size() * cbProductEntry + g_cchStrTab;451 size_t cbActual = g_vendors.size() * cbVendorEntry + g_products.size() * cbProductEntry + StrTab.cchStrTab; 1130 452 #ifdef USB_ID_DATABASE_WITH_COMPRESSION 1131 cbActual += sizeof( USBIdDatabase::s_aCompDict);453 cbActual += sizeof(StrTab.aCompDict); 1132 454 #endif 1133 455 cout << INFO_PREF "Total " << dec << cbActual << " bytes"; … … 1143 465 * Produce the source file. 1144 466 */ 1145 if (!outName) 1146 { 1147 cerr << "Error: Output file is not specified." << endl; 1148 return ERROR_OPEN_FILE; 1149 } 1150 1151 fout.open(outName); 1152 if (!fout.is_open()) 1153 { 1154 cerr << "Error: Can not open file to write '" << outName << "'." << endl; 1155 return ERROR_OPEN_FILE; 1156 } 1157 1158 fout << header; 1159 1160 WriteStringTable(fout); 1161 #ifdef USB_ID_DATABASE_WITH_COMPRESSION 1162 WriteCompressionDictionary(fout); 1163 #endif 1164 1165 fout << product_header; 467 if (!pszOutFile) 468 return RTMsgErrorExit((RTEXITCODE)ERROR_OPEN_FILE, "Output file is not specified."); 469 470 FILE *pOut = fopen(pszOutFile, "w"); 471 if (!pOut) 472 return RTMsgErrorExit((RTEXITCODE)ERROR_OPEN_FILE, "Error opening '%s' for writing", pszOutFile); 473 474 fputs(header, pOut); 475 BldProgStrTab_WriteStringTable(&StrTab, pOut, "", "USBIdDatabase::s_", "StrTab"); 476 477 fputs(product_header, pOut); 1166 478 for (ProductsSet::iterator itp = g_products.begin(); itp != g_products.end(); ++itp) 1167 fout << *itp; 1168 fout << product_part2; 479 fprintf(pOut, " { 0x%04x },\n", itp->productID); 480 481 fputs(product_part2, pOut); 1169 482 for (ProductsSet::iterator itp = g_products.begin(); itp != g_products.end(); ++itp) 1170 itp->product.printRefLine(fout);1171 f out << product_footer;1172 1173 f out << vendor_header;483 fprintf(pOut, "{ 0x%06x, 0x%02x },\n", itp->StrRef.offStrTab, itp->StrRef.cchString); 484 fputs(product_footer, pOut); 485 486 fputs(vendor_header, pOut); 1174 487 for (VendorsSet::iterator itv = g_vendors.begin(); itv != g_vendors.end(); ++itv) 1175 f out << *itv;1176 f out << vendor_part2;488 fprintf(pOut, " { 0x%04x, 0x%04x, 0x%04x },\n", itv->vendorID, itv->iProduct, itv->cProducts); 489 fputs(vendor_part2, pOut); 1177 490 for (VendorsSet::iterator itv = g_vendors.begin(); itv != g_vendors.end(); ++itv) 1178 itv->vendor.printRefLine(fout); 1179 fout << vendor_footer; 1180 1181 fout.close(); 1182 491 fprintf(pOut, "{ 0x%06x, 0x%02x },\n", itv->StrRef.offStrTab, itv->StrRef.cchString); 492 fputs(vendor_footer, pOut); 493 494 if (ferror(pOut)) 495 return RTMsgErrorExit((RTEXITCODE)ERROR_OPEN_FILE, "Error writing '%s'!", pszOutFile); 496 if (fclose(pOut) != 0) 497 return RTMsgErrorExit((RTEXITCODE)ERROR_OPEN_FILE, "Error closing '%s'!", pszOutFile); 1183 498 1184 499 return RTEXITCODE_SUCCESS; -
trunk/src/VBox/Main/src-server/USBIdDatabaseStub.cpp
r58016 r59733 5 5 6 6 /* 7 * Copyright (C) 2015 Oracle Corporation7 * Copyright (C) 2015-2016 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 18 18 #include "USBIdDatabase.h" 19 19 20 const char USBIdDatabase::s_achStrTab[] = ""; 21 const size_t USBIdDatabase::s_cchStrTab = 0; 22 #ifdef USB_ID_DATABASE_WITH_COMPRESSION 23 const USBIDDBSTR USBIdDatabase::s_aCompDict[127]; 24 #endif 20 const RTBLDPROGSTRTAB USBIdDatabase::s_StrTab = { "", 0, 0 NULL }; 25 21 26 const size_t USBIdDatabase::s_cVendors = 0;27 const USBIDDBVENDOR USBIdDatabase::s_aVendors[] = { 0 };28 const USBIDDBSTRUSBIdDatabase::s_aVendorNames[] = { {0,0} };22 const size_t USBIdDatabase::s_cVendors = 0; 23 const USBIDDBVENDOR USBIdDatabase::s_aVendors[] = { 0 }; 24 const RTBLDPROGSTRREF USBIdDatabase::s_aVendorNames[] = { {0,0} }; 29 25 30 const size_t USBIdDatabase::s_cProducts = 0;31 const USBIDDBPROD USBIdDatabase::s_aProducts[] = { 0 };32 const USBIDDBSTRUSBIdDatabase::s_aProductNames[] = { {0,0} };26 const size_t USBIdDatabase::s_cProducts = 0; 27 const USBIDDBPROD USBIdDatabase::s_aProducts[] = { 0 }; 28 const RTBLDPROGSTRREF USBIdDatabase::s_aProductNames[] = { {0,0} }; 33 29
Note:
See TracChangeset
for help on using the changeset viewer.