zutils.cpp

Go to the documentation of this file.
00001 /**
00002  *  Copyright (C) 2004-2005 Alo Sarv <madcat_@users.sourceforge.net>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017  */
00018 
00019 /** \file zutils.cpp Implementation of Zlib-related utility methods */
00020 
00021 #include <hn/hnprec.h>
00022 #include "zutils.h"
00023 #include <zlib.h>       // for zlib compression
00024 #include <hn/log.h>
00025 #include <hn/utils.h>
00026 
00027 namespace Zlib {
00028 
00029 // Pack data using zlib
00030 std::string compress(const std::string &input) {
00031         uLongf destLen = input.size() + 300;
00032         boost::scoped_array<Bytef> dest(new Bytef[destLen]);
00033         int ret = compress2(
00034                 dest.get(), &destLen,
00035                 reinterpret_cast<const Bytef*>(input.data()), input.size(),
00036                 Z_BEST_COMPRESSION
00037         );
00038         std::string tmp(reinterpret_cast<const char*>(dest.get()), destLen);
00039 
00040         if (ret == Z_OK) {
00041                 return tmp;
00042         } else {
00043                 switch (ret) {
00044                 case Z_MEM_ERROR:
00045                         logDebug(
00046                                 "ZError: Not enough memory to compress packet."
00047                         );
00048                         break;
00049                 case Z_BUF_ERROR:
00050                         logDebug(
00051                                 "ZError: Not enough buffer to compress packet."
00052                         );
00053                         break;
00054                 case Z_STREAM_ERROR:
00055                         logError(
00056                                 "ZError: Invalid compression level "
00057                                 "for compression."
00058                         );
00059                         break;
00060                 default:
00061                         break;
00062                 }
00063                 return std::string();
00064         }
00065 }
00066 
00067 // unpack data using zlib
00068 std::string decompress(const std::string &input, uint32_t bufsize /* = 0 */) {
00069         uLongf destLen = bufsize;
00070         if (destLen == 0) {
00071                 destLen = input.size() * 10 + 300;
00072         }
00073         boost::scoped_array<Bytef> dest(new Bytef[destLen]);
00074         memset(dest.get(), 0, destLen);
00075         int ret = uncompress(
00076                 dest.get(), &destLen,
00077                 reinterpret_cast<const Bytef*>(input.data()), input.size()
00078         );
00079         std::string tmp(reinterpret_cast<const char*>(dest.get()), destLen);
00080         if (ret == Z_OK) {
00081                 return tmp;
00082         }
00083         // Else
00084         boost::format fmt(
00085                 "Unpacking packet: inputSize=%s buffersize=%s: Error: `%s' %s"
00086         );
00087         fmt % Utils::hexDump(input.size()) % Utils::hexDump(destLen);
00088         switch (ret) {
00089                 case Z_MEM_ERROR:
00090                         fmt % "Not enough memory to decompress packet.";
00091                         break;
00092                 case Z_BUF_ERROR: {
00093                         fmt % "Not enough buffer to decompress packet.";
00094                         // call ourself again, increase buffer 10x
00095                         bool ok = false;
00096                         while (!ok) {
00097                                 try {
00098                                         tmp = decompress(input, destLen*10);
00099                                         ok = true;
00100                                 } catch (std::runtime_error&) {
00101                                         if (destLen > 1024*1024) {
00102                                                 // don't go over 1 MB bufsize
00103                                                 break;
00104                                         }
00105                                 }
00106                         }
00107                         if (ok) {
00108                                 return tmp;
00109                         } // else falls through and throws exception
00110                         break;
00111                 }
00112                 case Z_DATA_ERROR:
00113                         fmt % "Input corrupt or incomplete.";
00114                         break;
00115                 case Z_ERRNO:
00116                         fmt % "Z_ERRNO";
00117                         break;
00118                 case Z_VERSION_ERROR:
00119                         fmt % "Z_VERSION_ERROR";
00120                         break;
00121                 case Z_STREAM_ERROR:
00122                         fmt % "Z_STREAM_ERROR";
00123                         break;
00124                 default:
00125                         fmt % "Unknown error.";
00126                         break;
00127         }
00128         fmt % Utils::hexDump(input);
00129         throw std::runtime_error(fmt.str());
00130 }
00131 
00132 }