diff --git a/pkg/noun/jets/e/zlib.c b/pkg/noun/jets/e/zlib.c index ecdb11a8e3..88b2849771 100644 --- a/pkg/noun/jets/e/zlib.c +++ b/pkg/noun/jets/e/zlib.c @@ -10,7 +10,7 @@ #include "noun.h" static void* -gzip_malloc(voidpf opaque, uInt items, uInt size) +zlib_malloc(voidpf opaque, uInt items, uInt size) { size_t len = items * size; void* result = u3a_malloc(len); @@ -18,131 +18,203 @@ gzip_malloc(voidpf opaque, uInt items, uInt size) } static void -gzip_free(voidpf opaque, voidpf address) +zlib_free(voidpf opaque, voidpf address) { u3a_free(address); } u3_noun -u3qe_gunzip(u3_noun zipped_octs) +_decompress(u3_atom pos, u3_noun octs, int window_bits) { - u3_atom head = u3h(zipped_octs); - u3_atom tail = u3t(zipped_octs); - c3_w tel_w = u3r_met(3, tail); - c3_w hed_w; - if ( c3n == u3r_safe_word(head, &hed_w) ) { - return u3m_bail(c3__fail); + u3_atom p_octs = u3h(octs); + u3_atom q_octs = u3t(octs); + + c3_w p_octs_w, pos_w; + + if ( c3n == u3r_safe_word(p_octs, &p_octs_w) ) { + return u3_none; + } + if (c3n == u3r_safe_word(pos, &pos_w)) { + return u3_none; } - c3_c* input; - if (c3y == u3a_is_cat(tail)) { - input = &tail; + c3_w len_w = u3r_met(3, q_octs); + + int leading_zeros = 0; + + if (p_octs_w > len_w) { + leading_zeros = p_octs_w - len_w; } else { - u3a_atom* vat_u = u3a_to_ptr(tail); - input = (c3_y*)vat_u->buf_w; + len_w = p_octs_w; + } + + // Bytestream exhausted + // + if (pos_w >= len_w) { + return u3_none; } - if ( tel_w > hed_w ) { - return u3m_error("subtract-underflow"); + c3_y* input; + + if (c3y == u3a_is_cat(q_octs)) { + input = (c3_y*)&q_octs + pos_w; + } + else { + u3a_atom* vat_u = u3a_to_ptr(q_octs); + input = (c3_y*)vat_u->buf_w + pos_w; } int ret; z_stream strm; - int leading_zeros = hed_w - tel_w; - - if (leading_zeros > 0) { - strm.avail_in = hed_w - leading_zeros; + if (pos_w < len_w) { + strm.avail_in = (len_w - pos_w); } else { - strm.avail_in = hed_w; + strm.avail_in = 0; } - strm.zalloc = gzip_malloc; - strm.zfree = gzip_free; + strm.zalloc = zlib_malloc; + strm.zfree = zlib_free; strm.opaque = Z_NULL; strm.next_in = input; - ret = inflateInit2(&strm, 16); - if (ret != 0) { + ret = inflateInit2(&strm, window_bits); + + if (ret != Z_OK) { u3l_log("%i", ret); u3l_log("%s", strm.msg); return u3m_bail(c3__exit); } - uint chunk = hed_w / 10; - strm.avail_out = 16384; - strm.next_out = u3a_malloc(16384); + c3_w chunk_w = len_w / 10; + u3i_slab sab_u; + +#define INIT_SZ 16384 + strm.avail_out = INIT_SZ; + u3i_slab_init(&sab_u, 3, INIT_SZ); + strm.next_out = sab_u.buf_y; void* this_address = strm.next_out; - ret = inflate(&strm, Z_FINISH); - - if (strm.total_in + leading_zeros == hed_w) { - int zero = 0; - strm.next_in = &zero; - for (int i=0; i -5 && ret < 0) || ret == 2) || (strm.avail_in == 0 && ret == Z_BUF_ERROR)) { - u3l_log("%i", ret); - u3l_log("%s", strm.msg); - return u3m_bail(c3__exit); - } +#define ZEROS_SZ 256 + c3_y zeros[ZEROS_SZ]; - while (strm.avail_in > 0) { - strm.avail_out = chunk; + if (leading_zeros) { + memset(zeros, 0, ZEROS_SZ); + } - this_address = u3a_realloc(this_address, (strm.total_out + chunk)); - strm.next_out = this_address + strm.total_out; + while ((ret = inflate(&strm, Z_FINISH)) == Z_BUF_ERROR) { - ret = inflate(&strm, Z_FINISH); + // Output exhausted: reallocate + // + if (strm.avail_out == 0) { + strm.avail_out = chunk_w; - if ((ret > -5 && ret < 0) || ret == 2) { - u3l_log("%i", ret); - u3l_log("%s", strm.msg); - return u3m_bail(c3__exit); + u3i_slab_grow(&sab_u, 3, strm.total_out + chunk_w); + strm.next_out = sab_u.buf_y + strm.total_out; } - } - if (strm.total_in + leading_zeros == hed_w) { - int zero = 0; - strm.next_in = &zero; - for (int i=0; i= len_w + && strm.total_in + pos_w < p_octs_w) { + + c3_w rem_w = p_octs_w - (strm.total_in + pos_w); + strm.next_in = zeros; + + if (rem_w > ZEROS_SZ) { + strm.avail_in = ZEROS_SZ; + } + else { + strm.avail_in = rem_w; + } + } + else { + u3l_log("%i", ret); + u3l_log("%s", strm.msg); + inflateEnd(&strm); + return u3m_bail(c3__exit); + } + } + else { + u3l_log("%i", ret); + u3l_log("%s", strm.msg); + inflateEnd(&strm); + return u3m_bail(c3__exit); + } } } - - if (ret < 0 || ret == 2) { + if (ret != Z_STREAM_END) { u3l_log("%i", ret); u3l_log("%s", strm.msg); + inflateEnd(&strm); return u3m_bail(c3__exit); } - - u3_noun unzipped_octs = u3nc(strm.total_out, u3i_bytes(strm.total_out, this_address)); ret = inflateEnd(&strm); - if (ret < 0 || ret == 2) { + if (ret != Z_OK) { u3l_log("%i", ret); u3l_log("%s", strm.msg); return u3m_bail(c3__exit); } - return unzipped_octs; + u3_noun decompressed_octs = u3nc(strm.total_out, u3i_slab_mint(&sab_u)); + u3_noun new_pos = pos_w + strm.total_in; + u3_noun new_stream = u3nc(u3i_word(new_pos), u3k(octs)); + + return u3nc(decompressed_octs, new_stream); +} + +u3_noun +u3qe_decompress_gzip(u3_atom pos, u3_noun octs) +{ + return _decompress(pos, octs, 31); +} +u3_noun +u3qe_decompress_zlib(u3_atom pos, u3_noun octs) +{ + return _decompress(pos, octs, 15); +} + +u3_noun +u3we_decompress_gzip(u3_noun cor) +{ + u3_atom pos; + u3_noun octs; + + u3_noun a = u3r_at(u3x_sam, cor); + u3x_cell(a, &pos, &octs); + + if(_(u3a_is_atom(pos)) && _(u3a_is_cell(octs))) { + return u3qe_decompress_gzip(pos, octs); + } + + else { + return u3m_bail(c3__exit); + } } u3_noun -u3we_gunzip(u3_noun cor) +u3we_decompress_zlib(u3_noun cor) { + u3_atom pos; + u3_noun octs; + u3_noun a = u3r_at(u3x_sam, cor); + u3x_cell(a, &pos, &octs); - if ( _(u3du(a)) ) { - return u3qe_gunzip(a); + if(_(u3a_is_atom(pos)) && _(u3a_is_cell(octs))) { + return u3qe_decompress_zlib(pos, octs); } + else { return u3m_bail(c3__exit); } diff --git a/pkg/noun/jets/q.h b/pkg/noun/jets/q.h index bfbde8a0f0..4dabd4b2c1 100644 --- a/pkg/noun/jets/q.h +++ b/pkg/noun/jets/q.h @@ -211,7 +211,9 @@ u3_noun u3qes_equ(u3_atom, u3_atom); u3_noun u3qes_gte(u3_atom, u3_atom); u3_noun u3qes_gth(u3_atom, u3_atom); - u3_noun u3qe_gunzip(u3_noun); + + u3_noun u3qe_decompress_zlib(u3_atom, u3_noun); + u3_noun u3qe_decompress_gzip(u3_atom, u3_noun); /** Tier 6. **/ diff --git a/pkg/noun/jets/tree.c b/pkg/noun/jets/tree.c index 2e0c3d1896..270a357cca 100644 --- a/pkg/noun/jets/tree.c +++ b/pkg/noun/jets/tree.c @@ -271,8 +271,12 @@ static c3_c* _140_hex_lune_ha[] = { }; static u3j_harm _137_hex__crc32_a[] = {{".2", u3we_crc32}, {}}; static u3j_core _137_hex__crc_d[] = {{"crc32", 7, _137_hex__crc32_a, 0, no_hashes }, {}}; -static u3j_harm _139_hex__gunzip_a[] = {{".2", u3we_gunzip}, {}}; -static u3j_core _139_hex__unzip_d[] = {{"gunzip", 7, _139_hex__gunzip_a, 0, no_hashes }, {}}; +static u3j_harm _139_hex__decompress_zlib_a[] = {{".2", u3we_decompress_zlib}, {}}; +static u3j_harm _139_hex__decompress_gzip_a[] = {{".2", u3we_decompress_gzip}, {}}; +static u3j_core _139_hex__zlib_d[] = { + {"decompress-zlib", 7, _139_hex__decompress_zlib_a, 0, no_hashes }, + {"decompress-gzip", 7, _139_hex__decompress_gzip_a, 0, no_hashes }, + {}}; static u3j_harm _140_hex_coed__ed_puck_a[] = {{".2", u3wee_puck}, {}}; static c3_c* _140_hex_coed__ed_puck_ha[] = { "1bc694675842345c50b0e20a2193bb5bcbb42f163fc832431a3d1822a81e4c98", @@ -2349,9 +2353,9 @@ static u3j_core _138_hex_d[] = { "leer", 63, _140_hex_leer_a, 0, no_hashes }, { "loss", 63, _140_hex_loss_a, 0, no_hashes }, { "lune", 127, _140_hex_lune_a, 0, no_hashes }, -// XX move me to 137 when it exists + // XX move me to 137 when it exists { "crc", 31, 0, _137_hex__crc_d, no_hashes }, - { "gzip", 31, 0, _139_hex__unzip_d, no_hashes }, + { "zlib", 31, 0, _139_hex__zlib_d, no_hashes }, { "coed", 63, 0, _140_hex_coed_d, no_hashes }, { "aes", 31, 0, _140_hex_aes_d, no_hashes }, diff --git a/pkg/noun/jets/w.h b/pkg/noun/jets/w.h index 146074037f..de3c81b791 100644 --- a/pkg/noun/jets/w.h +++ b/pkg/noun/jets/w.h @@ -290,8 +290,10 @@ u3_noun u3wes_equ(u3_noun); u3_noun u3wes_gte(u3_noun); u3_noun u3wes_gth(u3_noun); + u3_noun u3we_crc32(u3_noun); - u3_noun u3we_gunzip(u3_noun); + u3_noun u3we_decompress_zlib(u3_noun); + u3_noun u3we_decompress_gzip(u3_noun); /** Tier 6. **/