diff --git a/include/libg1m.h b/include/libg1m.h index d3c47d4..89f99a6 100644 --- a/include/libg1m.h +++ b/include/libg1m.h @@ -154,9 +154,11 @@ extern int g1m_mcs_insert(g1m_t *handle, g1m_mcsfile_t **tofile, /* ************************************************************************** */ /* Version decoding/encoding */ extern int g1m_decode_version(const char *raw, g1m_version_t *version); +extern int g1m_encode_version(const g1m_version_t *version, char *raw); /* Date decoding/encoding */ extern int g1m_decode_date(const char *raw, time_t *date); +extern int g1m_encode_date(const time_t *date, char *raw); # ifdef __cplusplus } diff --git a/include/libg1m/internals.h b/include/libg1m/internals.h index 7fddbc3..846e8f1 100644 --- a/include/libg1m/internals.h +++ b/include/libg1m/internals.h @@ -92,8 +92,10 @@ if (err) goto fail; /* write */ -# define WRITE(BUF, SZ) \ - (*buffer->write)(buffer->cookie, (unsigned char*)(BUF), (SZ)); +# define WRITE(BUF, SZ) { \ + int WRITE_err = (*buffer->write)(buffer->cookie, \ + (unsigned char*)(BUF), (SZ)); \ + if (WRITE_err) return (WRITE_err); } # define DWRITE(S) WRITE(&(S), sizeof(S)) /* ************************************************************************** */ /* Decoding functions */ @@ -172,6 +174,14 @@ G1M_CASHFUNC(program) G1M_CASFUNC(matrix) G1M_CASFUNC(capture) /* ************************************************************************** */ +/* Handle encoding functions */ +/* ************************************************************************** */ +# define G1M_ENCFUNC(NAME) \ +extern int g1m_announce_##NAME(g1m_t *handle, size_t *size); \ +extern int g1m_encode_##NAME(g1m_t *handle, g1m_buffer_t *buffer); + +G1M_ENCFUNC(addin) +/* ************************************************************************** */ /* Picture utilities */ /* ************************************************************************** */ # define alloc_pixels(W, H) \ diff --git a/include/libg1m/picture.h b/include/libg1m/picture.h index 58ecc59..9f9afa9 100644 --- a/include/libg1m/picture.h +++ b/include/libg1m/picture.h @@ -25,6 +25,7 @@ extern "C" { /* picture format */ typedef int g1m_pictureformat_t; # define g1m_pictureformat_1bit 0x0100 +# define g1m_pictureformat_1bit_r 0x0101 # define g1m_pictureformat_1bit_packed 0x0110 # define g1m_pictureformat_1bit_packed_r 0x0111 # define g1m_pictureformat_1bit_packed_old 0x0120 diff --git a/src/decode/std/addin.c b/src/decode/std/addin.c index e37cea2..64a4140 100644 --- a/src/decode/std/addin.c +++ b/src/decode/std/addin.c @@ -65,9 +65,9 @@ int g1m_decode_std_addin(g1m_t **h, g1m_buffer_t *buffer, log_info("creation date is: %.24s", ctime(&handle->creation_date)); /* fill icon */ - g1m_decode_picture(handle->icon_unsel, g1m_pictureformat_1bit_packed, + g1m_decode_picture(handle->icon_unsel, g1m_pictureformat_1bit, hd.icon, handle->width, handle->height); - g1m_decode_picture(handle->icon_sel, g1m_pictureformat_1bit_packed_r, + g1m_decode_picture(handle->icon_sel, g1m_pictureformat_1bit_r, hd.icon, handle->width, handle->height); /* read content */ diff --git a/src/encode/addin.c b/src/encode/addin.c new file mode 100644 index 0000000..797994b --- /dev/null +++ b/src/encode/addin.c @@ -0,0 +1,82 @@ +/* ***************************************************************************** + * encode/addin.c -- encode an addin. + * 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_announce_addin: + * Announce an add-in's size. + * + * @arg handle the handle. + * @arg size the size to feed. + * @return the error code (0 if ok). + */ + +int g1m_announce_addin(g1m_t *handle, size_t *size) +{ + *size += sizeof(struct standard_header) + sizeof(struct g1a_subheader); + *size += handle->size; + return (0); +} + +/** + * g1m_encode_addin: + * Encode an add-in. + * + * @arg handle the handle. + * @arg buffer the buffer to which to write to. + * @return the error code (0 if ok). + */ + +int g1m_encode_addin(g1m_t *handle, g1m_buffer_t *buffer) +{ + /* make the StandardHeader up */ + size_t filesize; g1m_announce_addin(handle, &filesize); + struct standard_header std = { + .main_id = "USBPower", + .subtype = "\xF3\x00\x10\x00\x10\x00", + .filesize = htobe32((uint32_t)filesize), + .control = (filesize + 0x41) & 0xFF, + .control2 = (filesize + 0xB8) & 0xFF, + .number = 0xFFFF}; + + /* reverse it and output it */ + uint8_t *b = (void*)&std; + for (size_t i = 0; i < sizeof(struct standard_header); i++) b[i] = ~b[i]; + DWRITE(std) + + /* make the add-in subheader up and output it */ + filesize -= sizeof(struct standard_header); + struct g1a_subheader sub = { + .estrips_count = 0, + .filesize = htobe32(filesize)}; + strncpy((char*)sub.title, handle->title, 8); + strncpy((char*)sub.internal_name, handle->intname, 8); + g1m_encode_version(&handle->version, (char*)sub.version); + g1m_encode_date(&handle->creation_date, (char*)sub.creation_date); + g1m_encode_picture((const uint32_t**)handle->icon_unsel, + g1m_pictureformat_1bit, sub.icon, + G1A_ICON_WIDTH, G1A_ICON_HEIGHT); + DWRITE(sub) + + /* output the content */ + WRITE(handle->content, handle->size) + + /* no error! */ + return (0); +} diff --git a/src/encode/main.c b/src/encode/main.c index 12052aa..11cc0f2 100644 --- a/src/encode/main.c +++ b/src/encode/main.c @@ -17,8 +17,7 @@ * along with libg1m; if not, see . * ************************************************************************** */ #include -#define A(NAME) g1m_announce_##NAME -#define E(NAME) g1m_encode_##NAME +#define FUNCS(NAME) g1m_announce_##NAME, g1m_encode_##NAME /* ************************************************************************** */ /* Correspondances */ @@ -38,6 +37,9 @@ struct corresp { /* All correspondances */ static const struct corresp encodings[] = { + /* add-in types */ + {g1m_type_addin, g1m_platform_fx, FUNCS(addin)}, + /* sentinel */ {0, 0, NULL, NULL} }; @@ -71,7 +73,7 @@ int g1m_encode(g1m_t *handle, g1m_buffer_t *buffer) /* announce, if necessary */ if (buffer->announce) { - size_t size; + size_t size = 0; if ((err = (*c->announce)(handle, &size)) || (err = (*buffer->announce)(buffer->cookie, size))) return (err); diff --git a/src/manage/handle.c b/src/manage/handle.c index 51ead67..fb249f9 100644 --- a/src/manage/handle.c +++ b/src/manage/handle.c @@ -231,6 +231,8 @@ int g1m_make_addin(g1m_t **h, g1m_platform_t platform, size_t size, if (!handle->icon_sel) goto fail; /* prepare pictures */ + handle->width = width; + handle->height = height; prepare_pixels(handle->icon_unsel, width, height) prepare_pixels(handle->icon_sel, width, height) diff --git a/src/utils/date.c b/src/utils/date.c index 459e775..a5971b2 100644 --- a/src/utils/date.c +++ b/src/utils/date.c @@ -48,3 +48,23 @@ int g1m_decode_date(const char *c, time_t *t) *t = mktime(&date); return (0); } + +/** + * g1m_encode_date: + * Encode a date from a string. + * + * @arg t the source timestamp. + * @arg c the destination string. + * @return the error code (0 if ok). + */ + +int g1m_encode_date(const time_t *t, char *c) +{ + /* helper values */ + struct tm *date = gmtime(t); + char buf[15]; sprintf(buf, "%04u.%02u%02u.%02u%02u", + min(date->tm_year + 1900, 9999), date->tm_mon + 1, date->tm_mday, + date->tm_hour, date->tm_min); + memcpy(c, buf, 14); + return (0); +} diff --git a/src/utils/picture.c b/src/utils/picture.c index 60fe2ae..b4b4e4f 100644 --- a/src/utils/picture.c +++ b/src/utils/picture.c @@ -58,6 +58,36 @@ int g1m_decode_picture(uint32_t **pixels, g1m_pictureformat_t format, int msk; const unsigned char *o, *g, *b, *r2; size_t off; switch (format) { + case g1m_pictureformat_1bit: + for (unsigned int y = 0; y < height; y++) { + msk = 0x80; + for (unsigned int x = 0; x < width; x++) { + /* get pixel */ + pixels[y][x] = (*raw & msk) ? 0x000000 : 0xFFFFFF; + + /* go to next */ + raw += msk & 1; + msk = (msk >> 1) | ((msk & 1) << 7); + } + if (width & 0x7) raw++; + } + break; + + case g1m_pictureformat_1bit_r: + for (unsigned int y = 0; y < height; y++) { + msk = 0x80; + for (unsigned int x = 0; x < width; x++) { + /* get pixel */ + pixels[y][x] = (*raw & msk) ? 0xFFFFFF : 0x000000; + + /* go to next */ + raw += msk & 1; + msk = (msk >> 1) | ((msk & 1) << 7); + } + if (width & 0x7) raw++; + } + break; + case g1m_pictureformat_4bit_mono: raw = &raw[(height * width / 2) * 2]; case g1m_pictureformat_1bit_packed: @@ -214,6 +244,38 @@ int g1m_encode_picture(const uint32_t **pixels, g1m_pictureformat_t format, int msk; switch (format) { + case g1m_pictureformat_1bit: + memset(raw, 0, g1m_picturesize_1bit(width, height)); + for (unsigned int y = 0; y < height; y++) { + msk = 0x80; + for (unsigned int x = 0; x < width; x++) { + /* get pixel */ + if (!pixels[y][x]) *raw |= msk; + + /* go to next */ + raw += msk & 1; + msk = (msk >> 1) | ((msk & 1) << 7); + } + if (width & 0x7) raw++; + } + break; + + case g1m_pictureformat_1bit_r: + memset(raw, 0, g1m_picturesize_1bit(width, height)); + for (unsigned int y = 0; y < height; y++) { + msk = 0x80; + for (unsigned int x = 0; x < width; x++) { + /* get pixel */ + if (pixels[y][x]) *raw |= msk; + + /* go to next */ + raw += msk & 1; + msk = (msk >> 1) | ((msk & 1) << 7); + } + if (width & 0x7) raw++; + } + break; + case g1m_pictureformat_1bit_packed: msk = 0x80; for (unsigned int y = 0; y < height; y++) diff --git a/src/utils/version.c b/src/utils/version.c index 883738d..ed5ea1b 100644 --- a/src/utils/version.c +++ b/src/utils/version.c @@ -45,3 +45,20 @@ int g1m_decode_version(const char *raw, g1m_version_t *version) /* no error */ return (0); } + +/** + * g1m_encode_version: + * Encode a version into an 'MM.mm.ffff' formatted version string. + * + * @arg version the version to encode. + * @arg the string to encode into. + * @return the error code (if any). + */ + +int g1m_encode_version(const g1m_version_t *version, char *raw) +{ + char buf[11]; sprintf(buf, "%02u.%02u.%04u", + version->major, version->minor, version->revision); + memcpy(raw, buf, 10); + return (0); +}