[C/C++] GZ und BZ2 Kompression (Stream) (updated - 09.04)

Dieses Thema im Forum "Projekte / Codes" wurde erstellt von terraNova, 7. April 2011 .

  1. 7. April 2011
    GZ und BZ2 Kompression (Stream) (updated - 09.04)

    Heyho

    Ich hab für ein Projekt letztens einen GZ-Stream (Mittels zLib ) gebastelt und vielleicht interessiert den ein oder anderen den Code ja.

    comp_streams.h:
    Spoiler
    Code:
    #ifndef COMP_STREAMS_H_
    #define COMP_STREAMS_H_
    
    #include <zlib.h>
    #include <vector>
    
    namespace dman {
    namespace comp {
     typedef std::vector<unsigned char> ByteArray;
    
     enum eStreamStates {
     eSSNone = 0,
     
     /* (DE-)Compress 
     - Params for stream_state::method() 
     */
     eSSComp,
     eSSDecomp,
    
     /* Clear Buffer 
     - Param for stream_state::clear() 
     */
     eSSClear,
    
     /* Level 
     - Params for stream_state::level() 
     */
     // ZLIB
     eSSGZSpeed = Z_BEST_SPEED,
     eSSGZNComp = Z_NO_COMPRESSION,
     eSSGZBComp = Z_BEST_COMPRESSION,
     eSSGZDComp = Z_DEFAULT_COMPRESSION,
     
     // BZLIB
     eSSBZCWorst = 1, // From
     eSSBZCBest = 9, // To
     };
    
     class stream_state {
     protected:
     int _method;
     int _clear; 
     int _level;
    
     public: 
     stream_state( void );
     ~stream_state( void );
    
     int get_method( void );
     int get_clear( void );
     int get_level( void );
     
     static
     stream_state& method( int method );
    
     static
     stream_state& level( int level = Z_BEST_SPEED );
    
     static
     stream_state& clear( void );
    
     void apply( stream_state& rhs );
     } /* class stream_mode */; 
    
     class gzstream {
     private:
     ByteArray buf;
     stream_state state;
    
     public:
     gzstream( void );
     explicit gzstream( char* buf, size_t count );
     ~gzstream( void );
     
     void clear( void );
     size_t read( char *buf, size_t count );
    
     ByteArray& get( void );
    
     protected: 
     unsigned
     char* compress( const unsigned char *in, size_t *len );
    
     unsigned
     char* decompress( const unsigned char *in, size_t *len );
    
     void process( void );
    
     void check_states( void );
    
     public:
     gzstream& operator <<( const unsigned char rhs );
     gzstream& operator <<( const unsigned char* rhs );
     gzstream& operator <<( ByteArray rhs );
     gzstream& operator <<( stream_state& rhs );
    
     gzstream& operator >>( ByteArray& rhs );
     } /* class gz */;
    
     class bz2stream {
     private:
     ByteArray buf;
     stream_state state;
    
     public:
     bz2stream( void );
     explicit bz2stream( char* buf, size_t count );
     ~bz2stream( void );
     
     void clear( void );
     size_t read( char *buf, size_t count );
    
     ByteArray& get( void );
    
     protected: 
     unsigned
     char* compress( const unsigned char *in, size_t *len );
    
     unsigned
     char* decompress( const unsigned char *in, size_t *len );
    
     void process( void );
    
     void check_states( void );
    
     public:
     bz2stream& operator <<( const unsigned char rhs );
     bz2stream& operator <<( const unsigned char* rhs );
     bz2stream& operator <<( ByteArray rhs );
     bz2stream& operator <<( stream_state& rhs );
    
     bz2stream& operator >>( ByteArray& rhs );
     } /* class bz */;
    } /* ns comp */;
    } /* ns dman */;
    
    #endif /* COMP_STREAMS_H_ */

    comp_streams.cpp:
    Spoiler
    Code:
    #include "comp_streams.h"
    
    namespace dman {
    namespace comp {
    # define SSApply(x) if(mode.x != eSSNone) x = mode.x;
    # define SSGet(x, m) static int sx; sx = x; x = m; return sx;
    
     const size_t c_g_tokLen = 4096;
    
     /* ==================================================================
     STREAM_MODE
     ================================================================== */
     stream_state::stream_state( void ) {
     _method = eSSNone;
     _clear = eSSNone;
     _level = eSSGZNComp;
     }
    
     stream_state::~stream_state( void ) {
    
     }
    
     int stream_state::get_level( void ) {
     SSGet(_level, _level);
     }
    
     int stream_state::get_method( void ) {
     SSGet(_method, _method);
     }
    
     int stream_state::get_clear( void ) {
     SSGet(_clear, eSSNone);
     }
    
     stream_state& stream_state::level( int level ) {
     static stream_state mode;
     memset(&mode, 0, sizeof(stream_state));
    
     switch(level) {
     case eSSGZSpeed:
     case eSSGZDComp:
     case eSSGZBComp:
     case eSSGZNComp:
     break;
    
     default: {
     mode._level = eSSGZNComp;
     return mode;
     }
     }
    
     mode._level = level;
     return mode;
     }
    
     stream_state& stream_state::method( int method ) {
     static stream_state mode;
     memset(&mode, 0, sizeof(stream_state));
    
     mode._method = method;
     return mode;
     }
    
     stream_state& stream_state::clear( void ) {
     static stream_state mode;
     memset(&mode, 0, sizeof(stream_state));
    
     mode._clear = eSSClear;
     return mode;
     }
    
     void stream_state::apply( stream_state& mode ) {
     SSApply(_method);
     SSApply(_clear);
     SSApply(_level);
     }
    
     /* ==================================================================
     GZSTREAM
     ================================================================== */
     gzstream::gzstream( void ) {
    
     }
    
     gzstream::~gzstream( void ) {
     buf.clear();
     }
    
     gzstream::gzstream( char *buf, size_t count ) {
     read(buf, count);
     }
    
     void gzstream::clear( void ) {
     buf.clear();
     }
     
     size_t gzstream::read( char *buf, size_t count ) {
     if(buf == nullptr || count <= 0)
     return 0;
     
     this->buf.insert(this->buf.end(), buf, buf+count);
     return 0;
     }
    
     ByteArray& gzstream::get( void ) {
     process();
    
     return buf;
     }
     
     unsigned char* gzstream::compress( const unsigned char *in, size_t *len ) {
     static ByteArray out;
     unsigned char buf[c_g_tokLen] = {0};
     z_stream iStrm = {0};
     size_t done = 0;
    
     out.clear();
     memset(&iStrm, Z_NULL, sizeof(z_stream));
     
     int ret = deflateInit(&iStrm, state.get_level());
    
     if(ret != Z_OK)
     return 0;
    
     iStrm.avail_in = (*len);
     iStrm.next_in = (Bytef*)in;
     
     while(ret != Z_STREAM_END) {
     memset(buf, 0, c_g_tokLen);
     iStrm.avail_out = c_g_tokLen;
     iStrm.next_out = (Bytef*)buf;
     ret = deflate(&iStrm, Z_FINISH);
     out.insert(out.end(), buf, buf+c_g_tokLen);
     }
     
     (*len) = iStrm.total_out;
     ret = deflateEnd(&iStrm);
    
     return &out[0];
     }
    
     unsigned char* gzstream::decompress( const unsigned char *in, size_t *len ) {
     static ByteArray out;
     unsigned char buf[c_g_tokLen] = {0};
     z_stream iStrm = {0};
    
     memset(buf, 0, c_g_tokLen);
     memset(&iStrm, Z_NULL, sizeof(z_stream));
     
     int ret = inflateInit(&iStrm, state.get_level());
    
     if(ret != Z_OK)
     return 0;
    
     iStrm.avail_in = *len;
     iStrm.next_in = (Bytef*)in;
    
     while(ret != Z_STREAM_END) {
     memset(buf, 0, c_g_tokLen);
     iStrm.avail_out = c_g_tokLen;
     iStrm.next_out = (Bytef*)buf;
     ret = inflate(&iStrm, Z_FINISH);
     out.insert(out.end(), buf, buf+c_g_tokLen);
     }
     
     (*len) = iStrm.total_out;
     inflateEnd(&iStrm);
    
     return &out[0];
     }
    
     void gzstream::process( void ) {
     if(buf.empty() == true)
     return;
    
     switch(state.get_method()) {
     case eSSComp: {
     size_t len = buf.size();
     unsigned char *comp = compress(&buf[0], &len);
    
     buf.clear();
     buf.assign(comp, comp+len);
     } break;
    
     case eSSDecomp: {
     size_t len = buf.size();
     unsigned char *decomp = decompress(&buf[0], &len);
    
     buf.clear();
     buf.assign(decomp, decomp+len);
     } break;
     }
     }
    
     void gzstream::check_states( void ) {
     if(state.get_clear()) {
     clear();
     }
     }
    
     gzstream& gzstream::operator <<( const unsigned char rhs ) {
     check_states();
     buf.insert(buf.end(), rhs);
    
     return (*this);
     }
    
     gzstream& gzstream::operator <<( const unsigned char* rhs ) {
     check_states();
     buf.insert(buf.end(), rhs, rhs+strlen((const char*)rhs));
    
     return (*this);
     }
    
     gzstream& gzstream::operator <<( ByteArray rhs ) {
     check_states();
     buf.insert(buf.end(), rhs.begin(), rhs.end());
    
     return (*this);
     }
    
     gzstream& gzstream::operator <<( stream_state& rhs ) {
     state.apply(rhs);
     return (*this);
     }
    
     gzstream& gzstream::operator >>( ByteArray& rhs ) {
     check_states();
     process();
    
     rhs.assign(buf.begin(), buf.end());
     return (*this);
     }
    
     /* ==================================================================
     BZ2STREAM
     ================================================================== */
     bz2stream::bz2stream( void ) {
    
     }
    
     bz2stream::~bz2stream( void ) {
     buf.clear();
     }
    
     bz2stream::bz2stream( char *buf, size_t count ) {
     read(buf, count);
     }
    
     void bz2stream::clear( void ) {
     buf.clear();
     }
     
     size_t bz2stream::read( char *buf, size_t count ) {
     if(buf == nullptr || count <= 0)
     return 0;
     
     this->buf.insert(this->buf.end(), buf, buf+count);
     }
    
     ByteArray& bz2stream::get( void ) {
     process();
    
     return buf;
     }
     
     unsigned char* bz2stream::compress( const unsigned char *in, size_t *len ) {
     static ByteArray out;
     unsigned char buf[c_g_tokLen] = {0};
     bz_stream iStrm = {0};
     size_t done = 0;
     bool ran = false;
    
     out.clear();
     memset(&iStrm, 0, sizeof(bz_stream));
     
     int ret = BZ2_bzCompressInit(&iStrm, state.get_level(), 0, 30);
    
     if(ret != BZ_OK)
     return 0;
    
     iStrm.avail_in = (*len);
     iStrm.next_in = (char*)in;
     
     while(ret != BZ_STREAM_END) {
     memset(buf, 0, c_g_tokLen);
     iStrm.avail_out = c_g_tokLen;
     iStrm.next_out = (char*)buf;
    
     ret = BZ2_bzCompress(&iStrm, (ran?BZ_FINISH:BZ_RUN));
    
     if(ret == BZ_RUN_OK && !ran) {
     ran = true;
     }
    
     if(ret < 0) {
     out.clear();
     return 0;
     }
    
     if(*buf != 0)
     out.insert(out.end(), buf, buf+c_g_tokLen);
     }
     
     (*len) = (iStrm.total_out_hi32 << 32)+iStrm.total_out_lo32;
     ret = BZ2_bzCompressEnd(&iStrm);
    
     return &out[0];
     }
    
     unsigned char* bz2stream::decompress( const unsigned char *in, size_t *len ) {
     static ByteArray out;
     unsigned char buf[c_g_tokLen] = {0};
     bz_stream iStrm = {0};
    
     memset(buf, 0, c_g_tokLen);
     memset(&iStrm, Z_NULL, sizeof(bz_stream));
     
     int ret = BZ2_bzDecompressInit(&iStrm, 0, 0);
    
     if(ret != BZ_OK)
     return 0;
    
     iStrm.avail_in = *len;
     iStrm.next_in = (char*)in;
    
     while(ret != BZ_STREAM_END) {
     memset(buf, 0, c_g_tokLen);
     iStrm.avail_out = c_g_tokLen;
     iStrm.next_out = (char*)buf;
     
     ret = BZ2_bzDecompress(&iStrm);
    
     if(ret < 0) {
     out.clear();
     return 0;
     }
    
     out.insert(out.end(), buf, buf+c_g_tokLen);
     }
     
     (*len) = (iStrm.total_out_hi32 << 32)+iStrm.total_out_lo32;
     BZ2_bzDecompressEnd(&iStrm);
    
     return &out[0];
     }
    
     void bz2stream::process( void ) {
     if(buf.empty() == true)
     return;
    
     switch(state.get_method()) {
     case eSSComp: {
     size_t len = buf.size();
     unsigned char *comp = compress(&buf[0], &len);
    
     buf.clear();
     buf.assign(comp, comp+len);
     } break;
    
     case eSSDecomp: {
     size_t len = buf.size();
     unsigned char *decomp = decompress(&buf[0], &len);
    
     buf.clear();
     buf.assign(decomp, decomp+len);
     } break;
     }
     }
    
     void bz2stream::check_states( void ) {
     if(state.get_clear()) {
     clear();
     }
     }
    
     bz2stream& bz2stream::operator <<( const unsigned char rhs ) {
     check_states();
     buf.insert(buf.end(), rhs);
    
     return (*this);
     }
    
     bz2stream& bz2stream::operator <<( const unsigned char* rhs ) {
     check_states();
     buf.insert(buf.end(), rhs, rhs+strlen((const char*)rhs));
    
     return (*this);
     }
    
     bz2stream& bz2stream::operator <<( ByteArray rhs ) {
     check_states();
     buf.insert(buf.end(), rhs.begin(), rhs.end());
    
     return (*this);
     }
    
     bz2stream& bz2stream::operator <<( stream_state& rhs ) {
     state.apply(rhs);
     return (*this);
     }
    
     bz2stream& bz2stream::operator >>( ByteArray& rhs ) {
     check_states();
     process();
    
     rhs.assign(buf.begin(), buf.end());
     return (*this);
     }
    } /* ns comp */;
    } /* ns dman */;

    Beispielanwendung zur De-/Kompression von Dateien:

    main.cpp:
    Spoiler
    Code:
    #include <iostream>
    #include <fstream>
    using namespace std;
    
    #include "comp_streams.h"
    using namespace dman::comp;
    
    void compress( const char *src, const char* dest ) {
     unsigned char c;
     ByteArray comp;
     
     fstream in(src, ios::binary|ios::in),
     out(dest, ios::binary|ios::out);
    
     if(!in.is_open() || !out.is_open())
     return;
     
     gzstream gz;
     gz << stream_state::method(eSSComp) << stream_state::level(eSSGZBComp);
    
     while(!in.eof() && in.good()) {
     in.get((char&)c);
    
     if(in.eof())
     break;
    
     gz << c;
     }
    
     gz >> comp;
     out.write((char*)&comp[0], comp.size());
    
     in.close(); out.close();
    }
    
    void decompress( const char *src, const char* dest ) {
     unsigned char c;
     ByteArray comp;
     
     fstream in(src, ios::binary|ios::in),
     out(dest, ios::binary|ios::out);
    
     if(!in.is_open() || !out.is_open())
     return;
     
     gzstream gz;
     gz << stream_state::method(eSSDecomp);
     
     while(!in.eof() && in.good()) {
     in.get((char&)c);
    
     if(in.eof())
     break;
    
     gz << c;
     }
    
     gz >> comp;
     out.write((char*)&comp[0], comp.size());
    
     in.close(); out.close();
    }
    
    int main( int argc, char **argv ) {
     if(argc != 4) {
     cout << "prog <-c | -d> <src> <dest>" << endl;
     return 0;
     }
    
     switch(*(argv[1]+1)) {
     case 'c': {
     cout << "Komprimiere '" << argv[2] << "' zu '" << argv[3] << "'. ";
     compress(argv[2], argv[3]);
     } break;
    
     case 'd': {
     cout << "Dekomprimiere '" << argv[2] << "' zu '" << argv[3] << "'. ";
     decompress(argv[2], argv[3]);
     } break;
     }
    
     return 0;
    }
    

    Um dem gzstream mitzuteilen, was er gerade zu tun hat (De-/Komprimieren, Buffer leeren, Kompressionslevel) hab ich die stream_state Klasse erstellt, die das ganze dann bequem per Stream regelt.

    Die Klassen sind nicht optimiert, daher bitte ich hier auf die Funktionsweise einzugehen, sollte Diskussionsbedarf bestehen.

    Benötigt wird die Bibliothek zlib die ich oben verlinkt habe (Ebenfalls im Ref.-Thread (Siehe Sig)).

    Grüße.


    // EDIT:

    BZ2 Stream noch hinzugefügt. Benötigt wird die BZip2 Lib.
    Um den Stream im Beispiel anzuwenden, einfach anstelle von "gz" "bz2" einsetzen.
     
  2. 9. April 2011
    AW: GZ und BZ2 Kompression (Stream) (updated - 09.04)

    nice!

    Hab vor ca. 2-3 Wochen angefangen mich mal mit der zlib zu beschäftigen,
    deshalb nice timing

    Bin leider grad nicht zu hause, werd' mir das aber auf jeden Fall mal
    genauer anschauen
     
  3. Video Script

    Videos zum Themenbereich

    * gefundene Videos auf YouTube, anhand der Überschrift.