diff --git a/include/libg1m.h b/include/libg1m.h index e6893eb..e700665 100644 --- a/include/libg1m.h +++ b/include/libg1m.h @@ -46,6 +46,8 @@ extern "C" { * --- * First, the none error. */ # define g1m_noerror 0x00 +# define g1m_error_none 0x00 +# define g1m_error_success 0x00 /* Then, the miscallenous errors */ # define g1m_error_unknown 0x01 diff --git a/include/libg1m/internals.h b/include/libg1m/internals.h index 6a38abe..e7702bf 100644 --- a/include/libg1m/internals.h +++ b/include/libg1m/internals.h @@ -96,12 +96,15 @@ /* ************************************************************************** */ /* Decoding functions */ /* ************************************************************************** */ +/* with expected types */ int g1m_decode_std(g1m_t *handle, const char *path, g1m_buffer_t *buffer, struct standard_header*, g1m_type_t expected_types); -int g1m_decode_cas(g1m_t *handle, g1m_buffer_t *buffer, - g1m_type_t expected_types); -int g1m_decode_casemul(g1m_t *handle, g1m_buffer_t *buffer); +/* w/o expected types */ +int g1m_decode_casemul(g1m_t *handle, g1m_buffer_t *buffer); +int g1m_decode_storage(g1m_t *handle, g1m_buffer_t *buffer); +int g1m_decode_cas(g1m_t *handle, g1m_buffer_t *buffer); +int g1m_decode_grc(g1m_t *handle, g1m_buffer_t *buffer); /* ************************************************************************** */ /* "Std"-specific decoding functions */ /* ************************************************************************** */ @@ -118,7 +121,6 @@ G1M_STDFUNC(addin_cg) G1M_STDFUNC(lang) G1M_STDFUNC(lang_cg) G1M_STDFUNC(fkey) -G1M_STDFUNC(storage) /* others */ int g1m_decode_fkey_cg_content(g1m_t *handle, g1m_buffer_t *buffer, @@ -183,6 +185,9 @@ int g1m_skip(g1m_buffer_t *buffer, size_t size, uint_fast32_t *checksum); uint8_t g1m_checksum8(void *mem, size_t size); uint32_t g1m_checksum32(void *mem, size_t size, uint32_t checksum); +/* Get extension */ +int g1m_getext(const char *path, char *buf, size_t n); + /* File buffer */ int g1m_filebuffer_read(void *vcookie, unsigned char *buf, size_t size); diff --git a/src/core/decode.c b/src/core/decode.c deleted file mode 100644 index 7e99f04..0000000 --- a/src/core/decode.c +++ /dev/null @@ -1,59 +0,0 @@ -/* ***************************************************************************** - * core/decode.c -- decode a file. - * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey - * - * This file is part of libg1m. - * libg1m is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 3.0 of the License, - * or (at your option) any later version. - * - * libg1m is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with libg1m; if not, see . - * ************************************************************************** */ -#include - -/** - * g1m_decode: - * Decode a file. - * - * Read the standard header, correct endianness, check magic numbers, - * then read subparts according to the G1M type. - * - * @arg handle the handle. - * @arg path the file path. - * @arg buffer the buffer to read from. - * @arg expected_types the expected types. - * @return the error code (0 if ok). - */ - -int g1m_decode(g1m_t *handle, const char *path, g1m_buffer_t *buffer, - g1m_type_t expected_types) -{ - /* initialize the handle */ - memset(handle, 0, sizeof(g1m_t)); - - /* identify a CAS file */ - unsigned char buf[0x20]; READ(buf, 1) - if (buf[0] == ':') - return (g1m_decode_cas(handle, buffer, expected_types)); - - /* identify a Casemul file */ - READ(&buf[1], 3) - if (!memcmp(buf, "CAFS", 4)) { - handle->platform |= g1m_platflag_be; - return (g1m_decode_casemul(handle, buffer)); - } else if (!memcmp(buf, "ACFS", 4)) - return (g1m_decode_casemul(handle, buffer)); - - /* identify a standard header (send a _copy_) */ - READ(&buf[4], 0x1C) - uint8_t altbuf[0x20]; memcpy(altbuf, buf, 0x20); - return (g1m_decode_std(handle, path, buffer, - (struct standard_header*)altbuf, expected_types)); -} diff --git a/src/decode/cas.c b/src/decode/cas.c index 11a1b77..b89698b 100644 --- a/src/decode/cas.c +++ b/src/decode/cas.c @@ -111,6 +111,7 @@ static int decode_caspro_head(g1m_mcshead_t *head, struct caspro_header *hd) end = memchr(hd->aux, 0xFF, 8); len = end ? (size_t)(end - (char*)hd->aux) : 8; memcpy(head->password, hd->aux, len); head->password[len] = 0; + log_info("Is a program of %" PRIuFAST32 " bytes", head->size); break; case g1m_mcstype_variable: if (hd->used) head->flags |= g1m_mcsflag_unfinished; @@ -240,12 +241,10 @@ int g1m_decode_casfile_part(g1m_mcsfile_t *file, g1m_buffer_t *buffer) * * @arg handle the handle to create. * @arg buffer the buffer to read from. - * @arg expected_types the expected types. * @return the libg1m error. */ -int g1m_decode_cas(g1m_t *handle, g1m_buffer_t *buffer, - g1m_type_t expected_types) +int g1m_decode_cas(g1m_t *handle, g1m_buffer_t *buffer) { int err; @@ -335,3 +334,19 @@ fail: g1m_free_mcs(handle); return (err); } + +/** + * g1m_decode_grc: + * Decode Graph Card file. + * + * @arg handle the handle. + * @arg buffer the buffer to read from. + * @return the error code (0 if ok). + */ + +int g1m_decode_grc(g1m_t *handle, g1m_buffer_t *buffer) +{ + uint8_t intro[2]; READ(intro, 2) /* probably the file count? */ + uint8_t colon; READ(&colon, 1) /* read first colon */ + return (g1m_decode_cas(handle, buffer)); +} diff --git a/src/decode/main.c b/src/decode/main.c new file mode 100644 index 0000000..fe1e74d --- /dev/null +++ b/src/decode/main.c @@ -0,0 +1,130 @@ +/* ***************************************************************************** + * decode/main.c -- decode a file. + * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey + * + * This file is part of libg1m. + * libg1m is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3.0 of the License, + * or (at your option) any later version. + * + * libg1m is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libg1m; if not, see . + * ************************************************************************** */ +#include + +/* ************************************************************************** */ +/* Check using extensions */ +/* ************************************************************************** */ +/* Decode function */ +typedef int (*decode_func)(g1m_t*, g1m_buffer_t*); + +/* Correspondance type */ +struct corresp { + /* extension */ + const char *ext; + + /* expected types */ + g1m_type_t type; + + /* function */ + decode_func decode; +}; + +/* Correspondances */ +static struct corresp correspondances[] = { +// {"g1s", g1m_type_storage, g1m_decode_storage}, + {"grc", g1m_type_mcs, g1m_decode_grc}, + + {NULL, 0, NULL} +}; + +/** + * lookup_extension: + * Get the function using the type. + * + * @arg path the path. + * @arg types the expected types. + * @arg decode the decode function to set. + * @return the error code (0 if ok). + */ + +static int lookup_extension(const char *path, g1m_type_t types, + decode_func *func) +{ + /* match the extension */ + char ext[5]; + if (!g1m_getext(path, ext, 5)) return (g1m_error_magic); + struct corresp *c = correspondances - 1; + while ((++c)->ext) if (!strcmp(c->ext, ext)) break; + + /* check if correspondance is valid and expected */ + if (!c->ext) return (g1m_error_magic); + if (types && !(types & c->type)) return (g1m_error_wrong_type); + + /* return the decode function */ + *func = c->decode; + return (0); +} + +/* ************************************************************************** */ +/* Main decoding function */ +/* ************************************************************************** */ +/** + * g1m_decode: + * Decode a file. + * + * Read the standard header, correct endianness, check magic numbers, + * then read subparts according to the G1M type. + * + * @arg handle the handle. + * @arg path the file path. + * @arg buffer the buffer to read from. + * @arg expected_types the expected types. + * @return the error code (0 if ok). + */ + +int g1m_decode(g1m_t *handle, const char *path, g1m_buffer_t *buffer, + g1m_type_t expected_types) +{ + /* initialize the handle */ + memset(handle, 0, sizeof(g1m_t)); + + /* match using extension */ + decode_func decode; + int err = lookup_extension(path, expected_types, &decode); + if (err == g1m_error_wrong_type) return (g1m_error_wrong_type); + else if (!err) return ((*decode)(handle, buffer)); + + /* identify a CAS file */ + unsigned char buf[0x20]; READ(buf, 1) + if (buf[0] == ':') { + if (expected_types && !(expected_types & g1m_type_mcs)) + return (g1m_error_wrong_type); + return (g1m_decode_cas(handle, buffer)); + } + + /* identify a Casemul file */ + READ(&buf[1], 3) + if (!memcmp(buf, "CAFS", 4)) { + handle->platform |= g1m_platflag_be; + if (expected_types && !(expected_types & g1m_type_mcs)) + return (g1m_error_wrong_type); + return (g1m_decode_casemul(handle, buffer)); + } else if (!memcmp(buf, "ACFS", 4)) { + if (expected_types && !(expected_types & g1m_type_mcs)) + return (g1m_error_wrong_type); + return (g1m_decode_casemul(handle, buffer)); + } + + /* identify a standard header (send a _copy_) */ + READ(&buf[4], 0x1C) + uint8_t altbuf[0x20]; memcpy(altbuf, buf, 0x20); + return (g1m_decode_std(handle, path, buffer, + (struct standard_header*)altbuf, expected_types)); +} diff --git a/src/decode/std/storage.c.draft b/src/decode/storage.c.draft similarity index 94% rename from src/decode/std/storage.c.draft rename to src/decode/storage.c.draft index a2c4249..4d588f1 100644 --- a/src/decode/std/storage.c.draft +++ b/src/decode/storage.c.draft @@ -1,5 +1,5 @@ /* ***************************************************************************** - * decode/std/storage.c -- decode a storage file. + * decode/storage.c -- decode a storage file. * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey * * This file is part of libg1m. @@ -31,18 +31,16 @@ * * @arg handle the libg1m handle. * @arg buffer the buffer to read from. - * @arg std the standard header. * @return the error code (0 if ok). */ -int g1m_decode_std_storage(g1m_t *handle, g1m_buffer_t *buffer, - struct standard_header *std) +int g1m_decode_storage(g1m_t *handle, g1m_buffer_t *buffer) { (void)std; int err, ret = 0; handle->type = 0x00; log_info("Storage memory!"); /* go to offset 0x270000 of the file */ - SKIP(0x270000 - sizeof(struct standard_header)) + SKIP(0x270000) /* get the entries */ struct storage_entry storage_entries[0x800]; diff --git a/src/type/std.c b/src/type/std.c index 2f7520e..c153a75 100644 --- a/src/type/std.c +++ b/src/type/std.c @@ -129,9 +129,6 @@ struct ext_corresp { /* Extension correspondances */ static struct ext_corresp ext_types[] = { - /* storage files */ - {"g1s", "Storage file", g1m_platform_none, g1m_type_storage}, - /* fx types with non-checked header */ {"g1l", "fx language file", g1m_platform_fx, g1m_type_lang}, {"g1n", "fx fkeys file", g1m_platform_fx, g1m_type_fkey}, @@ -144,31 +141,6 @@ static struct ext_corresp ext_types[] = { {NULL, NULL, 0, 0} }; -/** - * get_extension: - * Get extension from a path. - * - * @arg path the path. - * @arg extbuf the extension buffer. - * @return extension. - */ - -static void get_extension(const char *path, char *extbuf) -{ - /* get filename */ - const char *filename = strrchr(path, '/'); - filename = filename ? filename + 1 : path; - - /* get extension */ - const char *ext = strrchr(filename, '.'); - ext = ext ? ext + 1 : filename; - - /* copy it */ - extbuf[4] = 0; strncpy(extbuf, ext, 4); - for (int i = 0; i < 3; i++) - extbuf[i] = tolower(extbuf[i]); -} - /* ************************************************************************** */ /* Main functions */ /* ************************************************************************** */ @@ -197,7 +169,7 @@ int g1m_maketype_std(const char *path, && !memcmp(subtype, "\xFF\xFF\xFF\xFF\xFF\xFF", 6)) { log_info("Blank type! Let's use the extension to try and identify it."); if (!path) return (1); - char ext[5]; get_extension(path, ext); + char ext[5]; g1m_getext(path, ext, 5); struct ext_corresp *e = ext_types - 1; while ((++e)->ext) { diff --git a/src/utils/extension.c b/src/utils/extension.c new file mode 100644 index 0000000..0be6c47 --- /dev/null +++ b/src/utils/extension.c @@ -0,0 +1,52 @@ +/* ***************************************************************************** + * utils/extension.c -- extension utilities. + * Copyright (C) 2017 Thomas "Cakeisalie5" Touhey + * + * This file is part of libg1m. + * libg1m is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3.0 of the License, + * or (at your option) any later version. + * + * libg1m is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libg1m; if not, see . + * ************************************************************************** */ +#include +#include + +/** + * g1m_getext: + * Get extension from a path. + * + * @arg path the path. + * @arg buf the extension buffer. + * @arg n the extension buffer size. + * @return the size of the extension. + */ + +int g1m_getext(const char *path, char *buf, size_t n) +{ + /* no size? */ + if (!n) return (0); + + /* get filename */ + const char *filename = strrchr(path, '/'); + filename = filename ? filename + 1 : path; + + /* get extension */ + const char *ext = strrchr(filename, '.'); + ext = ext ? ext + 1 : ""; + + /* copy it */ + buf[n - 1] = 0; strncpy(buf, ext, n - 1); + for (int i = 0; buf[i]; i++) + buf[i] = tolower(buf[i]); + + /* return the size */ + return (strlen(buf)); +}