VirtualBox

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

Last change on this file since 57632 was 57632, checked in by vboxsync, 9 years ago

USBIdDatabaseGenerator: coding style

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