diff --git a/src/isotoserial.d b/src/isotoserial.d new file mode 100644 index 0000000..8f28fe8 --- /dev/null +++ b/src/isotoserial.d @@ -0,0 +1,76 @@ +module isotoserial; + +import std.string : toStringz, fromStringz; +import std.stdio; +import std.exception; +import std.conv : to; + +private enum LibarchiveRet : int { + ARCHIVE_EOF = 1, /* Found end of archive. */ + ARCHIVE_OK = 0, /* Operation was successful. */ + ARCHIVE_RETRY = (-10), /* Retry might succeed. */ + ARCHIVE_WARN = (-20), /* Partial success. */ + /* For example, if write_header "fails", then you can't push data. */ + ARCHIVE_FAILED = (-25), /* Current operation cannot complete. */ + /* But if write_header is "fatal," then this archive is dead and useless. */ + ARCHIVE_FATAL = (-30), /* No more operations are possible. */ +} + +public class LibarchiveException : Exception { + this(LibarchiveRet code, string file = __FILE__, size_t line = __LINE__) { + super("libarchive error " ~ to!string(cast(int)code) ~ ": " ~ to!string(code), file, line); + } +} + +extern(C) { + struct archive; + struct archive_entry; + + archive* archive_read_new(); + int archive_read_open_filename(archive*, const(char)* filename, size_t block_size); + int archive_read_next_header(archive*, archive_entry**); + int archive_read_data_skip(archive*); + int archive_read_free(archive*); + int archive_read_support_format_iso9660(archive*); + int archive_read_support_format_empty(archive*); + int archive_read_support_format_mtree(archive*); + int archive_read_support_format_raw(archive*); + int archive_read_support_format_tar(archive*); + int archive_read_support_format_all(archive*); + int archive_read_support_compression_none(archive*); + int archive_read_support_compression_all(archive*); + int archive_read_close(archive*); + + const(char)* archive_entry_pathname(archive_entry*); +} + +public string iso_to_serial (string path) { + archive* arc = archive_read_new(); + scope(exit) archive_read_free(arc); + + // open umd_data.bin + // examples: + // NPEG-00003|8F33052F02B34E56|0001|G + // NPJH-50465|0D506D389F2AA444|0001|G + // ULJM-05530|5A2E0CF722EF6299|0001|G + archive_read_support_format_iso9660(arc); + archive_read_support_format_empty(arc); + archive_read_support_format_raw(arc); + //archive_read_support_format_tar(arc); + archive_read_support_compression_none(arc); + + const LibarchiveRet r = cast(LibarchiveRet)archive_read_open_filename(arc, path.toStringz, 10240); + if (r != LibarchiveRet.ARCHIVE_OK) + throw new LibarchiveException(r); + archive_entry* entry; + writefln("reading content of %s...", path); + while (archive_read_next_header(arc, &entry) == LibarchiveRet.ARCHIVE_OK) { + writefln("path: \"%s\"", archive_entry_pathname(entry).fromStringz); + archive_read_data_skip(arc); + } + + return "UCES-00356"; //Tekken Dark Resurrection + //return "NPJH-50465"; //Hatsune Miku (missing from redump list) + //return "ULJM-05530"; //Undead Knights (missing from redump list) + //return "NPEG-00003"; //fl0w (missing from redump list) +} diff --git a/src/main.d b/src/main.d index aee05aa..fc8644f 100644 --- a/src/main.d +++ b/src/main.d @@ -2,11 +2,13 @@ import std.stdio; import std.getopt; import std.typecons; import gamesdb; +import isotoserial; int main() { writeln("hello world"); Unique!GamesDB db = new GamesDB; - writefln("Title for game UCES-00356 is %s", db.find_by_serial("UCES-00356")); + string serial = iso_to_serial("/home/michele/deleme/b-mikuex.iso"); + writefln("Title for game %s is %s", serial, db.find_by_serial(serial)); return 0; } diff --git a/src/meson.build b/src/meson.build index 3233c62..92db1d7 100644 --- a/src/meson.build +++ b/src/meson.build @@ -25,6 +25,7 @@ executable(meson.project_name(), 'main.d', sqlitedb_cfile_target, 'gamesdb.d', + 'isotoserial.d', install: true, dependencies: [libarchive_dep, sqlite_dep] )