summaryrefslogtreecommitdiffhomepage
path: root/csv/csv.cpp
blob: d899e11aae5985c1f03a7629376e9bf52cdedd21 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/* Homepage http://facetracknoir.sourceforge.net/home/default.htm
 *
 * ISC License (ISC)                                                             *
 *                                                                               *
 * Copyright (c) 2015, Wim Vriend                                                *
 *                                                                               *
 * Permission to use, copy, modify, and/or distribute this software for any      *
 * purpose with or without fee is hereby granted, provided that the above        *
 * copyright notice and this permission notice appear in all copies.             *
 */

#include "csv.h"
#include "compat/library-path.hpp"
#include <utility>
#include <cstdio>
#include <QByteArray>
#include <QString>
#include <QStringDecoder>
#include <QFile>
#include <QByteArrayView>
#include <QDebug>

namespace {

void chomp(QString& str)
{
    if (!str.isEmpty() && str.back() == '\n')
    {
        str.chop(1);
        if (!str.isEmpty() && str.back() == '\r')
            str.chop(1);
    }
}

auto do_scanf(QLatin1StringView s, unsigned(&tmp)[8])
{
    unsigned fuzz[3];
    return std::sscanf(s.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);
};

}

bool getGameData(int id, unsigned char* table, QString& gamename)
{
    for (int i = 0; i < 8; i++)
        table[i] = 0;

    if (id != 0)
        qDebug() << "csv: lookup game id" << id;

    static const QString csv_path(OPENTRACK_BASE_PATH +
                                  OPENTRACK_DOC_PATH "settings/facetracknoir supported games.csv");
    auto id_str = QString::number(id);

    QFile file(csv_path);
    if (!file.open(QIODevice::ReadOnly))
    {
        qDebug() << "csv: can't open game list for freetrack protocol!";
        return false;
    }
    QStringDecoder decoder{QStringConverter::Encoding::Utf8};
    QStringList gameLine; gameLine.reserve(8);
    unsigned lineno = 0;
    // TODO QIODevice::readLineInto() is Qt 6.9 - sh 20250515
    char buf[256];

    while (auto sz = file.readLine(buf, sizeof(buf)))
    {
        QString line = decoder.decode(QByteArrayView{buf, sz});
        chomp(line);

        if (line.isEmpty())
            continue;

        gameLine = line.split(';', Qt::SplitBehaviorFlags::KeepEmptyParts);

        //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.size() == 8)
        {
            if (gameLine[6] == id_str)
            {
                const QString& proto = gameLine[3];
                QString& name = gameLine[1];
                const QByteArray id_cstr = gameLine[7].toLatin1();
                unsigned tmp[8] {};

                if (proto == QStringLiteral("V160") || id_cstr.length() != 22)
                    (void)0;
                else if (id_cstr.length() != 22 || do_scanf(QLatin1StringView(id_cstr), tmp) != 11)
                    qDebug() << "scanf failed" << lineno;
                else
                {
                    using uchar = unsigned char;
                    for (int i = 0; i < 8; i++)
                        table[i] = uchar(tmp[i]);
                }
                gamename = std::move(name);
                return true;
            }
        }
        else
            qDebug() << "csv wrong column count" << gameLine.size();

        lineno++;
    }

    if (id)
        qDebug() << "unknown game connected" << id;

    return false;
}