/* ============================================================================== This file is part of the JUCE library - "Jules' Utility Class Extensions" Copyright 2004-9 by Raw Material Software Ltd. ------------------------------------------------------------------------------ JUCE can be redistributed and/or modified under the terms of the GNU General Public License (Version 2), as published by the Free Software Foundation. A copy of the license is included in the JUCE distribution, or can be found online at www.gnu.org/licenses. JUCE 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 General Public License for more details. ------------------------------------------------------------------------------ To release a closed-source product which uses JUCE, commercial licenses are available: visit www.rawmaterialsoftware.com/juce for more information. ============================================================================== */ #include "../../core/juce_StandardHeader.h" namespace zlibNamespace { #if JUCE_INCLUDE_ZLIB_CODE #undef OS_CODE #undef fdopen #include "zlib/zlib.h" #undef OS_CODE #else #include #endif } BEGIN_JUCE_NAMESPACE #include "juce_GZIPCompressorOutputStream.h" //============================================================================== // internal helper object that holds the zlib structures so they don't have to be // included publicly. class GZIPCompressorHelper { public: GZIPCompressorHelper (const int compressionLevel, const bool nowrap) : data (0), dataSize (0), compLevel (compressionLevel), strategy (0), setParams (true), streamIsValid (false), finished (false), shouldFinish (false) { using namespace zlibNamespace; zerostruct (stream); streamIsValid = (deflateInit2 (&stream, compLevel, Z_DEFLATED, nowrap ? -MAX_WBITS : MAX_WBITS, 8, strategy) == Z_OK); } ~GZIPCompressorHelper() { using namespace zlibNamespace; if (streamIsValid) deflateEnd (&stream); } bool needsInput() const throw() { return dataSize <= 0; } void setInput (uint8* const newData, const int size) throw() { data = newData; dataSize = size; } int doNextBlock (uint8* const dest, const int destSize) throw() { using namespace zlibNamespace; if (streamIsValid) { stream.next_in = data; stream.next_out = dest; stream.avail_in = dataSize; stream.avail_out = destSize; const int result = setParams ? deflateParams (&stream, compLevel, strategy) : deflate (&stream, shouldFinish ? Z_FINISH : Z_NO_FLUSH); setParams = false; switch (result) { case Z_STREAM_END: finished = true; // Deliberate fall-through.. case Z_OK: data += dataSize - stream.avail_in; dataSize = stream.avail_in; return destSize - stream.avail_out; default: break; } } return 0; } private: zlibNamespace::z_stream stream; uint8* data; int dataSize, compLevel, strategy; bool setParams, streamIsValid; public: bool finished, shouldFinish; }; //============================================================================== const int gzipCompBufferSize = 32768; GZIPCompressorOutputStream::GZIPCompressorOutputStream (OutputStream* const destStream_, int compressionLevel, const bool deleteDestStream, const bool noWrap) : destStream (destStream_), streamToDelete (deleteDestStream ? destStream_ : 0), buffer (gzipCompBufferSize) { if (compressionLevel < 1 || compressionLevel > 9) compressionLevel = -1; helper = new GZIPCompressorHelper (compressionLevel, noWrap); } GZIPCompressorOutputStream::~GZIPCompressorOutputStream() { flush(); } //============================================================================== void GZIPCompressorOutputStream::flush() { if (! helper->finished) { helper->shouldFinish = true; while (! helper->finished) doNextBlock(); } destStream->flush(); } bool GZIPCompressorOutputStream::write (const void* destBuffer, int howMany) { if (! helper->finished) { helper->setInput ((uint8*) destBuffer, howMany); while (! helper->needsInput()) { if (! doNextBlock()) return false; } } return true; } bool GZIPCompressorOutputStream::doNextBlock() { const int len = helper->doNextBlock (buffer, gzipCompBufferSize); if (len > 0) return destStream->write (buffer, len); else return true; } int64 GZIPCompressorOutputStream::getPosition() { return destStream->getPosition(); } bool GZIPCompressorOutputStream::setPosition (int64 /*newPosition*/) { jassertfalse // can't do it! return false; } END_JUCE_NAMESPACE