/* * libretroshare/src/utils: rscompress.cc * * Basic memory chunk compression, based on openpgp-sdk * * Copyright 2013 by Cyril Soler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License Version 2 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. * * Please report all bugs and problems to "csoler@users.sourceforge.net". * */ #include #include #include #include #include #include "rscompress.h" #include "zlib.h" #include "util/rsmemory.h" // 16K buffer size. // static const unsigned int CHUNK = 16384u ; bool RsCompress::compress_memory_chunk(const uint8_t *input_mem,const uint32_t input_size,uint8_t *& output_mem,uint32_t& output_size) { uint32_t remaining_input = input_size ; uint32_t output_offset = 0 ; uint32_t input_offset = 0 ; output_size = 1024 ; output_mem = (uint8_t*)rs_safe_malloc(output_size) ; if(!output_mem) return false ; int ret, flush; unsigned have; int level = 9 ; z_stream strm; unsigned char in[CHUNK]; unsigned char out[CHUNK]; /* allocate deflate state */ strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; ret = deflateInit(&strm, level); if (ret != Z_OK) return false; /* compress until end of file */ do { uint32_t available_in = std::min(CHUNK,remaining_input) ; memcpy(in,input_mem+input_offset,available_in) ; strm.avail_in = available_in ; remaining_input -= available_in ; input_offset += available_in ; flush = /*feof(source)*/ remaining_input ? Z_NO_FLUSH: Z_FINISH ; strm.next_in = in; /* run deflate() on input until output buffer not full, finish compression if all of source has been read in */ do { strm.avail_out = CHUNK; strm.next_out = out; ret = deflate(&strm, flush); /* no bad return value */ assert(ret != Z_STREAM_ERROR); /* state not clobbered */ have = CHUNK - strm.avail_out; if(output_size < have+output_offset) { //std::cerr << "Growing outputbuffer from " << output_size << " to " << have+output_offset << std::endl; output_mem = (uint8_t*)realloc(output_mem,have+output_offset) ; output_size = have+output_offset ; } memcpy(output_mem+output_offset,out,have) ; output_offset += have ; //std::cerr << "Copying " << have << " bytes to output. New offset=" << output_offset << std::endl; } while (strm.avail_out == 0); assert(strm.avail_in == 0); /* all input will be used */ /* done when last data in file processed */ } while (flush != Z_FINISH); assert(ret == Z_STREAM_END); /* stream will be complete */ /* clean up and return */ (void)deflateEnd(&strm); output_size = output_offset ; return true ; } bool RsCompress::uncompress_memory_chunk(const uint8_t *input_mem,const uint32_t input_size,uint8_t *& output_mem,uint32_t& output_size) { uint32_t remaining_input = input_size ; output_size = input_size ; uint32_t output_offset = 0 ; uint32_t input_offset = 0 ; output_mem = (uint8_t*)rs_safe_malloc(output_size) ; if(!output_mem) return false ; int ret; unsigned have; z_stream strm; unsigned char in[CHUNK]; unsigned char out[CHUNK]; /* allocate inflate state */ memset(&strm,0,sizeof(strm)) ; strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; strm.next_in = Z_NULL; strm.next_out = Z_NULL; ret = inflateInit(&strm); if (ret != Z_OK) return ret; /* decompress until deflate stream ends or end of file */ do { uint32_t available_in = std::min(CHUNK,remaining_input) ; memcpy(in,input_mem+input_offset,available_in) ; strm.avail_in = available_in ; remaining_input -= available_in ; input_offset += available_in ; if (strm.avail_in == 0) break; strm.next_in = in; /* run inflate() on input until output buffer not full */ do { strm.avail_out = CHUNK; strm.next_out = out; ret = inflate(&strm, Z_NO_FLUSH); assert(ret != Z_STREAM_ERROR); /* state not clobbered */ switch (ret) { case Z_NEED_DICT: ret = Z_DATA_ERROR; /* and fall through */ case Z_DATA_ERROR: case Z_MEM_ERROR: (void)inflateEnd(&strm); return ret; } have = CHUNK - strm.avail_out; if(output_size < have+output_offset) { output_mem = (uint8_t*)realloc(output_mem,have+output_offset) ; output_size = have+output_offset ; } memcpy(output_mem+output_offset,out,have) ; output_offset += have ; } while (strm.avail_out == 0); /* done when inflate() says it's done */ } while (ret != Z_STREAM_END); /* clean up and return */ (void)inflateEnd(&strm); output_size = output_offset ; return ret == Z_STREAM_END ; }