/* ***************************************************************************** * decode/std/addin.c -- decode an add-in 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 /** * addin_set_data: * Set handle data. * * Will take basic add-in data, put it into the right interface format * and store it. * * @arg handle the handle. * @arg title the addin title. * @arg title_size the addin title size. * @arg internal_name the addin internal name. * @arg internal_name_size the addin internal name size. * @arg version the version string. * @arg creation_time the creation time. */ static void addin_set_data(g1m_t *handle, char *title, size_t title_size, char *internal_name, size_t internal_name_size, char *version, char *creation_time) { /* useful vars */ const int two = '0' + '0' * 10; const int four = two + '0' * 100 + '0' * 1000; /* put title */ bzero(handle->title, 17); strncpy(handle->title, title, title_size); /* put internal name */ bzero(handle->internal_name, 12); strncpy(handle->internal_name, internal_name, internal_name_size); /* put version */ #define v version handle->version = (g1m_version_t){ .major = v[0] * 10 + v[1] - two, .minor = v[3] * 10 + v[4] - two, .revision = v[6] * 1000 + v[7] * 100 + v[8] * 10 + v[9] - four }; #undef v /* put time */ #define c creation_time struct tm created = { .tm_year = c[0] * 1000 + c[1] * 100 + c[2] * 10 + c[3] - four, .tm_mon = c[5] * 10 + c[6] - two, .tm_mday = c[7] * 10 + c[8] - two, .tm_hour = c[10] * 10 + c[11] - two, .tm_min = c[12] * 10 + c[13] - two }; handle->creation_date = mktime(&created); #undef c } /** * g1m_decode_std_addin: * Decodes a "normal" add-in (after Standard Header). * * @arg handle the handle. * @arg buffer the buffer to read from. * @return the error code (0 if ok). */ int g1m_decode_std_addin(g1m_t *handle, g1m_buffer_t *buffer, struct standard_header *std) { int err = 0; (void)std; /* get the subheader */ DREAD(hd, g1a_subheader) /* correct subheader endianess */ hd.filesize = be32toh(hd.filesize); /* log info about the subheader */ log_info("internal name is '%.8s'", hd.internal_name); log_info("title is '%.8s'", hd.title); log_info("estrips count is %" PRIu8, hd.estrips_count); log_info("version is %.10s", hd.version); log_info("creation date is %.14s", hd.creation_date); /* store data in the handle */ addin_set_data(handle, (char*)hd.title, 8, (char*)hd.internal_name, 8, (char*)hd.version, (char*)hd.creation_date); /* allocate space for icon */ handle->width = G1A_ICON_WIDTH; handle->height = G1A_ICON_HEIGHT; handle->pixels = alloc_pixels(G1A_ICON_WIDTH, G1A_ICON_HEIGHT); if (!handle->pixels) return (g1m_error_alloc); prepare_pixels(handle->pixels, G1A_ICON_WIDTH, G1A_ICON_HEIGHT) /* fill icon */ g1m_decode_picture(handle->pixels, g1m_pictureformat_1bit_packed, hd.icon, G1A_ICON_WIDTH, G1A_ICON_HEIGHT); /* skip size */ SKIP(hd.filesize - sizeof(struct standard_header) - sizeof(struct g1a_subheader)) /* no errors */ return (err); } /** * g1m_decode_std_addin_cg: * Decode fx-CG add-in (after Standard Header). * * @arg handle the handle. * @arg buffer the buffer to read from. * @arg std the standard header. * @return the error code (0 if ok). */ int g1m_decode_std_addin_cg(g1m_t *handle, g1m_buffer_t *buffer, struct standard_header *std) { int err = 0; /* get the subheader */ DREAD(hd, addin_cp_subheader) /* correct subheader endianness */ hd.checksum = be32toh(hd.checksum); hd.control = be32toh(hd.control); hd.filesize = be32toh(hd.filesize); /* control byte */ size_t content_size = hd.filesize - 4 - hd.magic[1] ? 0x7000 : 0x1000; if (hd.control != content_size) { log_fatal("control value is incorrect!"); log_fatal("calculated %" PRIuSIZE ", expected %" PRIu32, content_size, hd.control); return (g1m_error_magic); } /* start making checksum */ uint_fast32_t checksum = sizeof(struct standard_header) * 256 - g1m_checksum32(std, sizeof(struct standard_header), 0) + g1m_checksum32(&hd.magic, sizeof(struct addin_cp_subheader), 0); /* read subheader */ if (hd.magic[1]) { /* is Prizm */ DREAD(shd, g3a_subheader) checksum += g1m_checksum32(&shd, sizeof(struct g3a_subheader), 0); handle->pixels = alloc_pixels(G3A_ICON_WIDTH, G3A_ICON_HEIGHT); handle->width = G3A_ICON_WIDTH; handle->height = G3A_ICON_HEIGHT; if (!handle->pixels) return (g1m_error_alloc); prepare_pixels(handle->pixels, G3A_ICON_WIDTH, G3A_ICON_HEIGHT) g1m_decode_picture(handle->pixels, g1m_pictureformat_16bit, shd.unselected_icon_image, G3A_ICON_WIDTH, G3A_ICON_HEIGHT); } else { /* is C1A */ DREAD(shd, c1a_subheader) checksum += g1m_checksum32(&shd, sizeof(struct c1a_subheader), 0); handle->pixels = alloc_pixels(C1A_ICON_WIDTH, C1A_ICON_HEIGHT); handle->width = C1A_ICON_WIDTH; handle->height = C1A_ICON_HEIGHT; if (!handle->pixels) return (g1m_error_alloc); prepare_pixels(handle->pixels, C1A_ICON_WIDTH, C1A_ICON_HEIGHT); g1m_decode_picture(handle->pixels, g1m_pictureformat_1bit_packed, shd.icon, C1A_ICON_WIDTH, C1A_ICON_HEIGHT); } /* skip content for now */ if ((err = g1m_skip(buffer, content_size, &checksum))) goto fail; /* check the sum (yo!) */ err = g1m_error_magic; if (checksum != hd.checksum) { log_fatal("Invalid checksum!"); log_fatal("Header checksum is %" PRIu32 ", calculated checksum is %" PRIuFAST32, hd.checksum, checksum); goto fail; } /* log */ log_info("title is '%.16s'", hd.title); log_info("internal name is '%.11s'", hd.internal_name); log_info("version is '%.10s'", hd.version); log_info("timestamp is '%.14s'", hd.stamp); /* store basic data in the handle */ addin_set_data(handle, (char*)hd.title, 16, (char*)hd.internal_name, 12, (char*)hd.version, (char*)hd.stamp); /* no error */ return (0); fail: free(handle->pixels); return (err); }