File indexing completed on 2024-05-19 16:31:59

0001 /*
0002  *   SPDX-FileCopyrightText: 2001 Matthias Hoelzer-Kluepfel <mhk@caldera.de>
0003  *   SPDX-License-Identifier: GPL-2.0-or-later
0004  */
0005 
0006 #include "usbdb.h"
0007 
0008 #include <iostream>
0009 
0010 #include <QDebug>
0011 #include <QFile>
0012 #include <QRegularExpression>
0013 #include <QRegularExpressionMatch>
0014 #include <QStandardPaths>
0015 #include <QTextStream>
0016 
0017 USBDB::USBDB()
0018 {
0019     QString db = QStringLiteral("/usr/share/hwdata/usb.ids"); /* on Fedora and Arch*/
0020     if (!QFile::exists(db)) {
0021         db = QStringLiteral("/usr/share/misc/usb.ids"); /* on Gentoo */
0022     }
0023     if (db.isEmpty())
0024         return;
0025 
0026     QFile f(db);
0027 
0028     if (f.open(QIODevice::ReadOnly)) {
0029         QTextStream ts(&f);
0030 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0031         ts.setCodec("UTF-8");
0032 #endif
0033 
0034         QString line;
0035         int id = -1, subid = -1;
0036         const QRegularExpression vendor(QStringLiteral("^([0-9a-fA-F]{4})\\s+(.+)$"));
0037         const QRegularExpression product(QStringLiteral("^\t([0-9a-fA-F]{4})\\s+(.+)$"));
0038         const QRegularExpression cls(QStringLiteral("^C ([0-9a-fA-F]{2})\\s+(.+)$"));
0039         const QRegularExpression subclass(QStringLiteral("^\t([0-9a-fA-F]{2})\\s+(.+)$"));
0040         const QRegularExpression prot(QStringLiteral("^\t\t([0-9a-fA-F]{2})\\s+(.+)$"));
0041         while (ts.readLineInto(&line)) {
0042             if (!line.isEmpty() && line.startsWith(QLatin1String("#")))
0043                 continue;
0044 
0045             // skip unhandled categories lines
0046             if (line.isEmpty() || line.startsWith(QLatin1String("AT ")) || line.startsWith(QLatin1String("HID ")) || line.startsWith(QLatin1String("R "))
0047                 || line.startsWith(QLatin1String("BIAS ")) || line.startsWith(QLatin1String("PHY ")) || line.startsWith(QLatin1String("HUT "))
0048                 || line.startsWith(QLatin1String("L ")) || line.startsWith(QLatin1String("HCC ")) || line.startsWith(QLatin1String("VT "))) {
0049                 id = -1;
0050                 subid = -1;
0051                 continue;
0052             }
0053 
0054             QRegularExpressionMatch match;
0055             if (line.startsWith('C') && (match = cls.match(line)).hasMatch()) {
0056 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0057                 id = match.capturedRef(1).toInt(0, 16);
0058                 const QString name = match.capturedRef(2).trimmed().toString();
0059 #else
0060                 id = match.capturedView(1).toInt(0, 16);
0061                 const QString name = match.capturedView(2).trimmed().toString();
0062 #endif
0063                 _classes.insert(QStringLiteral("%1").arg(id), name);
0064             } else if (id >= 0 && subid >= 0 && (match = prot.match(line)).hasMatch()) {
0065 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0066                 const int protid = match.capturedRef(1).toInt(0, 16);
0067                 const QString name = match.capturedRef(2).trimmed().toString();
0068 #else
0069                 const int protid = match.capturedView(1).toInt(0, 16);
0070                 const QString name = match.capturedView(2).trimmed().toString();
0071 #endif
0072                 _classes.insert(QStringLiteral("%1-%2-%3").arg(id).arg(subid).arg(protid), name);
0073             } else if (id >= 0 && (match = subclass.match(line)).hasMatch()) {
0074 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0075                 subid = match.capturedRef(1).toInt(0, 16);
0076                 const QString name = match.capturedRef(2).trimmed().toString();
0077 #else
0078                 subid = match.capturedView(1).toInt(0, 16);
0079                 const QString name = match.capturedView(2).trimmed().toString();
0080 #endif
0081                 _classes.insert(QStringLiteral("%1-%2").arg(id).arg(subid), name);
0082             } else if ((match = vendor.match(line)).hasMatch()) {
0083 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0084                 id = match.capturedRef(1).toInt(0, 16);
0085 #else
0086                 id = match.capturedView(1).toInt(0, 16);
0087 #endif
0088                 const QString name = match.captured(2);
0089                 _ids.insert(QStringLiteral("%1").arg(id), name);
0090             } else if (id >= 0 && (match = product.match(line)).hasMatch()) {
0091 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0092                 subid = match.capturedRef(1).toInt(0, 16);
0093                 const QString name = match.capturedRef(2).trimmed().toString();
0094 #else
0095                 subid = match.capturedView(1).toInt(0, 16);
0096                 const QString name = match.capturedView(2).trimmed().toString();
0097 #endif
0098                 _ids.insert(QStringLiteral("%1-%2").arg(id).arg(subid), name);
0099             } else {
0100                 id = -1;
0101                 subid = -1;
0102             }
0103         }
0104 
0105         f.close();
0106     }
0107 }
0108 
0109 QString USBDB::vendor(uint16_t id) const
0110 {
0111     QString s = _ids.value(QStringLiteral("%1").arg(id));
0112     if (id != 0) {
0113         return s;
0114     }
0115     return QString();
0116 }
0117 
0118 QString USBDB::device(uint16_t vendor, uint16_t id) const
0119 {
0120     QString s = _ids.value(QStringLiteral("%1-%2").arg(vendor).arg(id));
0121     if ((id != 0) && (vendor != 0))
0122         return s;
0123     return QString();
0124 }
0125 
0126 QString USBDB::cls(uint8_t cls) const
0127 {
0128     return _classes.value(QStringLiteral("%1").arg(cls));
0129 }
0130 
0131 QString USBDB::subclass(uint8_t cls, uint8_t sub) const
0132 {
0133     return _classes.value(QStringLiteral("%1-%2").arg(cls).arg(sub));
0134 }
0135 
0136 QString USBDB::protocol(uint8_t cls, uint8_t sub, uint8_t prot) const
0137 {
0138     return _classes.value(QStringLiteral("%1-%2-%3").arg(cls).arg(sub).arg(prot));
0139 }