mirror of
https://github.com/mcneel/opennurbs.git
synced 2026-03-01 03:26:09 +08:00
719 lines
19 KiB
C++
719 lines
19 KiB
C++
//
|
|
// Copyright (c) 1993-2022 Robert McNeel & Associates. All rights reserved.
|
|
// OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
|
|
// McNeel & Associates.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
|
|
// ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
|
|
// MERCHANTABILITY ARE HEREBY DISCLAIMED.
|
|
//
|
|
// For complete openNURBS copyright information see <http://www.opennurbs.org>.
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
#include "opennurbs.h"
|
|
|
|
#if !defined(ON_COMPILING_OPENNURBS)
|
|
// This check is included in all opennurbs source .c and .cpp files to insure
|
|
// ON_COMPILING_OPENNURBS is defined when opennurbs source is compiled.
|
|
// When opennurbs source is being compiled, ON_COMPILING_OPENNURBS is defined
|
|
// and the opennurbs .h files alter what is declared and how it is declared.
|
|
#error ON_COMPILING_OPENNURBS must be defined when compiling opennurbs
|
|
#endif
|
|
|
|
#include "opennurbs_zlib.h"
|
|
|
|
struct ON_ZlibImplementation
|
|
{
|
|
z_stream m_strm;
|
|
unsigned char m_zlib_out_buffer[16384];
|
|
};
|
|
|
|
ON_CompressStream::ON_CompressStream()
|
|
: m_out_callback_function(0)
|
|
, m_out_callback_context(0)
|
|
, m_in_size(0)
|
|
, m_out_size(0)
|
|
, m_in_crc(0)
|
|
, m_out_crc(0)
|
|
, m_implementation(0)
|
|
, m_reserved(0)
|
|
{}
|
|
|
|
|
|
ON_CompressStream::~ON_CompressStream()
|
|
{
|
|
|
|
if ( 0 != m_implementation )
|
|
{
|
|
onfree(m_implementation);
|
|
m_implementation = 0;
|
|
}
|
|
}
|
|
|
|
void ON_CompressStream::ErrorHandler()
|
|
{
|
|
// place holder for error handing
|
|
ON_ERROR("ON_CompressStream error");
|
|
}
|
|
|
|
bool ON_CompressStream::Begin()
|
|
{
|
|
if ( 0 != m_implementation )
|
|
{
|
|
onfree(m_implementation);
|
|
m_implementation = 0;
|
|
}
|
|
|
|
// zero these because the same instance of an
|
|
// ON_CompressStream class may be used multiple times.
|
|
m_in_size = 0;
|
|
m_out_size = 0;
|
|
m_in_crc = 0;
|
|
m_out_crc = 0;
|
|
|
|
struct ON_ZlibImplementation* imp = (struct ON_ZlibImplementation*)onmalloc(sizeof(*imp));
|
|
memset(&imp->m_strm,0,sizeof(imp->m_strm));
|
|
|
|
if ( Z_OK != deflateInit( &imp->m_strm, Z_BEST_COMPRESSION ) )
|
|
{
|
|
onfree(imp);
|
|
return false;
|
|
}
|
|
|
|
m_implementation = imp;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool ON_CompressStream::In( ON__UINT64 size, const void* uncompressed_buffer )
|
|
{
|
|
if ( size <= 0 )
|
|
return true;
|
|
|
|
if ( 0 == m_implementation )
|
|
{
|
|
ErrorHandler();
|
|
return false;
|
|
}
|
|
|
|
if ( 0 == uncompressed_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_CompressStream 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 deflate_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 deflate function. It can either process
|
|
// more input from m_zlib.strm.next_in[], create more
|
|
// compressed output in m_zlib.strm.next_out[], or do both.
|
|
|
|
// provide storage for compressed 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 uncompressed input
|
|
break;
|
|
}
|
|
// submit a portion of uncompressed_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,uncompressed_buffer); // (size_t) cast is safe because sz <= max_sz = 0x7FFFFFF0
|
|
strm.next_in = (z_Bytef*)uncompressed_buffer;
|
|
strm.avail_in = (ON__UINT32)sz;
|
|
uncompressed_buffer = ((const unsigned char*)uncompressed_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_deflate( &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;
|
|
}
|
|
|
|
deflate_output_count = sizeof_out_buffer - strm.avail_out;
|
|
if ( deflate_output_count > 0 )
|
|
{
|
|
// The last call to deflate created compressed output.
|
|
// Send the output to compressed 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, deflate_output_count, out_buffer);
|
|
ON__UINT64 out_size1 = m_out_size + deflate_output_count;
|
|
|
|
rc = (0 != m_out_callback_function)
|
|
? m_out_callback_function( m_out_callback_context, deflate_output_count, out_buffer )
|
|
: Out( m_out_callback_context, deflate_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_CompressStream::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_CompressStream 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 deflate_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_deflate( &strm, Z_FINISH );
|
|
if ( zrc < 0 )
|
|
{
|
|
// Something went haywire - bail out.
|
|
ErrorHandler();
|
|
rc = false;
|
|
break;
|
|
}
|
|
|
|
deflate_output_count = sizeof_out_buffer - strm.avail_out;
|
|
if ( deflate_output_count > 0 )
|
|
{
|
|
// The last call to deflate created compressed output.
|
|
// Send the output to compressed 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 compressed_crc1 = ON_CRC32( m_out_crc, deflate_output_count, out_buffer);
|
|
ON__UINT64 compressed_size1 = m_out_size + ((ON__UINT64)deflate_output_count);
|
|
|
|
rc = (0 != m_out_callback_function)
|
|
? m_out_callback_function( m_out_callback_context, deflate_output_count, out_buffer )
|
|
: Out( m_out_callback_context, deflate_output_count, out_buffer );
|
|
if ( !rc )
|
|
break;
|
|
|
|
// Update compressed stream crc and size
|
|
m_out_crc = compressed_crc1;
|
|
m_out_size = compressed_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;
|
|
|
|
deflateEnd(&strm);
|
|
|
|
onfree(m_implementation);
|
|
m_implementation = 0;
|
|
|
|
return rc;
|
|
}
|
|
|
|
bool ON_CompressStream::Out( void*, ON__UINT32, const void* )
|
|
{
|
|
// default compressed stream handler does nothing.
|
|
return true;
|
|
}
|
|
|
|
bool ON_CompressStream::SetCallback(
|
|
ON_StreamCallbackFunction out_callback_function,
|
|
void* out_callback_context
|
|
)
|
|
{
|
|
m_out_callback_function = out_callback_function;
|
|
m_out_callback_context = out_callback_context;
|
|
return true;
|
|
}
|
|
|
|
ON_StreamCallbackFunction ON_CompressStream::CallbackFunction() const
|
|
{
|
|
return m_out_callback_function;
|
|
}
|
|
|
|
void* ON_CompressStream::CallbackContext() const
|
|
{
|
|
return m_out_callback_context;
|
|
}
|
|
|
|
|
|
ON__UINT64 ON_CompressStream::InSize() const
|
|
{
|
|
return m_in_size;
|
|
}
|
|
|
|
ON__UINT64 ON_CompressStream::OutSize() const
|
|
{
|
|
return m_out_size;
|
|
}
|
|
|
|
ON__UINT32 ON_CompressStream::InCRC() const
|
|
{
|
|
return m_in_crc;
|
|
}
|
|
|
|
ON__UINT32 ON_CompressStream::OutCRC() const
|
|
{
|
|
return m_out_crc;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
ON_UncompressStream::ON_UncompressStream()
|
|
: m_out_callback_function(0)
|
|
, m_out_callback_context(0)
|
|
, m_in_size(0)
|
|
, m_out_size(0)
|
|
, m_in_crc(0)
|
|
, m_out_crc(0)
|
|
, m_implementation(0)
|
|
, m_reserved(0)
|
|
{}
|
|
|
|
|
|
ON_UncompressStream::~ON_UncompressStream()
|
|
{
|
|
|
|
if ( 0 != m_implementation )
|
|
{
|
|
onfree(m_implementation);
|
|
m_implementation = 0;
|
|
}
|
|
}
|
|
|
|
void ON_UncompressStream::ErrorHandler()
|
|
{
|
|
// place holder for error handing
|
|
ON_ERROR("ON_UncompressStream error");
|
|
}
|
|
|
|
bool ON_UncompressStream::Begin()
|
|
{
|
|
if ( 0 != m_implementation )
|
|
{
|
|
onfree(m_implementation);
|
|
m_implementation = 0;
|
|
}
|
|
|
|
// zero these because the same instance of an
|
|
// ON_UncompressStream class may be used multiple times.
|
|
m_in_size = 0;
|
|
m_out_size = 0;
|
|
m_in_crc = 0;
|
|
m_out_crc = 0;
|
|
|
|
struct ON_ZlibImplementation* imp = (struct ON_ZlibImplementation*)onmalloc(sizeof(*imp));
|
|
memset(&imp->m_strm,0,sizeof(imp->m_strm));
|
|
|
|
if ( Z_OK != inflateInit( &imp->m_strm ) )
|
|
{
|
|
onfree(imp);
|
|
return false;
|
|
}
|
|
|
|
m_implementation = imp;
|
|
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
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_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::Out( void*, ON__UINT32, const void* )
|
|
{
|
|
// default uncompressed stream handler does nothing.
|
|
return true;
|
|
}
|
|
|
|
bool ON_UncompressStream::SetCallback(
|
|
ON_StreamCallbackFunction out_callback_function,
|
|
void* out_callback_context
|
|
)
|
|
{
|
|
m_out_callback_function = out_callback_function;
|
|
m_out_callback_context = out_callback_context;
|
|
return true;
|
|
}
|
|
|
|
ON_StreamCallbackFunction ON_UncompressStream::CallbackFunction() const
|
|
{
|
|
return m_out_callback_function;
|
|
}
|
|
|
|
void* ON_UncompressStream::CallbackContext() const
|
|
{
|
|
return m_out_callback_context;
|
|
}
|
|
|
|
ON__UINT64 ON_UncompressStream::InSize() const
|
|
{
|
|
return m_in_size;
|
|
}
|
|
|
|
ON__UINT64 ON_UncompressStream::OutSize() const
|
|
{
|
|
return m_out_size;
|
|
}
|
|
|
|
ON__UINT32 ON_UncompressStream::InCRC() const
|
|
{
|
|
return m_in_crc;
|
|
}
|
|
|
|
ON__UINT32 ON_UncompressStream::OutCRC() const
|
|
{
|
|
return m_out_crc;
|
|
}
|
|
|
|
|
|
class ON_UncompressBuffer_Context
|
|
{
|
|
public:
|
|
ON_UncompressBuffer_Context(
|
|
size_t sizeof_uncompressed_buffer,
|
|
const void* uncompressed_buffer
|
|
)
|
|
: m_dst((sizeof_uncompressed_buffer > 0) ? ((unsigned char*)uncompressed_buffer) : nullptr)
|
|
, m_dst_end((nullptr != m_dst) ? (m_dst + sizeof_uncompressed_buffer) : nullptr)
|
|
{}
|
|
|
|
unsigned char* m_dst = nullptr;
|
|
unsigned char* m_dst_end = nullptr;
|
|
static bool Callback(void* context, ON__UINT32 size, const void* buffer)
|
|
{
|
|
ON_UncompressBuffer_Context* p = (ON_UncompressBuffer_Context*)context;
|
|
unsigned char* dst = p->m_dst;
|
|
unsigned char* dst_end = p->m_dst_end;
|
|
const unsigned char* src = (size > 0) ? ((const unsigned char*)buffer) : nullptr;
|
|
const unsigned char* src_end = (nullptr != src) ? (src + size) : nullptr;
|
|
while (dst < dst_end && src < src_end)
|
|
{
|
|
*dst++ = *src++;
|
|
}
|
|
p->m_dst = dst;
|
|
return (src == src_end);
|
|
}
|
|
private:
|
|
ON_UncompressBuffer_Context() = delete;
|
|
ON_UncompressBuffer_Context(const ON_UncompressBuffer_Context&) = delete;
|
|
ON_UncompressBuffer_Context& operator=(const ON_UncompressBuffer_Context&) = delete;
|
|
};
|
|
|
|
size_t ON_UncompressBuffer(
|
|
size_t sizeof_compressed_buffer,
|
|
const void* compressed_buffer,
|
|
size_t sizeof_uncompressed_buffer,
|
|
void* uncompressed_buffer
|
|
)
|
|
{
|
|
unsigned char* dst((sizeof_uncompressed_buffer > 0) ? ((unsigned char*)uncompressed_buffer) : nullptr);
|
|
ON_UncompressBuffer_Context context(sizeof_uncompressed_buffer, dst);
|
|
ON_UncompressStream unzipper;
|
|
bool rc = unzipper.SetCallback(ON_UncompressBuffer_Context::Callback, &context);
|
|
if (rc)
|
|
{
|
|
rc = unzipper.Begin();
|
|
if (rc)
|
|
{
|
|
rc = unzipper.In(sizeof_compressed_buffer, compressed_buffer);
|
|
if (!unzipper.End())
|
|
rc = false;
|
|
}
|
|
}
|
|
return rc ? (context.m_dst - dst) : 0;
|
|
}
|