diff --git a/firmware/SOURCES b/firmware/SOURCES index 71a11429cd..8d7232f206 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -270,6 +270,7 @@ common/unicode.c common/vuprintf.c common/zip.c common/adler32.c +common/inflate.c /* Display */ scroll_engine.c diff --git a/firmware/common/inflate.c b/firmware/common/inflate.c new file mode 100644 index 0000000000..26fd191690 --- /dev/null +++ b/firmware/common/inflate.c @@ -0,0 +1,759 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2021 by James Buren (libflate adaptations for RockBox) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/* Copyright 2021 Plan 9 Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "inflate.h" +#include +#include "adler32.h" +#include "crc32.h" +#include "system.h" + +enum { + INFLATE_BUFFER_SIZE = 32768, + INFLATE_SYMBOL_MAX = 288, + INFLATE_OFFSET_MAX = 32, + INFLATE_CODELEN_MAX = 19, + INFLATE_HUFF_BITS = 17, + INFLATE_FLAT_BITS = 7, + INFLATE_SYMBOL_BITS = 7, + INFLATE_OFFSET_BITS = 6, + INFLATE_CODELEN_BITS = 6, +}; + +struct inflate_huff { + uint32_t max_bits; + uint32_t min_bits; + uint32_t flat_mask; + uint32_t flat[1 << INFLATE_FLAT_BITS]; + uint32_t max_code[INFLATE_HUFF_BITS]; + uint32_t last[INFLATE_HUFF_BITS]; + uint32_t decode[INFLATE_SYMBOL_MAX]; +}; + +struct inflate { + uint8_t in[INFLATE_BUFFER_SIZE]; + uint8_t out[INFLATE_BUFFER_SIZE]; + union { + struct { + uint8_t len[INFLATE_SYMBOL_MAX]; + uint8_t off[INFLATE_OFFSET_MAX]; + }; + uint8_t combo[INFLATE_SYMBOL_MAX + INFLATE_OFFSET_MAX]; + }; + uint8_t clen[INFLATE_CODELEN_MAX]; + struct inflate_huff lentab; + struct inflate_huff offtab; + struct inflate_huff clentab; + uint32_t bits[INFLATE_HUFF_BITS]; + uint32_t codes[INFLATE_HUFF_BITS]; +}; + +#define INFLATE_FILL(E) do { \ + const uint32_t _size = read(is, sizeof(it->in), rctx); \ + if (_size == 0) { \ + rv = (E); \ + goto bail; \ + } \ + ip = is; \ + ie = is + _size; \ +} while (0) + +#define INFLATE_FLUSH(E) do { \ + const uint32_t _size = (op - os); \ + if (write(os, _size, wctx) != _size) { \ + rv = (E); \ + goto bail; \ + } \ + flushed = true; \ + if (st == INFLATE_ZLIB) \ + chksum = adler_32(os, _size, chksum); \ + else if (st == INFLATE_GZIP) \ + chksum = crc_32r(os, _size, chksum); \ + op = os; \ +} while (0) + +#define INFLATE_GET_BYTE(E,C) do { \ + if (ip == ie) \ + INFLATE_FILL(E); \ + (C) = ip[0]; \ + ++ip; \ +} while (0) + +#define INFLATE_PUT_BYTE(E,B) do { \ + if (op == oe) \ + INFLATE_FLUSH(E); \ + op[0] = (B); \ + ++op; \ +} while (0) + +#define INFLATE_FILL_BITS(E,N) do { \ + while ((N) > nbits) { \ + uint8_t _byte; \ + INFLATE_GET_BYTE(E, _byte); \ + sreg |= (_byte << nbits); \ + nbits += 8; \ + } \ +} while (0) + +#define INFLATE_CONSUME_BITS(N) do { \ + sreg >>= (N); \ + nbits -= (N); \ +} while (0) + +#define INFLATE_EXTRACT_BITS(N,B) do { \ + (B) = (sreg & ((1 << (N)) - 1)); \ + INFLATE_CONSUME_BITS(N); \ +} while (0) + +#define INFLATE_CHECK_LENGTH(E,N) do { \ + if ((N) > (ie - ip)) { \ + rv = (E); \ + goto bail; \ + } \ +} while (0) + +#define INFLATE_REVERSE(C,B) ({ \ + uint32_t _c = (C); \ + _c <<= (16 - (B)); \ + ((revtab[_c >> 8]) | (revtab[_c & 0xff] << 8)); \ +}) + +#define INFLATE_DECODE(E,H) ({ \ + __label__ _found; \ + uint32_t _c = (H)->flat[sreg & (H)->flat_mask]; \ + uint32_t _b = (_c & 0xff); \ + uint32_t _code; \ + if (_b == 0xff) { \ + for (_b = (_c >> 8); _b <= (H)->max_bits; _b++) { \ + _c = (revtab[sreg & 0xff] << 8); \ + _c |= (revtab[(sreg >> 8) & 0xff]); \ + _c >>= (16 - _b); \ + if (_c <= (H)->max_code[_b]) { \ + _code = (H)->decode[(H)->last[_b] - _c]; \ + goto _found; \ + } \ + } \ + rv = (E); \ + goto bail; \ + } \ + _code = (_c >> 8); \ +_found: \ + INFLATE_CONSUME_BITS(_b); \ + _code; \ +}) + +static int inflate_blocks(struct inflate* it, int st, inflate_reader read, void* rctx, inflate_writer write, void* wctx) { + int rv = 0; + uint8_t* is = it->in; + uint8_t* ip; + uint8_t* ie; + uint8_t* os = it->out; + uint8_t* op = os; + uint8_t* oe = os + sizeof(it->out); + bool flushed = false; + uint32_t chksum; + uint32_t nbits = 0; + uint32_t sreg = 0; + uint32_t i; + uint32_t j; + bool final; + uint8_t type; + + INFLATE_FILL(-1); + + if (st == INFLATE_ZLIB) { + uint16_t header; + + INFLATE_CHECK_LENGTH(-2, 2); + + header = (ip[0] << 8 | ip[1]); + ip += 2; + + if ((header % 31) != 0) { + rv = -3; + goto bail; + } + + if (((header & 0xf000) >> 12) > 7) { + rv = -4; + goto bail; + } + + if (((header & 0x0f00) >> 8) != 8) { + rv = -5; + goto bail; + } + + if (((header & 0x0020) >> 5) != 0) { + rv = -6; + goto bail; + } + + chksum = 1; + } else if (st == INFLATE_GZIP) { + uint8_t flg; + + INFLATE_CHECK_LENGTH(-7, 10); + + if (ip[0] != 0x1f || ip[1] != 0x8b) { + rv = -8; + goto bail; + } + + if (ip[2] != 8) { + rv = -9; + goto bail; + } + + flg = ip[3]; + + if ((flg & 0xe0) != 0) { + rv = -10; + goto bail; + } + + ip += 10; + chksum = 0xffffffff; + + if ((flg & 0x04) != 0) { + uint16_t xlen; + + INFLATE_CHECK_LENGTH(-11, 2); + + xlen = (ip[0] | ip[1] << 8); + ip += 2; + + while (xlen >= (ie - ip)) { + xlen -= (ie - ip); + + if ((flg & 0x02) != 0) + chksum = crc_32r(is, ie - is, chksum); + + INFLATE_FILL(-12); + } + + ip += xlen; + } + + if ((flg & 0x08) != 0) { + while (ip++[0] != '\0') { + if (ip == ie) { + if ((flg & 0x02) != 0) + chksum = crc_32r(is, ie - is, chksum); + + INFLATE_FILL(-13); + } + } + } + + if ((flg & 0x10) != 0) { + while (ip++[0] != '\0') { + if (ip == ie) { + if ((flg & 0x02) != 0) + chksum = crc_32r(is, ie - is, chksum); + + INFLATE_FILL(-14); + } + } + } + + if ((flg & 0x02) != 0) { + uint16_t crc16; + + INFLATE_CHECK_LENGTH(-15, 2); + + crc16 = (ip[0] | ip[1] << 8); + chksum = crc_32r(is, ip - is, chksum); + chksum &= 0xffff; + chksum ^= 0xffff; + + if (crc16 != chksum) { + rv = -16; + goto bail; + } + + ip += 2; + } + + chksum = 0xffffffff; + } else { + chksum = 0; + } + + do { + INFLATE_FILL_BITS(-17, 3); + final = (sreg & 0x01); + type = ((sreg & 0x06) >> 1); + INFLATE_CONSUME_BITS(3); + + if (type == 0) { + uint8_t header[4]; + uint32_t len; + uint32_t clen; + + INFLATE_CONSUME_BITS(nbits & 0x07); + + for (i = 0; i < 4; i++) { + if (nbits != 0) + INFLATE_EXTRACT_BITS(8, header[i]); + else + INFLATE_GET_BYTE(-18, header[i]); + } + + len = (header[0] | (header[1] << 8)); + clen = (header[2] | (header[3] << 8)) ^ 0xffff; + + if (len != clen) { + rv = -19; + goto bail; + } + + while (len != 0) { + if (ip == ie) + INFLATE_FILL(-20); + + if (op == oe) + INFLATE_FLUSH(-21); + + j = MIN(len, MIN((uint32_t) (ie - ip), (uint32_t) (oe - op))); + for (i = 0; i < j; i++) + op[i] = ip[i]; + + len -= j; + ip += j; + op += j; + } + } else if (type == 3) { + rv = -22; + goto bail; + } else { + static const uint8_t revtab[256] = + { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, + }; + uint8_t* tab[3]; + uint32_t tab_lens[3]; + uint32_t tab_bits[3]; + struct inflate_huff* tab_huffs[3] = { &it->lentab, &it->offtab, &it->clentab, }; + uint32_t c; + uint32_t k; + + if (type == 2) { + static const uint32_t min_tab_sizes[3] = { 257, 1, 4, }; + static const uint32_t min_tab_bits[3] = { 5, 5, 4, }; + static const uint32_t clen_order[INFLATE_CODELEN_MAX] = { + 16, 17, 18, 0, 8, + 7, 9, 6, 10, 5, + 11, 4, 12, 3, 13, + 2, 14, 1, 15, + }; + + INFLATE_FILL_BITS(-23, 14); + for (i = 0; i < 3; i++) { + INFLATE_EXTRACT_BITS(min_tab_bits[i], tab_lens[i]); + tab_lens[i] += min_tab_sizes[i]; + } + + tab[2] = it->clen; + for (i = 0; i < INFLATE_CODELEN_MAX; i++) + tab[2][i] = 0; + for (i = 0; i < tab_lens[2]; i++) { + INFLATE_FILL_BITS(-24, 3); + INFLATE_EXTRACT_BITS(3, tab[2][clen_order[i]]); + } + + tab[0] = it->combo; + tab_bits[0] = INFLATE_SYMBOL_BITS; + + tab[1] = tab[0] + tab_lens[0]; + tab_bits[1] = INFLATE_OFFSET_BITS; + + tab_lens[2] = INFLATE_CODELEN_MAX; + tab_bits[2] = INFLATE_CODELEN_BITS; + } else { + tab[0] = it->len; + for (i = 0; i < 144; i++) + tab[0][i] = 8; + for (; i < 256; i++) + tab[0][i] = 9; + for (; i < 280; i++) + tab[0][i] = 7; + for (; i < INFLATE_SYMBOL_MAX; i++) + tab[0][i] = 8; + tab_lens[0] = INFLATE_SYMBOL_MAX; + tab_bits[0] = INFLATE_FLAT_BITS; + + tab[1] = it->off; + for (i = 0; i < INFLATE_OFFSET_MAX; i++) + tab[1][i] = 5; + tab_lens[1] = INFLATE_OFFSET_MAX; + tab_bits[1] = INFLATE_FLAT_BITS; + } + + for(; type != 0xff; --type) { + const uint8_t* hb = tab[type]; + uint32_t hb_len = tab_lens[type]; + uint32_t flat_bits = tab_bits[type]; + struct inflate_huff* h = tab_huffs[type]; + uint32_t* bits = it->bits; + uint32_t* codes = it->codes; + uint32_t max_bits = 0; + uint32_t min_bits = INFLATE_HUFF_BITS + 1; + uint32_t min_code; + uint32_t b; + uint32_t code; + uint32_t fc; + uint32_t ec; + + for (i = 0; i < INFLATE_HUFF_BITS; i++) + bits[i] = 0; + + for (i = 0; i < hb_len; i++) { + b = hb[i]; + + if (b != 0) { + bits[b]++; + + if (b < min_bits) + min_bits = b; + + if (b > max_bits) + max_bits = b; + } + } + + if (max_bits == 0) { + h->flat_mask = h->min_bits = h->max_bits = 0; + goto table_done; + } + + h->max_bits = max_bits; + + for (b = c = code = 0; b <= max_bits; b++) { + h->last[b] = c; + c += bits[b]; + + min_code = (code << 1); + codes[b] = min_code; + code = (min_code + bits[b]); + + if (code > (1U << b)) { + rv = -25; + goto bail; + } + + h->max_code[b] = (code - 1); + h->last[b] += (code - 1); + } + + if (flat_bits > max_bits) + flat_bits = max_bits; + + h->flat_mask = ((1 << flat_bits) - 1); + + if (min_bits > flat_bits) + min_bits = flat_bits; + + h->min_bits = min_bits; + + for (i = 0, b = (1 << flat_bits); i < b; i++) + h->flat[i] = 0xffffffff; + + for (b = max_bits; b > flat_bits; b--) { + code = h->max_code[b]; + + if (code == 0xffffffff) + break; + + min_code = ((code + 1) - bits[b]); + min_code >>= (b - flat_bits); + code >>= (b - flat_bits); + + for (; min_code <= code; min_code++) + h->flat[INFLATE_REVERSE(min_code, flat_bits)] = ((b << 8) | 0xff); + } + + for (i = 0; i < hb_len; i++) { + b = hb[i]; + + if (b == 0) + continue; + + c = codes[b]++; + + if (b <= flat_bits) { + code = ((i << 8) | b); + ec = ((c + 1) << (flat_bits - b)); + + if (ec > (1U << flat_bits)) { + rv = -26; + goto bail; + } + + for (fc = (c << (flat_bits - b)); fc < ec; fc++) + h->flat[INFLATE_REVERSE(fc, flat_bits)] = code; + } + + if (b > min_bits) { + c = h->last[b] - c; + + if (c >= hb_len) { + rv = -27; + goto bail; + } + + h->decode[c] = i; + } + } + + table_done: + + if (type == 2) { + static const uint32_t bits[3] = { 2, 3, 7, }; + static const uint32_t bases[3] = { 3, 3, 11, }; + + for (i = 0, j = tab_lens[0] + tab_lens[1]; i < j; ) { + uint32_t len; + uint8_t byte; + + INFLATE_FILL_BITS(-28, h->max_bits); + + c = INFLATE_DECODE(-29, h); + + if (c < 16) { + tab[0][i++] = c; + continue; + } + + c -= 16; + + if (c == 0 && i == 0) { + rv = -30; + goto bail; + } + + INFLATE_FILL_BITS(-31, bits[c]); + INFLATE_EXTRACT_BITS(bits[c], len); + len += bases[c]; + + if ((i + len) > j) { + rv = -32; + goto bail; + } + + byte = ((c == 0) ? tab[0][i - 1] : 0); + for (k = 0; k < len; k++) + tab[0][i + k] = byte; + + i += len; + } + } + } + + while (1) { + static const uint32_t lenbase[INFLATE_SYMBOL_MAX - 257] = { + 3, 4, 5, 6, 7, 8, 9, 10, + 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, + 131, 163, 195, 227, 258, 0, 0, + }; + static const uint32_t lenextra[INFLATE_SYMBOL_MAX - 257] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, + 5, 5, 5, 5, 0, 0, 0, + }; + static const uint32_t offbase[INFLATE_OFFSET_MAX] = { + 1, 2, 3, 4, 5, 7, 9, 13, + 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, + 4097, 6145, 8193, 12289, 16385, 24577, 0, 0, + }; + static const uint32_t offextra[INFLATE_OFFSET_MAX] = { + 0, 0, 0, 0, 1, 1, 2, 2, + 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, + 11, 11, 12, 12, 13, 13, 0, 0, + }; + uint32_t len; + uint32_t off; + uint8_t* cp; + + INFLATE_FILL_BITS(-33, tab_huffs[0]->max_bits); + c = INFLATE_DECODE(-34, tab_huffs[0]); + + if (c < 256) { + INFLATE_PUT_BYTE(-35, c); + continue; + } + + if (c == 256) + break; + + if (c > 285) { + rv = -36; + goto bail; + } + + c -= 257; + INFLATE_FILL_BITS(-37, lenextra[c]); + INFLATE_EXTRACT_BITS(lenextra[c], len); + len += lenbase[c]; + + INFLATE_FILL_BITS(-38, tab_huffs[1]->max_bits); + c = INFLATE_DECODE(-39, tab_huffs[1]); + + if (c > 29) { + rv = -40; + goto bail; + } + + INFLATE_FILL_BITS(-41, offextra[c]); + INFLATE_EXTRACT_BITS(offextra[c], off); + off += offbase[c]; + + cp = op - off; + if (cp < os) { + if (!flushed) { + rv = -42; + goto bail; + } + + cp += sizeof(it->out); + } + + while (len != 0) { + if (op == oe) + INFLATE_FLUSH(-43); + + if (cp == oe) + cp = os; + + j = MIN(len, MIN((uint32_t) (oe - op), (uint32_t) (oe - cp))); + + for (i = 0; i < j; i++) + op[i] = cp[i]; + + op += j; + cp += j; + len -= j; + } + } + } + } while (!final); + + INFLATE_FLUSH(-44); + + if (st != INFLATE_RAW) { + uint8_t header[4]; + uint32_t chksum2; + + INFLATE_CONSUME_BITS(nbits & 0x07); + + for (i = 0; i < 4; i++) { + if (nbits != 0) + INFLATE_EXTRACT_BITS(8, header[i]); + else + INFLATE_GET_BYTE(-45, header[i]); + } + + if (st == INFLATE_ZLIB) { + chksum2 = ((header[0] << 24) | (header[1] << 16) | (header[2] << 8) | (header[3] << 0)); + + if (chksum != chksum2) { + rv = -46; + goto bail; + } + } else if (st == INFLATE_GZIP) { + chksum2 = ((header[3] << 24) | (header[2] << 16) | (header[1] << 8) | (header[0] << 0)); + + if (~chksum != chksum2) { + rv = -47; + goto bail; + } + } + } + +bail: + return rv; +} + +const uint32_t inflate_size = sizeof(struct inflate); +const uint32_t inflate_align = _Alignof(struct inflate); + +int inflate(struct inflate* it, int st, inflate_reader read, void* rctx, inflate_writer write, void* wctx) { + if (it == NULL || read == NULL || write == NULL || st < 0 || st > 2 || (((uintptr_t) it) & (_Alignof(struct inflate) - 1)) != 0) + return -48; + + return inflate_blocks(it, st, read, rctx, write, wctx); +} diff --git a/firmware/include/inflate.h b/firmware/include/inflate.h new file mode 100644 index 0000000000..b0685e8fbb --- /dev/null +++ b/firmware/include/inflate.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2021 by James Buren (libflate adaptations for RockBox) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef _INFLATE_H_ +#define _INFLATE_H_ + +#include + +enum { + INFLATE_RAW, + INFLATE_ZLIB, + INFLATE_GZIP, +}; + +struct inflate; + +typedef uint32_t inflate_reader(void* block, uint32_t block_size, void* ctx); +typedef uint32_t inflate_writer(const void* block, uint32_t block_size, void* ctx); + +extern const uint32_t inflate_size; +extern const uint32_t inflate_align; + +// 'it' must be allocated by the caller. it must be at least 'inflate_size' bytes +// and aligned at 'inflate_align' bytes. 'st' is the type of stream to decompress; +// see above enum for possible options. +int inflate(struct inflate* it, int st, inflate_reader read, void* rctx, inflate_writer write, void* wctx); + +#endif