cosmopolitan/libc/str/undeflate.c

264 lines
8.8 KiB
C
Raw Normal View History

2020-06-15 14:18:57 +00:00
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
2020-12-28 01:18:44 +00:00
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
2020-06-15 14:18:57 +00:00
2020-12-28 01:18:44 +00:00
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
2020-06-15 14:18:57 +00:00
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
Productionize new APE loader and more The APE_NO_MODIFY_SELF loader payload has been moved out of the examples folder and improved so that it works on BSD systems, and permits general elf program headers. This brings its quality up enough that it should be acceptable to use by default for many programs, e.g. Python, Lua, SQLite and Python. It's the responsibility of the user to define an appropriate TMPDIR if /tmp is considered an adversarial environment. Mac OS shall be supported by APE_NO_MODIFY_SELF soon. Fixes and improvements have been made to program_executable_name as it's now the one true way to get the absolute path of the executing image. This change fixes a memory leak in linenoise history loading, introduced by performance optimizations in 51904e2687c04d7ae20410cd94c2148972d6bae6 This change fixes a longstanding regression with Mach system calls, that 23ae9dfceb6f657862f00e674a8e4dc357a9d24d back in February which impacted our sched_yield() implementation, which is why no one noticed until now. The Blinkenlights PC emulator has been improved. We now fix rendering on XNU and BSD by not making the assumption that the kernel terminal driver understands UTF8 since that seems to break its internal modeling of \r\n which is now being addressed by using \e[𝑦H instead. The paneling is now more compact in real mode so you won't need to make your font as tiny if you're only emulating an 8086 program. The CLMUL ISA is now emulated too This change also makes improvement to time. CLOCK_MONOTONIC now does the right thing on Windows NT. The nanosecond time module functions added in Python 3.7 have been backported. This change doubles the performance of Argon2 password stretching simply by not using its copy_block and xor_block helper functions, as they were trivial to inline thus resulting in us needing to iterate over each 1024 byte block four fewer times. This change makes code size improvements. _PyUnicode_ToNumeric() was 64k in size and now it's 10k. The CJK codec lookup tables now use lazy delta zigzag deflate (δzd) encoding which reduces their size from 600k to 200k plus the code bloat caused by macro abuse in _decimal.c is now addressed so our fully-loaded statically-linked hermetically-sealed Python virtual interpreter container is now 9.4 megs in the default build mode and 5.5m in MODE=tiny which leaves plenty of room for chibicc. The pydoc web server now accommodates the use case of people who work by SSH'ing into a different machine w/ python.com -m pydoc -p8080 -h0.0.0.0 Finally Python Capsulae delenda est and won't be supported in the future
2021-10-02 15:17:04 +00:00
#include "libc/bits/weaken.h"
2020-06-15 14:18:57 +00:00
#include "libc/intrin/repmovsb.h"
#include "libc/macros.internal.h"
2020-06-15 14:18:57 +00:00
#include "libc/nexgen32e/kompressor.h"
Productionize new APE loader and more The APE_NO_MODIFY_SELF loader payload has been moved out of the examples folder and improved so that it works on BSD systems, and permits general elf program headers. This brings its quality up enough that it should be acceptable to use by default for many programs, e.g. Python, Lua, SQLite and Python. It's the responsibility of the user to define an appropriate TMPDIR if /tmp is considered an adversarial environment. Mac OS shall be supported by APE_NO_MODIFY_SELF soon. Fixes and improvements have been made to program_executable_name as it's now the one true way to get the absolute path of the executing image. This change fixes a memory leak in linenoise history loading, introduced by performance optimizations in 51904e2687c04d7ae20410cd94c2148972d6bae6 This change fixes a longstanding regression with Mach system calls, that 23ae9dfceb6f657862f00e674a8e4dc357a9d24d back in February which impacted our sched_yield() implementation, which is why no one noticed until now. The Blinkenlights PC emulator has been improved. We now fix rendering on XNU and BSD by not making the assumption that the kernel terminal driver understands UTF8 since that seems to break its internal modeling of \r\n which is now being addressed by using \e[𝑦H instead. The paneling is now more compact in real mode so you won't need to make your font as tiny if you're only emulating an 8086 program. The CLMUL ISA is now emulated too This change also makes improvement to time. CLOCK_MONOTONIC now does the right thing on Windows NT. The nanosecond time module functions added in Python 3.7 have been backported. This change doubles the performance of Argon2 password stretching simply by not using its copy_block and xor_block helper functions, as they were trivial to inline thus resulting in us needing to iterate over each 1024 byte block four fewer times. This change makes code size improvements. _PyUnicode_ToNumeric() was 64k in size and now it's 10k. The CJK codec lookup tables now use lazy delta zigzag deflate (δzd) encoding which reduces their size from 600k to 200k plus the code bloat caused by macro abuse in _decimal.c is now addressed so our fully-loaded statically-linked hermetically-sealed Python virtual interpreter container is now 9.4 megs in the default build mode and 5.5m in MODE=tiny which leaves plenty of room for chibicc. The pydoc web server now accommodates the use case of people who work by SSH'ing into a different machine w/ python.com -m pydoc -p8080 -h0.0.0.0 Finally Python Capsulae delenda est and won't be supported in the future
2021-10-02 15:17:04 +00:00
#include "libc/stdio/stdio.h"
2020-06-15 14:18:57 +00:00
#include "libc/str/str.h"
#include "libc/str/undeflate.h"
#define kDeflateCompressionTypeNone 0b00
#define kDeflateCompressionTypeFixedHuffman 0b01
#define kDeflateCompressionTypeDynamicHuffman 0b10
#define kDeflateCodeLengthCopyPrevious3To6Times 16
#define kDeflateCodeLengthRepeatZero3To10Times 17
#define kDeflateCodeLengthRepeatZero11To138Times 18
#define CONSUME(BITS) \
hold.word >>= BITS; \
hold.bits -= BITS
#define MOAR(BITS) \
while (hold.bits < BITS) { \
al = *ip++; \
hold.word |= (size_t)al << hold.bits; \
hold.bits += 8; \
}
struct DeflateHold {
size_t word;
size_t bits;
};
static const struct DeflateConsts {
uint16_t lenbase[32];
uint16_t distbase[32];
uint8_t lenbits[32];
uint8_t distbits[32];
uint8_t orders[19];
struct RlDecode lensrl[6];
} kDeflate = {
{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},
{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, 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, 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},
{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15},
{{144, 8}, {112, 9}, {24, 7}, {8, 8}, {32, 5}, {0, 0}},
};
static uint32_t undeflatetree(struct DeflateState *ds, uint32_t *tree,
const uint8_t *lens, size_t symcount) {
2020-06-15 14:18:57 +00:00
size_t i, len;
uint32_t code, slot;
uint16_t codes[16], first[16], counts[16];
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
bzero(counts, sizeof(counts));
2020-06-15 14:18:57 +00:00
for (i = 0; i < symcount; i++) {
counts[lens[i]]++;
}
codes[0] = 0;
first[0] = 0;
counts[0] = 0;
for (i = 1; i < ARRAYLEN(codes); i++) {
codes[i] = (codes[i - 1] + counts[i - 1]) << 1;
first[i] = first[i - 1] + counts[i - 1];
}
assert(first[15] + counts[15] <= symcount);
for (i = 0; i < symcount; i++) {
if ((len = lens[i])) {
code = codes[len]++;
slot = first[len]++;
tree[slot] = code << (32 - len) | i << 4 | len;
}
}
return first[15];
}
static struct DeflateHold undeflatesymbol(struct DeflateHold hold,
const uint32_t *tree,
size_t treecount,
uint32_t *out_symbol) {
2020-06-15 14:18:57 +00:00
size_t left, right, m;
uint32_t search, key;
left = 0;
right = treecount;
Make major improvements to redbean and libraries The most exciting improvement is dynamic pages will soon be able to use the executable itself as an object store. it required a heroic technique for overcoming ETXTBSY restrictions which lets us open the executable in read/write mode, which means (1) wa can restore the APE header, and (2) we can potentially containerize redbean extension code so that modules you download for your redbean online will only impact your redbean. Here's a list of breaking changes to redbean: - Remove /tool/net/ prefix from magic ZIP paths - GetHeader() now returns NIL if header is absent Here's a list of fixes and enhancements to redbean: - Support 64-bit ZIP archives - Record User-Agent header in logs - Add twelve error handlers to accept() - Display octal st_mode on listing page - Show ZIP file comments on listing page - Restore APE MZ header on redbean startup - Track request count on redbean index page - Report server uptime on redbean index page - Don't bind server socket using SO_REUSEPORT - Fix #151 where Lua LoadAsset() could free twice - Report rusage accounting when workers exit w/ -vv - Use ZIP iattr field as text/plain vs. binary hint - Add ParseUrl() API for parsing things like a.href - Add ParseParams() API for parsing HTTP POST bodies - Add IsAcceptablePath() API for checking dots, etc. - Add IsValidHttpToken() API for validating sane ASCII - Add IsAcceptableHostPort() for validating HOST[:PORT] - Send 400 response to HTTP/1.1 requests without a Host - Send 403 response if ZIP or file isn't other readable - Add virtual hosting that tries prepending Host to path - Route requests based on Host in Request-URI if present - Host routing will attempt to remove or add the www. prefix - Sign-extend UNIX timestamps and don't adjust FileTime zone Here's some of the improvements made to Cosmopolitan Libc: - Fix ape.S indentation - Improve consts.sh magnums - Write pretty good URL parser - Improve rusage accounting apis - Bring mremap() closer to working - Added ZIP APIs which will change - Check for overflow in reallocarray() - Remove overly fancy linkage in strerror() - Fix GDB attach on crash w/ OpenBSD msyscall() - Make sigqueue() portable to most UNIX distros - Make integer serialization macros more elegant - Bring back 34x tprecode8to16() performance boost - Make malloc() more resilient to absurdly large sizes
2021-04-18 18:34:59 +00:00
search = BITREVERSE16(hold.word);
2020-06-15 14:18:57 +00:00
search <<= 16;
search |= 0xffff;
while (left < right) { /* TODO(jart): Make this O(1) like Zlib. */
m = (left + right) >> 1;
if (search < tree[m]) {
right = m;
} else {
left = m + 1;
}
}
key = tree[left - 1];
assert(!((search ^ key) >> (32 - (key & 0xf))));
*out_symbol = (key >> 4) & 0xfff;
CONSUME(key & 0xf);
return hold;
}
/**
* Decompresses raw DEFLATE data.
*
* This is 10x smaller and 10x slower than chromium zlib.
*
* @param output should be followed by a single guard page, and have
* 36kb of guard pages preceding it too because buffer overflows
* are part of the design of this algorithm
2020-06-15 14:18:57 +00:00
* @note h/t Phil Katz, David Huffman, Claude Shannon
*/
ssize_t undeflate(void *output, size_t outputsize, void *input,
size_t inputsize, struct DeflateState *ds) {
2020-06-15 14:18:57 +00:00
struct DeflateHold hold;
bool isfinalblock;
size_t i, nlit, ndist;
Productionize new APE loader and more The APE_NO_MODIFY_SELF loader payload has been moved out of the examples folder and improved so that it works on BSD systems, and permits general elf program headers. This brings its quality up enough that it should be acceptable to use by default for many programs, e.g. Python, Lua, SQLite and Python. It's the responsibility of the user to define an appropriate TMPDIR if /tmp is considered an adversarial environment. Mac OS shall be supported by APE_NO_MODIFY_SELF soon. Fixes and improvements have been made to program_executable_name as it's now the one true way to get the absolute path of the executing image. This change fixes a memory leak in linenoise history loading, introduced by performance optimizations in 51904e2687c04d7ae20410cd94c2148972d6bae6 This change fixes a longstanding regression with Mach system calls, that 23ae9dfceb6f657862f00e674a8e4dc357a9d24d back in February which impacted our sched_yield() implementation, which is why no one noticed until now. The Blinkenlights PC emulator has been improved. We now fix rendering on XNU and BSD by not making the assumption that the kernel terminal driver understands UTF8 since that seems to break its internal modeling of \r\n which is now being addressed by using \e[𝑦H instead. The paneling is now more compact in real mode so you won't need to make your font as tiny if you're only emulating an 8086 program. The CLMUL ISA is now emulated too This change also makes improvement to time. CLOCK_MONOTONIC now does the right thing on Windows NT. The nanosecond time module functions added in Python 3.7 have been backported. This change doubles the performance of Argon2 password stretching simply by not using its copy_block and xor_block helper functions, as they were trivial to inline thus resulting in us needing to iterate over each 1024 byte block four fewer times. This change makes code size improvements. _PyUnicode_ToNumeric() was 64k in size and now it's 10k. The CJK codec lookup tables now use lazy delta zigzag deflate (δzd) encoding which reduces their size from 600k to 200k plus the code bloat caused by macro abuse in _decimal.c is now addressed so our fully-loaded statically-linked hermetically-sealed Python virtual interpreter container is now 9.4 megs in the default build mode and 5.5m in MODE=tiny which leaves plenty of room for chibicc. The pydoc web server now accommodates the use case of people who work by SSH'ing into a different machine w/ python.com -m pydoc -p8080 -h0.0.0.0 Finally Python Capsulae delenda est and won't be supported in the future
2021-10-02 15:17:04 +00:00
uint8_t *ip, *ipe, *op, *si, b, al, last, compressiontype;
2020-06-15 14:18:57 +00:00
uint32_t j, l, len, sym, tlit, tdist, tlen, nlen;
op = output;
ip = input;
Productionize new APE loader and more The APE_NO_MODIFY_SELF loader payload has been moved out of the examples folder and improved so that it works on BSD systems, and permits general elf program headers. This brings its quality up enough that it should be acceptable to use by default for many programs, e.g. Python, Lua, SQLite and Python. It's the responsibility of the user to define an appropriate TMPDIR if /tmp is considered an adversarial environment. Mac OS shall be supported by APE_NO_MODIFY_SELF soon. Fixes and improvements have been made to program_executable_name as it's now the one true way to get the absolute path of the executing image. This change fixes a memory leak in linenoise history loading, introduced by performance optimizations in 51904e2687c04d7ae20410cd94c2148972d6bae6 This change fixes a longstanding regression with Mach system calls, that 23ae9dfceb6f657862f00e674a8e4dc357a9d24d back in February which impacted our sched_yield() implementation, which is why no one noticed until now. The Blinkenlights PC emulator has been improved. We now fix rendering on XNU and BSD by not making the assumption that the kernel terminal driver understands UTF8 since that seems to break its internal modeling of \r\n which is now being addressed by using \e[𝑦H instead. The paneling is now more compact in real mode so you won't need to make your font as tiny if you're only emulating an 8086 program. The CLMUL ISA is now emulated too This change also makes improvement to time. CLOCK_MONOTONIC now does the right thing on Windows NT. The nanosecond time module functions added in Python 3.7 have been backported. This change doubles the performance of Argon2 password stretching simply by not using its copy_block and xor_block helper functions, as they were trivial to inline thus resulting in us needing to iterate over each 1024 byte block four fewer times. This change makes code size improvements. _PyUnicode_ToNumeric() was 64k in size and now it's 10k. The CJK codec lookup tables now use lazy delta zigzag deflate (δzd) encoding which reduces their size from 600k to 200k plus the code bloat caused by macro abuse in _decimal.c is now addressed so our fully-loaded statically-linked hermetically-sealed Python virtual interpreter container is now 9.4 megs in the default build mode and 5.5m in MODE=tiny which leaves plenty of room for chibicc. The pydoc web server now accommodates the use case of people who work by SSH'ing into a different machine w/ python.com -m pydoc -p8080 -h0.0.0.0 Finally Python Capsulae delenda est and won't be supported in the future
2021-10-02 15:17:04 +00:00
ipe = ip + inputsize;
2020-06-15 14:18:57 +00:00
hold.word = 0;
hold.bits = 0;
isfinalblock = 0;
while (!isfinalblock) {
MOAR(3);
isfinalblock = hold.word & 0b1;
CONSUME(1);
compressiontype = hold.word & 0b11;
CONSUME(2);
switch (compressiontype) {
case kDeflateCompressionTypeNone:
CONSUME(hold.bits & 7);
MOAR(32);
len = hold.word & 0xffff;
nlen = (hold.word >> 16) & 0xffff;
assert(len == ~nlen);
CONSUME(32);
while (len--) {
if (hold.bits) {
*op++ = hold.word;
CONSUME(8);
} else {
*op++ = *ip++;
}
}
continue;
case kDeflateCompressionTypeFixedHuffman:
nlit = 288;
ndist = 32;
rldecode(ds->lens, kDeflate.lensrl);
break;
case kDeflateCompressionTypeDynamicHuffman:
MOAR(5 + 5 + 4);
nlit = (hold.word & 0b11111) + 257;
CONSUME(5);
ndist = (hold.word & 0b11111) + 1;
CONSUME(5);
nlen = (hold.word & 0b1111) + 4;
CONSUME(4);
for (i = 0; i < nlen; i++) {
MOAR(3);
ds->lenlens[kDeflate.orders[i]] = hold.word & 0b111;
CONSUME(3);
}
for (; i < ARRAYLEN(ds->lenlens); i++) {
ds->lenlens[kDeflate.orders[i]] = 0;
}
tlen =
undeflatetree(ds, ds->lencodes, ds->lenlens, ARRAYLEN(ds->lenlens));
i = 0;
last = 0;
while (i < nlit + ndist) {
MOAR(16);
hold = undeflatesymbol(hold, ds->lencodes, tlen, &sym);
b = 2;
j = 1;
switch (sym) {
case kDeflateCodeLengthRepeatZero11To138Times:
b += 4;
j += 8;
/* fallthrough */
case kDeflateCodeLengthRepeatZero3To10Times:
b += 1;
last = 0;
/* fallthrough */
case kDeflateCodeLengthCopyPrevious3To6Times:
MOAR(b);
j += (hold.word & ((1u << b) - 1u)) + 2u;
CONSUME(b);
break;
default:
last = sym;
break;
}
while (j--) {
ds->lens[i++] = last;
}
}
break;
default:
return -1;
}
tlit = undeflatetree(ds, ds->litcodes, ds->lens, nlit);
tdist = undeflatetree(ds, ds->distcodes, &ds->lens[nlit], ndist);
do {
MOAR(16);
hold = undeflatesymbol(hold, ds->litcodes, tlit, &sym);
if (sym < 256) {
*op++ = sym;
} else if (sym > 256) {
sym -= 257;
b = kDeflate.lenbits[sym];
MOAR(b);
l = kDeflate.lenbase[sym] + (hold.word & ((1u << b) - 1));
CONSUME(b);
MOAR(16);
hold = undeflatesymbol(hold, ds->distcodes, tdist, &sym);
b = kDeflate.distbits[sym];
MOAR(b);
/* max readback: 24577 + 2**13-1 = 32768 */
si = op - ((uint32_t)kDeflate.distbase[sym] +
(uint32_t)(hold.word & ((1u << b) - 1)));
CONSUME(b);
repmovsb(&op, &si, l);
}
} while (sym != 256);
}
return 0;
}