/* ***************************************************************************** * decode/std/picture.c -- decode a picture 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 #include /* ************************************************************************** */ /* Obfuscation-related functions */ /* ************************************************************************** */ /** * g3p_deobfuscate: * De-obfuscate the image data. * * @arg buf the buffer. * @arg n the buffer size. */ static void g3p_deobfuscate(uint8_t *buf, size_t n) { while (n--) { int byte = *buf; *buf++ = ~((byte << 5) | (byte >> 3)) & 0xFF; } } /* ************************************************************************** */ /* Prizm Picture decoding function */ /* ************************************************************************** */ /** * g1m_decode_std_g3p: * Decode a G3P file. * * @arg handle the handle. * @arg buffer the buffer to read from. * @arg std the standard header. * @arg pic the standard picture header. * @return the error code (0 if ok). */ int g1m_decode_std_g3p(g1m_t **h, g1m_buffer_t *buffer, struct standard_header *std, struct standard_picheader *pic) { int err; *h = NULL; uint8_t *defbuf = NULL, *infbuf = NULL; /* start a checksum */ uint32_t check = g1m_checksum32((void*)std, sizeof(struct standard_header), 0); check = g1m_checksum32((void*)pic, sizeof(struct standard_picheader), check); /* read the image header */ DREAD(ihd, g3p_subheader) check = g1m_checksum32(&ihd, sizeof(struct g3p_subheader), check); unsigned int width = be16toh(ihd.width), height = be16toh(ihd.height); int color_depth = be16toh(ihd.color_depth); /* log info */ log_info("Width: %upx, height: %upx", width, height); log_info("Pixel depth: %s", (color_depth == g3p_color_4bit) ? "4-bit" : "16-bit"); log_info("Generator ID: 0x%04X", be16toh(ihd.generator_id)); log_info("-"); /* read deflated image */ size_t deflated_image_size = be32toh(ihd.data_size) - 6; log_info("Reading %" PRIuSIZE "B of deflated data", deflated_image_size); err = g1m_error_alloc; defbuf = malloc(deflated_image_size); if (!defbuf) goto fail; READ(defbuf, deflated_image_size) /* unobfuscate if required */ int is_obfuscated = ((std->obfuscated + 8) & 0xff) != ((std->filesize & 0xff00) >> 8); if (is_obfuscated) { log_info("Is obfuscated, let's deobfuscate!"); g3p_deobfuscate(defbuf, deflated_image_size); } /* make the destination buffer */ size_t rawsize = color_depth == g3p_color_4bit ? g1m_picturesize_4bit_code(width, height) : g1m_picturesize_16bit(width, height); err = g1m_error_alloc; infbuf = malloc(rawsize); if (!infbuf) goto fail; /* uncompress */ uLongf inflated_size = 0L; // rawsize? int z_err = uncompress(infbuf, &inflated_size, defbuf, deflated_image_size); if (z_err) { log_fatal("Zlib error: error #%d", z_err); err = g1m_error_magic; goto fail; } free(defbuf); defbuf = NULL; /* check the checksum */ uint32_t checksum; READ(&checksum, sizeof(uint32_t)) uLong adl = adler32(0, defbuf, deflated_image_size); if (adl != (uLong)checksum) { log_fatal("Incorrect Adler32 checksum!"); log_fatal("Expected 0x%08" PRIX32 ", got 0x%08lX", checksum, adl); err = g1m_error_checksum; goto fail; } /* make the handle */ err = g1m_make_picture(h, ihd.width, ihd.height); if (err) goto fail; g1m_t *handle = *h; /* then store it */ g1m_decode_picture(handle->pixels, ihd.color_depth == g3p_color_4bit ? g1m_pictureformat_4bit_code : g1m_pictureformat_16bit, infbuf, handle->width, handle->height); free(infbuf); infbuf = NULL; /* TODO: footers? */ /* no error */ return (0); fail: g1m_free(*h); *h = NULL; free(infbuf); free(defbuf); return (err); } /* ************************************************************************** */ /* Classpad Picture decoding function */ /* ************************************************************************** */ /** * g1m_decode_std_c2p: * Decode Classpad images. * * @arg handle the handle. * @arg buffer the buffer to read from. * @arg std the standard header. * @arg pic the standard picture header. * @return the error code (0 if ok). */ int g1m_decode_std_c2p(g1m_t **h, g1m_buffer_t *buffer, struct standard_header *std, struct standard_picheader *pic) { (void)h; (void)buffer; (void)std; (void)pic; /* TODO */ log_info("C2P files are not managed yet."); /* no error */ return (g1m_error_magic); }