zlib 简单封装

下列代码用于压缩和解压字符串,使用标准库string。实现了对zlib的简单封装。


#pragma once

#include <boost/noncopyable.hpp>
#include <zlib.h>
#include <string>
#include <cassert>
#include <strings.h> // for bzero

class ZlibDecompressor : boost::noncopyable {
 public:
  ZlibDecompressor(const std::string &input)
      : zerror_(Z_OK),
        z_init_error_(Z_OK),
        input_(input),
        output_()
  {
    ::bzero(&zstream_, sizeof(zstream_));
    z_init_error_ = inflateInit(&zstream_);
    if (z_init_error_ == Z_OK)
      zerror_ = decompress();
  }

  const char *zlibErrorMessage() const { return zstream_.msg; }

  int zlibErrorCode() const { return zerror_; }

  ~ZlibDecompressor()
  {
    if (z_init_error_ == Z_OK)
      inflateEnd(&zstream_);
  }

  std::string output() const
  {
    if(valid())
      return output_;
    return output_;
  }
  
  bool valid() const { return zerror_ == Z_OK; }

 private:

  const static int CHUNK = 8192;

  int decompress() {
    int ret;
    size_t begin = 0;
    size_t size = input_.size();
    unsigned char out[CHUNK];
    do {
      int chunk = ((size - begin) < CHUNK ? size - begin : CHUNK);
      if (chunk == 0)
        break;
      zstream_.avail_in = static_cast<uint>(chunk);
      zstream_.next_in = (Bytef *) &input_[begin];
      do
      {
        zstream_.avail_out = CHUNK;
        zstream_.next_out = (Bytef*)out;
        ret = inflate(&zstream_, Z_NO_FLUSH);
        assert(ret != Z_STREAM_ERROR);
        switch (ret)
        {
          case Z_NEED_DICT:
            ret = Z_DATA_ERROR;
          case Z_DATA_ERROR:
          case Z_MEM_ERROR:
            return ret;
        }
        int have = CHUNK - static_cast<int>(zstream_.avail_out);
        output_.append(out, out + have);
      } while (zstream_.avail_out == 0);
      begin += chunk;
    } while (ret != Z_STREAM_END);
    return ret;
  }

  z_stream zstream_;
  int zerror_;
  int z_init_error_;
  std::string input_;
  std::string output_;
};

class ZlibCompressor : boost::noncopyable {
 public:
  explicit ZlibCompressor(const std::string &input)
      : zerror_(Z_OK),
        z_init_error_(Z_OK),
        input_(input),
        output_()
  {
    ::bzero(&zstream_, sizeof(zstream_));
    z_init_error_ = deflateInit(&zstream_, -1);
    if(z_init_error_ == Z_OK)
      zerror_ = compress();
  }

  explicit ZlibCompressor(const std::string& input, int level)
  : zerror_(Z_OK),
    z_init_error_(Z_OK),
    input_(input),
    output_()
  {
    assert(level >= -1 && level <= 9);
    ::bzero(&zstream_, sizeof(zstream_));
    z_init_error_ = deflateInit(&zstream_, level);
    if(z_init_error_ == Z_OK)
      zerror_ = compress();
  }

  ~ZlibCompressor() {
    if(z_init_error_ == Z_OK)
      deflateEnd(&zstream_);
  }

  const char *zlibErrorMessage() const { return zstream_.msg; }

  int zlibErrorCode() const { return zerror_; }

  std::string output() const
  {
    if(valid())
      return output_;
    return "";
  }
    
  bool valid() const { return zerror_ == Z_OK; }

 private:

  const static int CHUNK = 8192;

  int compress() {
    unsigned char out[CHUNK];
    size_t size = input_.size();
    size_t begin = 0;
    int ret;
    int flush;
    do
    {
      int chunk;
      if(size - begin <= CHUNK)
      {
        chunk = size - begin;
        flush = Z_FINISH;
      }
      else
      {
        chunk = CHUNK;
        flush = Z_NO_FLUSH;
      }
      zstream_.avail_in = chunk;
      zstream_.next_in = (Bytef *)&input_[begin];
      do
      {
        zstream_.avail_out = CHUNK;
        zstream_.next_out = out;
        ret = deflate(&zstream_, flush);
        assert(ret != Z_STREAM_ERROR);
        int have = CHUNK - static_cast<int>(zstream_.avail_out);
        output_.append(out, out + have);
      }while(zstream_.avail_out == 0);
      assert(zstream_.avail_in == 0);
      begin += chunk;
    }while(flush != Z_FINISH);
    assert(ret == Z_STREAM_END);
    return Z_OK;
  }

  z_stream zstream_;
  int zerror_;
  int z_init_error_;
  std::string input_;
  std::string output_;
};
posted @ 2017-03-25 15:24 ZHOU YANG 阅读(...) 评论(...) 编辑 收藏