*/ REBSER *Decompress(REBSER *input, REBCNT index, REBINT len, REBCNT limit, REBFLG use_crc) /* ** Decompress a binary (only). ** ***********************************************************************/ { REBCNT size; REBSER *output; REBINT err; if (len < 0 || (index + len > BIN_LEN(input))) len = BIN_LEN(input) - index; // Get the size from the end and make the output buffer that size. if (len <= 4) Trap0(RE_PAST_END); // !!! better msg needed size = Bytes_To_Long(BIN_SKIP(input, len) - 4); if (limit && size > limit) Trap_Num(RE_SIZE_LIMIT, size); output = Make_Binary(size + 20); // (Why 20 extra? -CS) //DISABLE_GC; err = Z_uncompress(BIN_HEAD(output), (uLongf*)&size, BIN_HEAD(input) + index, len, use_crc); if (err) { if (PG_Boot_Phase < 2) return 0; if (err == Z_MEM_ERROR) Trap0(RE_NO_MEMORY); SET_INTEGER(DS_RETURN, err); Trap1(RE_BAD_PRESS, DS_RETURN); //!!!provide error string descriptions } SET_STR_END(output, size); SERIES_TAIL(output) = size; //ENABLE_GC; return output; }
*/ REBSER *Compress(REBSER *input, REBINT index, REBINT len, REBFLG use_crc) /* ** Compress a binary (only). ** data ** /part ** length ** /crc32 ** ** Note: If the file length is "small", it can't overrun on ** compression too much so we use our magic numbers; otherwise, ** we'll just be safe by a percentage of the file size. This may ** be a bit much, though. ** ***********************************************************************/ { // NOTE: The use_crc flag is not present in Zlib 1.2.8 // Instead, compress's fifth paramter is the compression level // It can be a value from 1 to 9, or Z_DEFAULT_COMPRESSION if you // want it to pick what the library author considers the "worth it" // tradeoff of time to generally suggest. uLongf size; REBSER *output; REBINT err; REBYTE out_size[sizeof(REBCNT)]; if (len < 0) Trap_DEAD_END(RE_PAST_END); // !!! better msg needed size = len + (len > STERLINGS_MAGIC_NUMBER ? len / 10 + 12 : STERLINGS_MAGIC_FIX); output = Make_Binary(size); //DISABLE_GC; // !!! why?? // dest, dest-len, src, src-len, level err = z_compress2(BIN_HEAD(output), &size, BIN_HEAD(input) + index, len, Z_DEFAULT_COMPRESSION); if (err) { REBVAL arg; if (err == Z_MEM_ERROR) Trap_DEAD_END(RE_NO_MEMORY); SET_INTEGER(&arg, err); Trap1_DEAD_END(RE_BAD_PRESS, &arg); //!!!provide error string descriptions } SET_STR_END(output, size); SERIES_TAIL(output) = size; REBCNT_To_Bytes(out_size, (REBCNT)len); // Tag the size to the end. Append_Series(output, (REBYTE*)out_size, sizeof(REBCNT)); if (SERIES_AVAIL(output) > 1024) // Is there wasted space? output = Copy_Series(output); // Trim it down if too big. !!! Revisit this based on mem alloc alg. //ENABLE_GC; return output; }
*/ REBSER *Compress(REBSER *input, REBINT index, REBINT len, REBFLG use_crc) /* ** Compress a binary (only). ** data ** /part ** length ** /crc32 ** ** Note: If the file length is "small", it can't overrun on ** compression too much so we use our magic numbers; otherwise, ** we'll just be safe by a percentage of the file size. This may ** be a bit much, though. ** ***********************************************************************/ { REBCNT size; REBSER *output; REBINT err; REBYTE out_size[4]; if (len < 0) Trap0(RE_PAST_END); // !!! better msg needed size = len + (len > STERLINGS_MAGIC_NUMBER ? len / 10 + 12 : STERLINGS_MAGIC_FIX); output = Make_Binary(size); //DISABLE_GC; // !!! why?? // dest, dest-len, src, src-len, level err = Z_compress2(BIN_HEAD(output), (uLongf*)&size, BIN_HEAD(input) + index, len, use_crc); if (err) { if (err == Z_MEM_ERROR) Trap0(RE_NO_MEMORY); SET_INTEGER(DS_RETURN, err); Trap1(RE_BAD_PRESS, DS_RETURN); //!!!provide error string descriptions } SET_STR_END(output, size); SERIES_TAIL(output) = size; Long_To_Bytes(out_size, (REBCNT)len); // Tag the size to the end. Append_Series(output, (REBYTE*)out_size, 4); if (SERIES_AVAIL(output) > 1024) // Is there wasted space? output = Copy_Series(output); // Trim it down if too big. !!! Revisit this based on mem alloc alg. //ENABLE_GC; return output; }
*/ REBSER *Decompress(const REBYTE *data, REBCNT len, REBCNT limit, REBFLG use_crc) /* ** Decompress a binary (only). ** ** Rebol's compress/decompress functions store an extra length ** at the tail of the data, to double-check the zlib result ** ***********************************************************************/ { // NOTE: The use_crc flag is not present in Zlib 1.2.8 // There is no fifth parameter to uncompress matching the fifth to compress uLongf size; REBSER *output; REBINT err; // Get the size from the end and make the output buffer that size. if (len <= 4) Trap_DEAD_END(RE_PAST_END); // !!! better msg needed size = Bytes_To_REBCNT(data + len - sizeof(REBCNT)); // NOTE: You can hit this if you 'make prep' without doing a full rebuild // (If you 'make clean' and build again and this goes away, it was that) if (limit && size > limit) Trap_Num(RE_SIZE_LIMIT, size); output = Make_Binary(size); //DISABLE_GC; err = z_uncompress(BIN_HEAD(output), &size, data, len); if (err) { REBVAL arg; if (PG_Boot_Phase < 2) return 0; if (err == Z_MEM_ERROR) Trap_DEAD_END(RE_NO_MEMORY); SET_INTEGER(&arg, err); Trap1_DEAD_END(RE_BAD_PRESS, &arg); //!!!provide error string descriptions } SET_STR_END(output, size); SERIES_TAIL(output) = size; //ENABLE_GC; return output; }
*/ REBSER *Compress(REBSER *input, REBINT index, REBCNT len, REBFLG gzip, REBFLG raw) /* ** This is a wrapper over Zlib which will compress a BINARY! ** series to produce another BINARY!. It can use either gzip ** or zlib envelopes, and has a "raw" option for no header. ** ** !!! Adds 32-bit size info to zlib non-raw compressions for ** compatibility with Rebol2 and R3-Alpha, at the cost of ** inventing yet-another-format. Consider removing. ** ** !!! Does not expose the "streaming" ability of zlib. ** ***********************************************************************/ { REBCNT buf_size; REBSER *output; int ret; z_stream strm; assert(BYTE_SIZE(input)); // must be BINARY! // compression level can be a value from 1 to 9, or Z_DEFAULT_COMPRESSION // if you want it to pick what the library author considers the "worth it" // tradeoff of time to generally suggest. // strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; ret = deflateInit2( &strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, raw ? (gzip ? window_bits_gzip_raw : window_bits_zlib_raw) : (gzip ? window_bits_gzip : window_bits_zlib), 8, Z_DEFAULT_STRATEGY ); if (ret != Z_OK) raise Error_Compression(&strm, ret); // http://stackoverflow.com/a/4938401/211160 buf_size = deflateBound(&strm, len); strm.avail_in = len; strm.next_in = BIN_HEAD(input) + index; output = Make_Binary(buf_size); strm.avail_out = buf_size; strm.next_out = BIN_HEAD(output); ret = deflate(&strm, Z_FINISH); deflateEnd(&strm); if (ret != Z_STREAM_END) raise Error_Compression(&strm, ret); SET_STR_END(output, buf_size - strm.avail_out); SERIES_TAIL(output) = buf_size - strm.avail_out; if (gzip) { // GZIP contains its own CRC. It also has a 32-bit uncompressed // length (and CRC), conveniently (and perhaps confusingly) at the // tail in the same format that Rebol used. REBCNT gzip_len = Bytes_To_REBCNT( SERIES_DATA(output) + buf_size - strm.avail_out - sizeof(REBCNT) ); assert(len == gzip_len); } else if (!raw) { // Add 32-bit length to the end. // // !!! In ZLIB format the length can be found by decompressing, but // not known a priori. So this is for efficiency. It would likely be // better to not include this as it only confuses matters for those // expecting the data to be in a known format...though it means that // clients who wanted to decompress to a known allocation size would // have to save the size somewhere. REBYTE out_size[sizeof(REBCNT)]; REBCNT_To_Bytes(out_size, cast(REBCNT, len)); Append_Series(output, cast(REBYTE*, out_size), sizeof(REBCNT)); }