size_t up_unpack_step( void* outbuf_ptr, size_t outbuf_size, size_t* data_left ) { lib_zstream_unpack.next_out = outbuf_ptr; lib_zstream_unpack.avail_out = outbuf_size; int result; size_t input_size = lib_zstream_unpack.avail_in; result = z_inflate( &lib_zstream_unpack, Z_NO_FLUSH ); switch (result) { case Z_OK: case Z_STREAM_END: lib_unpack_left -= input_size - lib_zstream_unpack.avail_in; if (data_left != NULL) { *data_left = lib_zstream_unpack.avail_in; } return outbuf_size - lib_zstream_unpack.avail_out; break; default: lib_error = result; return 0; } }
bool ON_UncompressStream::End() { if ( 0 == m_implementation ) { ErrorHandler(); return false; } struct ON_ZlibImplementation* imp = (struct ON_ZlibImplementation*)m_implementation; z_stream& strm = imp->m_strm; if ( 0 != strm.avail_in || 0 != strm.next_in ) { // strm.avail_in is always zero when we leave an ON_UncompressStream function. ErrorHandler(); return false; } const ON__UINT32 sizeof_out_buffer = (ON__UINT32)(sizeof(imp->m_zlib_out_buffer)); void* out_buffer = imp->m_zlib_out_buffer; int zrc = Z_OK; bool rc = false; ON__UINT32 inflate_output_count; // counter prevents infinte loops if there is a bug in zlib return codes. for( int counter = 512; counter > 0; counter-- ) { // provide storage for compressed stream output strm.avail_in = 0; strm.next_in = 0; strm.next_out = (z_Bytef*)out_buffer; strm.avail_out = sizeof_out_buffer; // finish compression calculation zrc = z_inflate( &strm, Z_FINISH ); if ( zrc < 0 ) { // Something went haywire - bail out. ErrorHandler(); rc = false; break; } inflate_output_count = sizeof_out_buffer - strm.avail_out; if ( inflate_output_count > 0 ) { // The last call to inflate created uncompressed output. // Send the output to the uncompressed stream handler. // Calculate the updated crc and size before we call // the output handler because someday sombody will // decide it's a good idea to modify the values // in the buffer argument. ON__UINT32 out_crc1 = ON_CRC32( m_out_crc, inflate_output_count, out_buffer); ON__UINT64 out_size1 = m_out_size + inflate_output_count; rc = (0 != m_out_callback_function) ? m_out_callback_function( m_out_callback_context, inflate_output_count, out_buffer ) : Out( m_out_callback_context, inflate_output_count, out_buffer ); if ( !rc ) break; // Update compressed stream crc and size m_out_crc = out_crc1; m_out_size = out_size1; counter = 512; // created output - reset counter that detects stalls } if ( Z_STREAM_END == zrc ) { // no input left, all pending compressing is finished, // and all compressed output has been returned. rc = true; break; } } strm.avail_in = 0; strm.next_in = 0; strm.next_out = 0; strm.avail_out = 0; inflateEnd(&strm); onfree(m_implementation); m_implementation = 0; return rc; }
bool ON_UncompressStream::In( ON__UINT64 size, const void* compressed_buffer ) { if ( size <= 0 ) return true; if ( 0 == m_implementation ) { ErrorHandler(); return false; } if ( 0 == compressed_buffer ) { ErrorHandler(); return false; } struct ON_ZlibImplementation* imp = (struct ON_ZlibImplementation*)m_implementation; z_stream& strm = imp->m_strm; if ( 0 != strm.avail_in || 0 != strm.next_in ) { // strm.avail_in is always zero when we leave an ON_UncompressStream function. ErrorHandler(); return false; } const ON__UINT32 sizeof_out_buffer = (ON__UINT32)(sizeof(imp->m_zlib_out_buffer)); void* out_buffer = imp->m_zlib_out_buffer; int zrc = Z_OK; const ON__UINT64 max_sz = 0x7FFFFFF0; bool rc = false; ON__UINT32 inflate_output_count; // counter prevents infinte loops if there is a bug in zlib return codes. for( int counter = 512; counter > 0; counter-- ) { // Call zlib's inflate function. It can process // more compressed input from strm.next_in[], create more // uncompressed output in strm.next_out[], or do both. // provide storage for uncompressed stream output strm.next_out = (z_Bytef*)out_buffer; strm.avail_out = sizeof_out_buffer; if ( strm.avail_in <= 0 ) { if ( size <= 0 ) { // finshed with compressed input break; } // submit a portion of compressed_buffer to zlib ON__UINT64 sz = (size > max_sz) ? max_sz : size; m_in_size += sz; m_in_crc = ON_CRC32(m_in_crc,(size_t)sz,compressed_buffer); // (size_t) cast is safe because sz <= max_sz = 0x7FFFFFF0 strm.next_in = (z_Bytef*)compressed_buffer; strm.avail_in = (ON__UINT32)sz; compressed_buffer = ((const unsigned char*)compressed_buffer) + sz; size -= sz; counter = 512; // added input - reset the counter that detects stalls } // calculate compression ON__UINT32 avail_in0 = strm.avail_in; ON__UINT32 avail_out0 = strm.avail_out; zrc = z_inflate( &strm, Z_NO_FLUSH ); if ( zrc < 0 ) { // Something went haywire - bail out. ErrorHandler(); rc = false; break; } if ( strm.avail_in < avail_in0 || strm.avail_out > avail_out0 ) { // zlib did something rc = true; } inflate_output_count = sizeof_out_buffer - strm.avail_out; if ( inflate_output_count > 0 ) { // The last call to inflate created uncompressed output. // Send the output to the uncompressed stream handler. // Calculate the updated crc and size before we call // the output handler because someday sombody will // decide it's a good idea to modify the values // in the buffer argument. ON__UINT32 out_crc1 = ON_CRC32( m_out_crc, inflate_output_count, out_buffer); ON__UINT64 out_size1 = m_out_size + inflate_output_count; rc = (0 != m_out_callback_function) ? m_out_callback_function( m_out_callback_context, inflate_output_count, out_buffer ) : Out( m_out_callback_context, inflate_output_count, out_buffer ); if ( !rc ) break; // Update compressed stream crc and size m_out_crc = out_crc1; m_out_size = out_size1; counter = 512; // created output - reset counter that detects stalls } if ( size <= 0 && strm.avail_in <= 0 ) { // no input left break; } } strm.avail_in = 0; strm.next_in = 0; strm.next_out = 0; strm.avail_out = 0; return rc; }
bool ON_BinaryArchive::ReadInflate( size_t sizeof___outbuffer, // sizeof uncompressed data void* out___buffer // buffer for uncompressed data ) { const size_t max_avail = 0x7FFFFFF0; // See max_avail comment in ON_BinaryArchive::WriteInflate size_t sizeof__inbuffer = 0; void* in___buffer = 0; bool rc = false; // read compressed buffer from 3dm archive bool bValidCompressedBuffer = false; { ON__UINT32 tcode = 0; ON__INT64 big_value = 0; rc = BeginRead3dmBigChunk(&tcode,&big_value ); if (!rc) { if ( 0 != out___buffer && sizeof___outbuffer > 0 ) memset(out___buffer,0,sizeof___outbuffer); return false; } if ( tcode == TCODE_ANONYMOUS_CHUNK && big_value > 4 && sizeof___outbuffer > 0 && 0 != out___buffer ) { // read compressed buffer from the archive sizeof__inbuffer = (size_t)(big_value-4); // the last 4 bytes in this chunk are a 32 bit crc in___buffer = onmalloc(sizeof__inbuffer); if ( !in___buffer ) { rc = false; } else { rc = ReadByte( sizeof__inbuffer, in___buffer ); } } else { // Either I have the wrong chunk, or the input // parameters are bogus. rc = false; } int c0 = m_bad_CRC_count; if ( !EndRead3dmChunk() ) { rc = false; } bValidCompressedBuffer = ( m_bad_CRC_count > c0 ) ? false : rc; } if ( !bValidCompressedBuffer && 0 != out___buffer && sizeof___outbuffer > 0 ) { // Decompression will fail, but we might get something valid // at the start if the data flaw was near the end of the buffer. memset(out___buffer,0,sizeof___outbuffer); } if ( !rc ) { if ( in___buffer ) { onfree(in___buffer); in___buffer = 0; } return false; } int zrc = -1; // set up zlib in buffer unsigned char* my_next_in = (unsigned char*)in___buffer; size_t my_avail_in = sizeof__inbuffer; size_t d = my_avail_in; if ( d > max_avail ) d = max_avail; m_zlib.strm.next_in = my_next_in; m_zlib.strm.avail_in = (unsigned int)d; my_next_in += d; my_avail_in -= d; // set up zlib out buffer unsigned char* my_next_out = (unsigned char*)out___buffer; size_t my_avail_out = sizeof___outbuffer; d = my_avail_out; if ( d > max_avail ) d = max_avail; m_zlib.strm.next_out = my_next_out; m_zlib.strm.avail_out = (unsigned int)d; my_next_out += d; my_avail_out -= d; // counter guards against infinte loop if there are // bugs in zlib return codes int counter = 512; int flush = Z_NO_FLUSH; while ( rc && counter > 0 ) { // Call zlib's inflate function. It can either process // more input from m_zlib.strm.next_in[], create more // uncompressed output in m_zlib.strm.next_out[], or do both. if ( 0 == my_avail_in && 0 == m_zlib.strm.avail_in ) { // no compressed input is left - switch to finish mode flush = Z_FINISH; } zrc = z_inflate( &m_zlib.strm, flush ); if ( zrc < 0 ) { // Something went haywire - bail out. ON_ERROR("ON_BinaryArchive::ReadInflate - z_inflate failure"); rc = false; break; } if ( Z_FINISH == flush && Z_STREAM_END == zrc ) { // no input left, all pending decompression is finished, // and all decompressed output has been returned. break; } d = 0; if ( my_avail_in > 0 && m_zlib.strm.avail_in < max_avail ) { if ( 0 == m_zlib.strm.avail_in || 0 == m_zlib.strm.next_in ) { // The call to inflate() used up all the input // in m_zlib.strm.next_in[]. I can feed it another chunk // from inbuffer[] d = my_avail_in; if ( d > max_avail ) d = max_avail; m_zlib.strm.next_in = my_next_in; m_zlib.strm.avail_in = (unsigned int)d; } else { // The call to inflate() left some input in m_zlib.strm.next_in[], // but I can increase m_zlib.strm.avail_in. d = max_avail - m_zlib.strm.avail_in; if ( d > my_avail_in ) d = my_avail_in; m_zlib.strm.avail_in += (unsigned int)d; } my_next_in += d; my_avail_in -= d; } if ( my_avail_out > 0 && m_zlib.strm.avail_out < max_avail ) { // increase m_zlib.strm.next_out[] buffer if ( 0 == m_zlib.strm.avail_out || 0 == m_zlib.strm.next_out ) { d = my_avail_out; if ( d > max_avail ) d = max_avail; m_zlib.strm.next_out = my_next_out; m_zlib.strm.avail_out = (unsigned int)d; } else { d = max_avail - m_zlib.strm.avail_out; if ( d > my_avail_out ) d = my_avail_out; m_zlib.strm.avail_out += ((unsigned int)d); } my_next_out += d; my_avail_out -= d; } else if ( 0 == d ) { // no buffer changes counter--; } } if (in___buffer ) { onfree(in___buffer); in___buffer = 0; } if ( 0 == counter ) { rc = false; } return rc; }
bool ON_CompressedBuffer::InflateHelper( ON_CompressedBufferHelper* helper, size_t sizeof___outbuffer, // sizeof uncompressed data void* out___buffer // buffer for uncompressed data ) const { const size_t max_avail = 0x7FFFFFF0; // See max_avail comment in ON_CompressedBuffer::InflateHelper bool rc = true; int zrc = -1; // set up zlib in buffer unsigned char* my_next_in = (unsigned char*)m_buffer_compressed; size_t my_avail_in = m_sizeof_compressed; size_t d = my_avail_in; if ( d > max_avail ) d = max_avail; struct ON_CompressedBufferHelper& m_zlib = *helper; m_zlib.strm.next_in = my_next_in; m_zlib.strm.avail_in = (unsigned int)d; my_next_in += d; my_avail_in -= d; // set up zlib out buffer unsigned char* my_next_out = (unsigned char*)out___buffer; size_t my_avail_out = sizeof___outbuffer; d = my_avail_out; if ( d > max_avail ) d = max_avail; m_zlib.strm.next_out = my_next_out; m_zlib.strm.avail_out = (unsigned int)d; my_next_out += d; my_avail_out -= d; // counter guards against infinte loop if there are // bugs in zlib return codes int counter = 512; int flush = Z_NO_FLUSH; while ( rc && counter > 0 ) { // Call zlib's inflate function. It can either process // more input from m_zlib.strm.next_in[], create more // uncompressed output in m_zlib.strm.next_out[], or do both. if ( 0 == my_avail_in && 0 == m_zlib.strm.avail_in ) { // no compressed input is left - switch to finish mode flush = Z_FINISH; } zrc = z_inflate( &m_zlib.strm, flush ); if ( zrc < 0 ) { // Something went haywire - bail out. ON_ERROR("ON_CompressedBuffer::InflateHelper - z_inflate failure"); rc = false; break; } if ( Z_FINISH == flush && Z_STREAM_END == zrc ) { // no input left, all pending decompression is finished, // and all decompressed output has been returned. break; } d = 0; if ( my_avail_in > 0 && m_zlib.strm.avail_in < max_avail ) { if ( 0 == m_zlib.strm.avail_in || 0 == m_zlib.strm.next_in ) { // The call to inflate() used up all the input // in m_zlib.strm.next_in[]. I can feed it another chunk // from inbuffer[] d = my_avail_in; if ( d > max_avail ) d = max_avail; m_zlib.strm.next_in = my_next_in; m_zlib.strm.avail_in = (unsigned int)d; } else { // The call to inflate() left some input in m_zlib.strm.next_in[], // but I can increase m_zlib.strm.avail_in. d = max_avail - m_zlib.strm.avail_in; if ( d > my_avail_in ) d = my_avail_in; m_zlib.strm.avail_in += (unsigned int)d; } my_next_in += d; my_avail_in -= d; } if ( my_avail_out > 0 && m_zlib.strm.avail_out < max_avail ) { // increase m_zlib.strm.next_out[] buffer if ( 0 == m_zlib.strm.avail_out || 0 == m_zlib.strm.next_out ) { d = my_avail_out; if ( d > max_avail ) d = max_avail; m_zlib.strm.next_out = my_next_out; m_zlib.strm.avail_out = (unsigned int)d; } else { d = max_avail - m_zlib.strm.avail_out; if ( d > my_avail_out ) d = my_avail_out; m_zlib.strm.avail_out += ((unsigned int)d); } my_next_out += d; my_avail_out -= d; } else if ( 0 == d ) { // no buffer changes counter--; } } if ( 0 == counter ) { rc = false; } return rc; }