/* ***************************************************************************** * decode/std.c -- decode a "standard" CASIO 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 #define FUNC(NAME) g1m_decode_std_##NAME /* ************************************************************************** */ /* Getting the parsing function */ /* ************************************************************************** */ /* Correspondance type */ typedef int (*decode_func)(); struct corresp { unsigned int platform; unsigned int type; /* result */ decode_func decode; }; /* The correspondances */ static struct corresp parsing_functions[] = { /* add-ins */ {g1m_platform_fx, g1m_type_addin, FUNC(addin)}, {g1m_platform_cp, g1m_type_addin, FUNC(cp_addin)}, {g1m_platform_cg, g1m_type_addin, FUNC(cg_addin)}, /* mcs */ {g1m_platform_fx, g1m_type_mcs, FUNC(mcs)}, {g1m_platform_cg, g1m_type_mcs, FUNC(mcs)}, /* language files */ {g1m_platform_fx, g1m_type_lang, FUNC(lang)}, {g1m_platform_cg, g1m_type_lang, FUNC(cg_lang)}, /* function keys file */ {g1m_platform_fx, g1m_type_fkey, FUNC(fkey)}, {g1m_platform_cg, g1m_type_fkey, FUNC(cg_fkey)}, /* e-activities */ {g1m_platform_fx, g1m_type_eact, FUNC(eact)}, /* pictures */ {g1m_platform_cg, g1m_type_pict, FUNC(g3p)}, {g1m_platform_cp, g1m_type_pict, FUNC(c2p)}, {0, 0, NULL} }; /** * find_decode_function: * Find the parsing function. * * @arg platform the platform. * @arg type the type. * @arg rd pointer to the decode function. * @return the error code (0 if ok). */ static int find_decode_function(g1m_platform_t platform, g1m_type_t type, decode_func *rd) { /* get the function */ struct corresp *c = parsing_functions - 1; while ((++c)->decode) { if (c->type != type) continue; if (c->platform != platform) continue; break; } if (!c->decode) { log_fatal("No parsing function was found for this type."); return (g1m_error_magic); } /* set the vars */ *rd = c->decode; return (0); } /* ************************************************************************** */ /* Main standard header decoding function */ /* ************************************************************************** */ /** * g1m_decode_std: * Decode a file with standard header. * * @arg handle the handle to create. * @arg path the path. * @arg buffer the buffer to read from. * @arg std the standard header. * @arg expected_types the expected types. * @return the error code (0 if ok). */ int g1m_decode_std(g1m_t **handle, const char *path, g1m_buffer_t *buffer, struct standard_header *std, g1m_type_t expected_types) { int err; /* reverse the standard header */ uint8_t *u = (uint8_t*)std; uint32_t check = g1m_checksum32(std, sizeof(struct standard_header), 0); for (size_t i = 0; i < sizeof(struct standard_header); i++) u[i] = ~u[i]; /* print header */ log_info("Raw inverted standard header is:"); logm_info(std, sizeof(struct standard_header)); std->filesize = be32toh(std->filesize); std->number = be16toh(std->number); /* get the type */ g1m_platform_t platform; g1m_type_t type; const char *type_string; unsigned int mflags; decode_func rd; if (g1m_maketype_std(path, std->main_id, std->subtype, &type_string, &mflags, &platform, &type)) return (g1m_error_magic); log_info("Standard Header type is '%s'.", type_string); /* check control bytes */ if (mflags & g1m_stdflag_check1 && std->control != ((std->filesize + 0x41) & 0xff)) { log_info("First control byte isn't right."); return (g1m_error_magic); } else if (mflags & g1m_stdflag_check2 && std->control2 != ((std->filesize + 0xb8) & 0xff)) { log_info("Second control byte isn't right."); return (g1m_error_magic); } /* check if there is a standard subheader */ if (mflags & g1m_stdflag_sub) { log_info("Has a Standard Subheader!"); DREAD(hd, standard_subheader) if (g1m_maketype_sub(hd.filetype, hd.platform, &mflags, &type, &platform)) return (g1m_error_magic); /* TODO: controls */ /* find the decode function */ if (find_decode_function(platform, type, &rd)) return (g1m_error_magic); if (expected_types && !(type & expected_types)) return (g1m_error_wrong_type); /* read and decode for specific platforms */ check = g1m_checksum32(&hd.filetype, sizeof(struct standard_subheader) - 4, check); if (platform == g1m_platform_cp) { DREAD(shd, _classpad_subheader) check = g1m_checksum32(&shd, sizeof(struct _classpad_subheader), check); /* decode the file content */ err = (*rd)(handle, buffer, std, &hd, &shd, &check); if (err) return (err); } else if (platform == g1m_platform_cg) { DREAD(shd, _prizm_subheader) check = g1m_checksum32(&shd, sizeof(struct _prizm_subheader), check); /* decode the file content */ err = (*rd)(handle, buffer, std, &hd, &shd, &check); if (err) return (err); /* read the footer */ uint32_t endcheck; GREAD(&endcheck, sizeof(uint32_t)) err = g1m_error_checksum; if (be32toh(endcheck) != be32toh(hd.checksum)) goto fail; } /* check the sum */ err = g1m_error_checksum; if (check != be32toh(hd.checksum)) goto fail; /* no error */ return (0); } /* check if there is a standard picture header */ if (mflags & g1m_stdflag_pic) { log_info("Has a Standard Picture Header!"); DREAD(hd, standard_picheader) /* correct the type; TODO: hardcode less */ type = g1m_type_picture; if (!memcmp(hd.cp, "CC", 2)) platform = g1m_platform_cp; else if (!memcmp(hd.cp, "CP", 2)) platform = g1m_platform_cg; else { log_error("Unknown magic sequence: '%.2s'", hd.cp); return (g1m_error_magic); } /* find the decode function */ if (find_decode_function(platform, type, &rd)) return (g1m_error_magic); /* call it */ err = (*rd)(handle, buffer, std, &hd); if (err) return (err); /* no error! */ return (0); } /* find the decode function */ if (find_decode_function(platform, type, &rd)) return (g1m_error_magic); if (expected_types && !(type & expected_types)) return (g1m_error_wrong_type); /* log some data */ log_info("Standard Header filesize is %" PRIu32 "o.", std->filesize); log_info("Standard Header num is %" PRIu16 ".", std->number); /* subdecode. */ return ((*rd)(handle, buffer, std)); fail: g1m_free(*handle); *handle = NULL; return (err); }