summaryrefslogtreecommitdiffhomepage
path: root/csv/csv.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'csv/csv.cpp')
-rw-r--r--csv/csv.cpp220
1 files changed, 91 insertions, 129 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;
}