diff options
Diffstat (limited to 'csv')
-rw-r--r-- | csv/csv.cpp | 220 | ||||
-rw-r--r-- | csv/csv.h | 24 |
2 files changed, 93 insertions, 151 deletions
diff --git a/csv/csv.cpp b/csv/csv.cpp index a1f62dc0..d465906b 100644 --- a/csv/csv.cpp +++ b/csv/csv.cpp @@ -10,85 +10,19 @@ */ #include "csv.h" +#include "compat/macros.hpp" #include "compat/library-path.hpp" -#include <QTextDecoder> -#include <QFile> -#include <QString> -#include <QDebug> - -#include <utility> -#include <algorithm> - -const QTextCodec* const CSV::m_codec = QTextCodec::codecForName("System"); -const QRegExp CSV::m_rx = QRegExp(QString("((?:(?:[^;\\n]*;?)|(?:\"[^\"]*\";?))*)?\\n?")); -const QRegExp CSV::m_rx2 = QRegExp(QString("(?:\"([^\"]*)\";?)|(?:([^;]*);?)?")); - -CSV::CSV(QIODevice* device) : - m_device(device), - m_pos(0) -{ - if (m_device && m_device->isReadable()) - { - QTextDecoder dec(m_codec); - m_string = dec.toUnicode(m_device->readAll()); - } -} - -QString CSV::readLine() -{ - QString line; - - if ((m_pos = m_rx.indexIn(m_string,m_pos)) != -1) - { - line = m_rx.cap(1); - m_pos += m_rx.matchedLength(); - } - else - { - const QChar lf(QChar::LineFeed); - - while (m_pos < m_string.length()) - if (m_string[m_pos++] == lf) - break; - } - return line; -} - -bool CSV::parseLine(QStringList& ret) -{ - QString line(readLine()); - - QStringList list; - int pos2 = 0; - - if (line.size() == 0) - { - ret = QStringList(); - return m_device->size() > m_pos; - } - else - { - while (line.size() > pos2 && (pos2 = m_rx2.indexIn(line, pos2)) != -1) - { - QString col; - if (m_rx2.cap(1).size() > 0) - col = m_rx2.cap(1); - else if (m_rx2.cap(2).size() > 0) - col = m_rx2.cap(2); - list << col; +#include <ios> +#include <fstream> +#include <sstream> +#include <vector> - if (col.size()) - pos2 += m_rx2.matchedLength(); - else - pos2++; - } - } - ret = std::move(list); - return true; -} +#include <QString> +#include <QDebug> -bool CSV::getGameData(int id, unsigned char* table, QString& gamename) +static bool +check_line(int id, unsigned char* table, QString& game_name, const std::vector<std::string>& fields, unsigned lineno) { for (int i = 0; i < 8; i++) table[i] = 0; @@ -96,76 +30,104 @@ bool CSV::getGameData(int id, unsigned char* table, QString& gamename) if (id != 0) qDebug() << "csv: lookup game id" << id; - QString id_str(QString::number(id)); + const auto id_str = std::to_string(id); - static const QString csv_path(OPENTRACK_BASE_PATH + - OPENTRACK_DOC_PATH "settings/facetracknoir supported games.csv"); + unsigned tmp[8]; + unsigned fuzz[3]; - QFile file(csv_path); + //qDebug() << "Column 0: " << gameLine.at(0); // No. + //qDebug() << "Column 1: " << gameLine.at(1); // Game Name + //qDebug() << "Column 2: " << gameLine.at(2); // Game Protocol + //qDebug() << "Column 3: " << gameLine.at(3); // Supported since version + //qDebug() << "Column 4: " << gameLine.at(4); // Verified + //qDebug() << "Column 5: " << gameLine.at(5); // By + //qDebug() << "Column 6: " << gameLine.at(6); // International ID + //qDebug() << "Column 7: " << gameLine.at(7); // FaceTrackNoIR ID - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + if (fields.size() == 8) { - qDebug() << "csv: can't open game list for freetrack protocol!"; - return false; + if (fields[6] == id_str) + { + const auto& proto = fields[3]; + const auto& name = fields[1]; + + const auto& proto_id = fields[7]; + + auto do_scanf = [&]() { + return sscanf(proto_id.c_str(), + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + fuzz + 2, + fuzz + 0, + tmp + 3, tmp + 2, tmp + 1, tmp + 0, + tmp + 7, tmp + 6, tmp + 5, tmp + 4, + fuzz + 1); + }; + + if (proto == "V160" || proto_id.size() != 22) + (void)0; + else if (proto_id.size() != 22 || do_scanf() != 11) + qDebug() << "scanf failed" << lineno; + else + for (int i = 0; i < 8; i++) + table[i] = (unsigned char)tmp[i]; + game_name = QString::fromStdString(name); + return true; + } } + else + eval_once(qDebug() << "malformed csv line" << lineno); - CSV csv(&file); - - unsigned tmp[8]; - unsigned fuzz[3]; + if (id) + qDebug() << "unknown game connected" << id; - QStringList gameLine; + return false; +} - for (int lineno = 0; csv.parseLine(gameLine); lineno++) +bool get_game_data(int id, unsigned char* table, QString& game_name) +{ + static const auto filename = + (OPENTRACK_BASE_PATH + OPENTRACK_DOC_PATH "settings/facetracknoir supported games.csv").toStdWString(); + std::ifstream in; + in.exceptions(std::ifstream::badbit | std::ifstream::failbit); + in.open(filename); + try { - //qDebug() << "Column 0: " << gameLine.at(0); // No. - //qDebug() << "Column 1: " << gameLine.at(1); // Game Name - //qDebug() << "Column 2: " << gameLine.at(2); // Game Protocol - //qDebug() << "Column 3: " << gameLine.at(3); // Supported since version - //qDebug() << "Column 4: " << gameLine.at(4); // Verified - //qDebug() << "Column 5: " << gameLine.at(5); // By - //qDebug() << "Column 6: " << gameLine.at(6); // International ID - //qDebug() << "Column 7: " << gameLine.at(7); // FaceTrackNoIR ID - - if (gameLine.count() == 8) + if (in.fail()) + eval_once(qDebug() << "can't open csv file"); + + std::string line, field; + line.reserve(1024); field.reserve(1024); + std::vector<std::string> fields; fields.reserve(16); + unsigned lineno = 0; + try { - if (gameLine.at(6).compare(id_str, Qt::CaseInsensitive) == 0) + while (!in.eof()) { - const QString& proto = gameLine[3]; - QString& name = gameLine[1]; - - const QByteArray id_cstr = gameLine[7].toLatin1(); - - auto do_scanf = [&]() { - return sscanf(id_cstr.constData(), - "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - fuzz + 2, - fuzz + 0, - tmp + 3, tmp + 2, tmp + 1, tmp + 0, - tmp + 7, tmp + 6, tmp + 5, tmp + 4, - fuzz + 1); - }; - - if (proto == QStringLiteral("V160") || id_cstr.length() != 22) - (void)0; - else if (id_cstr.length() != 22 || do_scanf() != 11) - qDebug() << "scanf failed" << lineno; - else + line.clear(); + std::getline(in, line); + std::stringstream s{line, std::ios_base::in}; + fields.clear(); + while (!s.eof()) { - using uchar = unsigned char; - for (int i = 0; i < 8; i++) - table[i] = uchar(tmp[i]); + field.clear(); + std::getline(s, field, ';'); + fields.push_back(field); } - gamename = std::move(name); - return true; + bool ret = check_line(id, table, game_name, fields, lineno); + if (ret) + return true; + lineno++; } } - else - qDebug() << "malformed csv line" << lineno; + catch (const std::ios::failure& e) + { + eval_once(qDebug() << "failed to read .csv file:" << e.what()); + } + } + catch (const std::ios::failure& e) + { + eval_once(qDebug() << "can't open .csv file:" << e.what()); } - - if (id) - qDebug() << "unknown game connected" << id; return false; } @@ -1,26 +1,6 @@ #pragma once -#include <QtGlobal> -#include <QObject> -#include <QStringList> -#include <QIODevice> -#include <QTextCodec> -#include <QRegExp> -#include <QtGlobal> -class CSV -{ -public: - QString readLine(); - bool parseLine(QStringList& ret); +class QString; - static bool getGameData(int gameID, unsigned char* table, QString& gamename); -private: - CSV(QIODevice* device); +bool get_game_data(int id, unsigned char* table, QString& game_name); - QIODevice* m_device; - QString m_string; - int m_pos; - - static QTextCodec const* const m_codec; - static const QRegExp m_rx, m_rx2; -}; |