psp2name/tools/csv2sqlite/main.d
King_DuckZ 3f353b7dfe First import.
Lists are a bit dirty and can't be imported into sqlite atm
due to them having duplicated serial numbers. They need cleaning,
possibly against titelIDs.txt which, on the other hand, contains
dodgy character sequences.
2020-02-26 18:35:22 +01:00

96 lines
3.3 KiB
D

import std.stdio;
import std.csv;
import std.algorithm;
import std.typecons;
import etc.c.sqlite3;
import std.string : toStringz, fromStringz, empty;
import std.exception;
import std.conv : to;
private class SQLiteException : Exception {
this(int code, string msg1, string msg2, string file = __FILE__, size_t line = __LINE__) {
super("SQLite3 error " ~ to!string(code) ~ (msg1.empty ? "" : " ") ~ msg1 ~ ": " ~ msg, file, line);
}
}
extern(C) private int callback(void */*NotUsed*/, int /*argc*/, char **/*argv*/, char **/*azColName*/) {
return 0;
}
private int version_to_int (string ver) pure {
switch(ver) {
case "pal":
return 0;
case "ntsc_j":
return 1;
case "ntsc_u":
return 2;
default:
return 3;
}
}
private void insert_into_sqlite(sqlite3* db, string path, string ver) {
auto file = File(path, "r");
sqlite3_stmt* statement;
scope(exit) {sqlite3_finalize(statement);}
{
string sql = "INSERT INTO GameList(Name, Serial, Languages, Version) VALUES(?, ?, ?, ?);";
const int prepare_ret = sqlite3_prepare_v2(db, sql.ptr, cast(int)sql.length, &statement, null);
if (prepare_ret)
throw new SQLiteException(prepare_ret, "", sqlite3_errstr(prepare_ret).fromStringz.idup);
}
foreach (record; file.byLine.joiner("\n").csvReader!(Tuple!(string, string, string))) {
sqlite3_bind_text(statement, 1, record[0].ptr, cast(int)record[0].length, SQLITE_STATIC);
sqlite3_bind_text(statement, 2, record[1].ptr, cast(int)record[1].length, SQLITE_STATIC);
sqlite3_bind_text(statement, 3, record[2].ptr, cast(int)record[2].length, SQLITE_STATIC);
sqlite3_bind_int(statement, 4, version_to_int(ver));
stderr.writefln("insert into: \"%s\", \"%s\", \"%s\", \"%d\"", record[0], record[1], record[2], version_to_int(ver));
const int step_ret = sqlite3_step(statement);
if (step_ret && SQLITE_DONE != step_ret)
throw new SQLiteException(step_ret, "", sqlite3_errstr(step_ret).fromStringz.idup);
sqlite3_reset(statement);
}
}
int main(string[] argv) {
//input parameters should be csv files in this order: pal, ntsc_j, ntsc_u
stderr.writefln("got %s params: \"%s\", \"%s\", \"%s\", \"%s\"", argv.length, argv[1], argv[2], argv[3], argv[4]);
if (argv.length != 5) {
stderr.writefln("Expected 4 parameters: <pal.csv> <ntsc_j.csv> <ntsc_u.csv> <output.sqlite3>, but %s were received", argv.length - 1);
return 2;
}
try {
sqlite3* db = null;
scope(exit) { if (db) {sqlite3_close(db);} }
{
const int open_ret = sqlite3_open_v2(argv[4].toStringz(), &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, null);
if (open_ret)
throw new SQLiteException(open_ret, "opening database \"" ~ argv[4] ~ "\"", sqlite3_errmsg(db).fromStringz.idup);
}
{
string sql = "DROP TABLE IF EXISTS GameList; CREATE TABLE GameList(Serial VARCHAR(10) PRIMARY KEY NOT NULL, Name TEXT NOT NULL, Languages TEXT NOT NULL, Version TINYINT NOT NULL);";
char* error_msg = null;
const int query_ret = sqlite3_exec(db, sql.toStringz(), &callback, null, &error_msg);
if (query_ret)
throw new SQLiteException(query_ret, "creating GameList table", error_msg.fromStringz.idup);
}
insert_into_sqlite(db, argv[1], "pal");
insert_into_sqlite(db, argv[2], "ntsc_j");
insert_into_sqlite(db, argv[3], "ntsc_u");
}
catch (Exception err) {
stderr.writeln(err);
return 1;
}
return 0;
}