VirtualBox

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

Last change on this file since 57338 was 57338, checked in by vboxsync, 10 years ago

Main/HostUSBdevice: Fixed issue on Linux

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