diff options
Diffstat (limited to 'buf.c')
-rw-r--r-- | buf.c | 65 |
1 files changed, 65 insertions, 0 deletions
@@ -1385,6 +1385,69 @@ static val buf_decompress(val buf) uw_throwf(error_s, lit("~a: decompression failed"), self, nao); } +static val str_compress(val str, val level_opt) +{ + val self = lit("str-compress"); + val level = default_arg(level_opt, negone); + int lev = c_int(level, self); + size_t sz; + unsigned char *u8 = utf8_dup_to_buf(c_str(str, self), &sz, 0); + uLong bound = compressBound(sz), zsize = bound; + mem_t *zdata = chk_malloc(bound); + + if (convert(uLong, sz) != sz) { + free(zdata); + err_oflow(self); + } + + if (compress2(zdata, &zsize, u8, sz, lev) != Z_OK) { + free(zdata); + uw_throwf(error_s, lit("~a: compression failed"), self, nao); + } + + zdata = chk_realloc(zdata, zsize); + return make_owned_buf(unum(zsize), zdata); +} + +static val str_decompress(val buf) +{ + val self = lit("str-decompress"); + struct buf *b = buf_handle(buf, self); + ucnum zsize = c_unum(b->len, self); + uLong zsz10 = 10 * zsize; + uLong size = if3(zsz10 > zsize, zsz10, convert(uLong, -1)); + mem_t *data = chk_malloc(size); + val ret = nil; + + for (;;) { + switch (uncompress(data, &size, b->data, zsize)) { + case Z_OK: + + data = chk_realloc(data, size); + ret = string_utf8_from_buf(coerce(char *, data), size); + free(data); + return ret; + case Z_BUF_ERROR: + if (size == convert(uLong, -1)) + break; + if (size * 2 > size) + size = size * 2; + else if (size == convert(uLong, -1)) + break; + else + size = convert(uLong, -1); + data = chk_realloc(data, size); + continue; + default: + break; + } + break; + } + + free(data); + uw_throwf(error_s, lit("~a: decompression failed"), self, nao); +} + #endif val buf_ash(val buf, val bits) @@ -2084,6 +2147,8 @@ void buf_init(void) #if HAVE_ZLIB reg_fun(intern(lit("buf-compress"), user_package), func_n2o(buf_compress, 1)); reg_fun(intern(lit("buf-decompress"), user_package), func_n1(buf_decompress)); + reg_fun(intern(lit("str-compress"), user_package), func_n2o(str_compress, 1)); + reg_fun(intern(lit("str-decompress"), user_package), func_n1(str_decompress)); #endif reg_fun(intern(lit("buf-ash"), user_package), func_n2(buf_ash)); |