/* ************************************************************************** */ /* _____ _ */ /* parse/addin.c |_ _|__ _ _| |__ ___ _ _ */ /* | Project: libg1m | |/ _ \| | | | '_ \ / _ \ | | | */ /* | | (_) | |_| | | | | __/ |_| | */ /* By: thomas |_|\___/ \__,_|_| |_|\___|\__, |.fr */ /* Last updated: 2016/12/01 13:33:45 |___/ */ /* */ /* ************************************************************************** */ #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_parse_addin: * Parse "normal" add-in (after Standard Header). * * @arg handle the handle. * @arg stream the stream to parse from. * @return the error code (0 if ok). */ int g1m_parse_addin(g1m_t *handle, FILE *stream, struct standard_header *std) { (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_pixels_from_packed1bit(handle->pixels, hd.icon, G1A_ICON_WIDTH, G1A_ICON_HEIGHT); /* skip size */ SKIP(hd.filesize - sizeof(struct standard_header) - sizeof(struct g1a_subheader)) /* no errors */ return (0); } /** * g1m_parse_addin_cg: * Parse fx-CG add-in (after Standard Header). * * @arg handle the handle. * @arg stream the stream to parse from. * @arg std the standard header. * @return the error code (0 if ok). */ int g1m_parse_addin_cg(g1m_t *handle, FILE *stream, 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_pixels_from_16bits(handle->pixels, 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_pixels_from_packed1bit(handle->pixels, shd.icon, C1A_ICON_WIDTH, C1A_ICON_HEIGHT); } /* skip content for now */ if ((err = g1m_parse_skip(stream, 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); }