VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/USBIdDatabaseGenerator.cpp@ 57649

Last change on this file since 57649 was 57649, checked in by vboxsync, 9 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.8 KB
Line 
1/*
2* Copyright (C) 2006-2015 Oracle Corporation
3*
4* This file is part of VirtualBox Open Source Edition (OSE), as
5* available from http://www.virtualbox.org. This file is free software;
6* you can redistribute it and/or modify it under the terms of the GNU
7* General Public License (GPL) as published by the Free Software
8* Foundation, in version 2 as it comes in the "COPYING" file of the
9* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
10* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
11*/
12
13#include <stdio.h>
14#include <fstream>
15#include <iostream>
16#include <iomanip>
17#include <algorithm>
18#include <vector>
19#include <string>
20
21#include <iprt/initterm.h>
22#include <iprt/message.h>
23#include <iprt/string.h>
24#include <iprt/stream.h>
25
26using namespace std;
27
28const char *header =
29 "/*\n"
30 " * Copyright(C) 2015 Oracle Corporation\n"
31 " *\n"
32 " * This file is part of VirtualBox Open Source Edition(OSE), as\n"
33 " * available from http ://www.virtualbox.org. This file is free software;\n"
34 " * you can redistribute it and / or modify it under the terms of the GNU\n"
35 " * General Public License(GPL) as published by the Free Software\n"
36 " * Foundation, in version 2 as it comes in the \"COPYING\" file of the\n"
37 " * VirtualBox OSE distribution.VirtualBox OSE is distributed in the\n"
38 " * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.\n"
39 " */"
40 "\n"
41 "\n"
42 "#include \"USBIdDatabase.h\"\n"
43 "\n"
44 "/**\n"
45 " * USB devices aliases array.\n"
46 " * Format: VendorId, ProductId, Vendor Name, Product Name\n"
47 " * The source of the list is http://www.linux-usb.org/usb.ids\n"
48 " */\n"
49 "Product AliasDictionary::productArray[] =\n"
50 "{\n";
51
52const char *footer =
53 "};\n"
54 "\n"
55 "const size_t AliasDictionary::cProducts = sizeof(AliasDictionary::productArray) / sizeof(Product);\n";
56
57const char *vendor_header =
58 "\nVendor AliasDictionary::vendorArray[] =\n"
59 "{\n";
60const char *vendor_footer =
61 "};\n"
62 "\n"
63 "const size_t AliasDictionary::cVendors = sizeof(AliasDictionary::vendorArray) / sizeof(Vendor);\n";
64
65const char *start_block = "# Vendors, devices and interfaces. Please keep sorted.";
66const char *end_block = "# List of known device classes, subclasses and protocols";
67
68#define USBKEY(vendorId, productId) (((vendorId) << 16) | (productId))
69
70// error codes
71#define ERROR_INVALID_ARGUMENTS (1)
72#define ERROR_OPEN_FILE (2)
73#define ERROR_IN_PARSE_LINE (3)
74#define ERROR_DUPLICATE_ENTRY (4)
75#define ERROR_WRONG_FILE_FORMAT (5)
76
77struct VendorRecord
78{
79 size_t vendorID;
80 string vendor;
81};
82
83struct ProductRecord
84{
85 size_t key;
86 size_t vendorID;
87 size_t productID;
88 string product;
89};
90
91bool operator < (const ProductRecord& lh, const ProductRecord& rh)
92{
93 return lh.key < rh.key;
94}
95
96bool operator < (const VendorRecord& lh, const VendorRecord& rh)
97{
98 return lh.vendorID < rh.vendorID;
99}
100
101bool operator == (const ProductRecord& lh, const ProductRecord& rh)
102{
103 return lh.key == rh.key;
104}
105
106bool operator == (const VendorRecord& lh, const VendorRecord& rh)
107{
108 return lh.vendorID == rh.vendorID;
109}
110
111string conv(const string& src)
112{
113 string res = src;
114 for (size_t i = 0; i < res.length(); ++i)
115 {
116 switch (res[i])
117 {
118 case '"':
119 case '\\': res.insert(i++, "\\"); break;
120 default:
121 {
122 if ((unsigned char)res[i] >= 127)
123 {
124 size_t start = i;
125 string temp = "\" \"";
126 char buffer[8] = { 0 };
127 do
128 {
129 RTStrPrintf(buffer, sizeof(buffer), "\\x%x", (unsigned char)res[i]);
130 temp.append(buffer);
131 } while ((unsigned char)res[++i] & 0x80);
132 temp.append("\" \"");
133 res.replace(start, i - start, temp);
134 i += temp.length();
135 }
136 }
137 }
138 }
139 return res;
140}
141
142ostream& operator <<(ostream& stream, const ProductRecord product)
143{
144 stream << " { USBKEY(0x" << setfill('0') << setw(4) << hex << product.vendorID
145 << ", 0x" << setfill('0') << setw(4) << product.productID << "), "
146 << "\"" << conv(product.product).c_str() << "\" }," << endl;
147 return stream;
148}
149
150ostream& operator <<(ostream& stream, const VendorRecord vendor)
151{
152 stream << " { 0x" << setfill('0') << setw(4) << hex << vendor.vendorID
153 << ", \"" << conv(vendor.vendor).c_str() << "\" }," << endl;
154 return stream;
155}
156
157namespace State
158{
159 typedef int Value;
160 enum
161 {
162 lookForStartBlock,
163 lookForEndBlock,
164 finished
165 };
166}
167
168typedef vector<ProductRecord> ProductsSet;
169typedef vector<VendorRecord> VendorsSet;
170ProductsSet g_products;
171VendorsSet g_vendors;
172
173
174int ParseAlias(const string& src, size_t& id, string& desc)
175{
176 unsigned int i = 0;
177 int idx = 0;
178 string sin;
179
180 if (sscanf(src.c_str(), "%x", &i) != 1)
181 return ERROR_IN_PARSE_LINE;
182
183 size_t index = src.find_first_of(" \t", 1);
184 index = src.find_first_not_of(" \t", index);
185
186 if (index == string::npos)
187 return ERROR_IN_PARSE_LINE;
188
189 sin = src.substr(index);
190 id = i;
191 desc = sin;
192
193 return 0;
194}
195
196bool IsCommentOrEmptyLine(const string& str)
197{
198 size_t index = str.find_first_not_of(" \t");// skip left spaces
199 return index == string::npos || str[index] == '#';
200}
201
202bool getline(PRTSTREAM instream, string& resString)
203{
204 const size_t szBuf = 4096;
205 char buf[szBuf] = { 0 };
206
207 int rc = RTStrmGetLine(instream, buf, szBuf);
208 if (RT_SUCCESS(rc))
209 {
210 resString = buf;
211 return true;
212 }
213 else if (rc != VERR_EOF)
214 {
215 cerr << "Warning: Invalid line in file. Error: " << hex << rc << endl;
216 }
217 return false;
218}
219
220int ParseUsbIds(PRTSTREAM instream)
221{
222 State::Value state = State::lookForStartBlock;
223 string line;
224 int res = 0;
225 VendorRecord vendor = { 0, "" };
226
227 while (state != State::finished && getline(instream, line))
228 {
229 switch (state)
230 {
231 case State::lookForStartBlock:
232 {
233 if (line.find(start_block) != string::npos)
234 state = State::lookForEndBlock;
235 break;
236 }
237 case State::lookForEndBlock:
238 {
239 if (line.find(end_block) != string::npos)
240 state = State::finished;
241 else
242 {
243 if (!IsCommentOrEmptyLine(line))
244 {
245 if (line[0] == '\t')
246 {
247 // Parse Product line
248 // first line should be vendor
249 if (vendor.vendorID == 0)
250 {
251 cerr << "Wrong file format. Product before vendor: "
252 << line.c_str() << "'" << endl;
253 return ERROR_WRONG_FILE_FORMAT;
254 }
255 ProductRecord product = { 0, vendor.vendorID, 0, "" };
256 if (ParseAlias(line.substr(1), product.productID, product.product) != 0)
257 {
258 cerr << "Error in parsing product line: '"
259 << line.c_str() << "'" << endl;
260 return ERROR_IN_PARSE_LINE;
261 }
262 product.key = USBKEY(product.vendorID, product.productID);
263 Assert(product.vendorID != 0);
264 g_products.push_back(product);
265 }
266 else
267 {
268 // Parse vendor line
269 if (ParseAlias(line, vendor.vendorID, vendor.vendor) != 0)
270 {
271 cerr << "Error in parsing vendor line: '"
272 << line.c_str() << "'" << endl;
273 return ERROR_IN_PARSE_LINE;
274 }
275 g_vendors.push_back(vendor);
276 }
277 }
278 }
279 break;
280 }
281 }
282 }
283 if (state == State::lookForStartBlock)
284 {
285 cerr << "Error: wrong format of input file. Start line is not found." << endl;
286 return ERROR_WRONG_FILE_FORMAT;
287 }
288 return 0;
289}
290
291int main(int argc, char* argv[])
292{
293 int rc = RTR3InitExe(argc, &argv, 0);
294 if (RT_FAILURE(rc))
295 return RTMsgInitFailure(rc);
296
297 if (argc < 4)
298 {
299 cerr << "Format: " << argv[0] <<
300 " [linux.org usb list file] [custom usb list file] [-o output file]" << endl;
301 cerr << "Error: Invalid arguments." << endl;
302 return ERROR_INVALID_ARGUMENTS;
303 }
304 ofstream fout;
305 PRTSTREAM fin;
306 g_products.reserve(20000);
307 g_vendors.reserve(3500);
308
309 char* outName = NULL;
310 rc = 0;
311 for (int i = 1; i < argc; i++)
312 {
313 if (strcmp(argv[i], "-o") == 0)
314 {
315 outName = argv[++i];
316 continue;
317 }
318
319 if (RT_FAILURE(rc = RTStrmOpen(argv[i], "r", &fin)))
320 {
321 cerr << "Format: " << argv[0] <<
322 " [linux.org usb list file] [custom usb list file] [-o output file]" << endl;
323 cerr << "Error: Can not open file '" << argv[i] << "'. Error: " << hex << rc << endl;
324 return ERROR_OPEN_FILE;
325 }
326
327 int res = ParseUsbIds(fin);
328 if (res != 0)
329 {
330 cerr << "Error in parsing USB devices file '" <<
331 argv[i] << "'" << endl;
332 RTStrmClose(fin);
333 return res;
334 }
335 RTStrmClose(fin);
336 }
337
338 sort(g_products.begin(), g_products.end());
339 sort(g_vendors.begin(), g_vendors.end());
340
341 // validate that all records are unique
342 ProductsSet::iterator ita = adjacent_find(g_products.begin(), g_products.end());
343 if (ita != g_products.end())
344 {
345 cerr << "Warning: Duplicate alias detected. " << *ita << endl;
346 return 0;
347 }
348
349 if (!outName)
350 {
351 cerr << "Format: " << argv[0] <<
352 " [linux.org usb list file] [custom usb list file] [-o output file]" << endl;
353 cerr << "Error: Output file is not defined." << endl;
354 return ERROR_OPEN_FILE;
355 }
356
357 fout.open(outName);
358 if (!fout.is_open())
359 {
360 cerr << "Format: " << argv[0] <<
361 " [linux.org usb list file] [custom usb list file] [-o output file]" << endl;
362 cerr << "Error: Can not open file to write '" << argv[1] << "'." << endl;
363 return ERROR_OPEN_FILE;
364 }
365
366 fout << header;
367 for (ProductsSet::iterator itp = g_products.begin(); itp != g_products.end(); ++itp)
368 {
369 fout << *itp;
370 }
371 fout << footer;
372
373 fout << vendor_header;
374 for (VendorsSet::iterator itv = g_vendors.begin(); itv != g_vendors.end(); ++itv)
375 {
376 fout << *itv;
377 }
378 fout << vendor_footer;
379
380 fout.close();
381
382
383 return 0;
384}
385
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