mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-21 11:35:53 +00:00
209 lines
6.7 KiB
C++
209 lines
6.7 KiB
C++
/*
|
|
==============================================================================
|
|
|
|
This file is part of the beast_core module of the BEAST library.
|
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
|
or without fee is hereby granted, provided that the above copyright notice and this
|
|
permission notice appear in all copies.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
------------------------------------------------------------------------------
|
|
|
|
NOTE! This permissive ISC license applies ONLY to files within the beast_core module!
|
|
All other BEAST modules are covered by a dual GPL/commercial license, so if you are
|
|
using any other modules, be sure to check that you also comply with their license.
|
|
|
|
For more details, visit www.beast.com
|
|
|
|
==============================================================================
|
|
*/
|
|
|
|
class GZIPCompressorOutputStream::GZIPCompressorHelper : public Uncopyable
|
|
{
|
|
public:
|
|
GZIPCompressorHelper (const int compressionLevel, const int windowBits)
|
|
: compLevel ((compressionLevel < 1 || compressionLevel > 9) ? -1 : compressionLevel),
|
|
isFirstDeflate (true),
|
|
streamIsValid (false),
|
|
finished (false)
|
|
{
|
|
using namespace zlibNamespace;
|
|
zerostruct (stream);
|
|
|
|
streamIsValid = (deflateInit2 (&stream, compLevel, Z_DEFLATED,
|
|
windowBits != 0 ? windowBits : MAX_WBITS,
|
|
8, strategy) == Z_OK);
|
|
}
|
|
|
|
~GZIPCompressorHelper()
|
|
{
|
|
if (streamIsValid)
|
|
zlibNamespace::deflateEnd (&stream);
|
|
}
|
|
|
|
bool write (const uint8* data, size_t dataSize, OutputStream& out)
|
|
{
|
|
// When you call flush() on a gzip stream, the stream is closed, and you can
|
|
// no longer continue to write data to it!
|
|
bassert (! finished);
|
|
|
|
while (dataSize > 0)
|
|
if (! doNextBlock (data, dataSize, out, Z_NO_FLUSH))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void finish (OutputStream& out)
|
|
{
|
|
const uint8* data = nullptr;
|
|
size_t dataSize = 0;
|
|
|
|
while (! finished)
|
|
doNextBlock (data, dataSize, out, Z_FINISH);
|
|
}
|
|
|
|
private:
|
|
enum { strategy = 0 };
|
|
|
|
zlibNamespace::z_stream stream;
|
|
const int compLevel;
|
|
bool isFirstDeflate, streamIsValid, finished;
|
|
zlibNamespace::Bytef buffer[32768];
|
|
|
|
bool doNextBlock (const uint8*& data, size_t& dataSize, OutputStream& out, const int flushMode)
|
|
{
|
|
using namespace zlibNamespace;
|
|
|
|
if (streamIsValid)
|
|
{
|
|
stream.next_in = const_cast <uint8*> (data);
|
|
stream.next_out = buffer;
|
|
stream.avail_in = (z_uInt) dataSize;
|
|
stream.avail_out = (z_uInt) sizeof (buffer);
|
|
|
|
const int result = isFirstDeflate ? deflateParams (&stream, compLevel, strategy)
|
|
: deflate (&stream, flushMode);
|
|
isFirstDeflate = false;
|
|
|
|
switch (result)
|
|
{
|
|
case Z_STREAM_END:
|
|
finished = true;
|
|
// Deliberate fall-through..
|
|
case Z_OK:
|
|
{
|
|
data += dataSize - stream.avail_in;
|
|
dataSize = stream.avail_in;
|
|
const ssize_t bytesDone = (ssize_t) sizeof (buffer) - (ssize_t) stream.avail_out;
|
|
return bytesDone <= 0 || out.write (buffer, (size_t) bytesDone);
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
//==============================================================================
|
|
GZIPCompressorOutputStream::GZIPCompressorOutputStream (OutputStream* const out,
|
|
const int compressionLevel,
|
|
const bool deleteDestStream,
|
|
const int windowBits)
|
|
: destStream (out, deleteDestStream),
|
|
helper (new GZIPCompressorHelper (compressionLevel, windowBits))
|
|
{
|
|
bassert (out != nullptr);
|
|
}
|
|
|
|
GZIPCompressorOutputStream::~GZIPCompressorOutputStream()
|
|
{
|
|
flush();
|
|
}
|
|
|
|
void GZIPCompressorOutputStream::flush()
|
|
{
|
|
helper->finish (*destStream);
|
|
destStream->flush();
|
|
}
|
|
|
|
bool GZIPCompressorOutputStream::write (const void* destBuffer, size_t howMany)
|
|
{
|
|
bassert (destBuffer != nullptr && (ssize_t) howMany >= 0);
|
|
|
|
return helper->write (static_cast <const uint8*> (destBuffer), howMany, *destStream);
|
|
}
|
|
|
|
int64 GZIPCompressorOutputStream::getPosition()
|
|
{
|
|
return destStream->getPosition();
|
|
}
|
|
|
|
bool GZIPCompressorOutputStream::setPosition (int64 /*newPosition*/)
|
|
{
|
|
bassertfalse; // can't do it!
|
|
return false;
|
|
}
|
|
|
|
//==============================================================================
|
|
|
|
class GZIPTests : public UnitTest
|
|
{
|
|
public:
|
|
GZIPTests() : UnitTest ("GZIP", "beast") {}
|
|
|
|
void runTest()
|
|
{
|
|
beginTestCase ("GZIP");
|
|
Random rng;
|
|
|
|
for (int i = 100; --i >= 0;)
|
|
{
|
|
MemoryOutputStream original, compressed, uncompressed;
|
|
|
|
{
|
|
GZIPCompressorOutputStream zipper (&compressed, rng.nextInt (10), false);
|
|
|
|
for (int j = rng.nextInt (100); --j >= 0;)
|
|
{
|
|
MemoryBlock data ((unsigned int) (rng.nextInt (2000) + 1));
|
|
|
|
for (int k = (int) data.getSize(); --k >= 0;)
|
|
data[k] = (char) rng.nextInt (255);
|
|
|
|
original << data;
|
|
zipper << data;
|
|
}
|
|
}
|
|
|
|
{
|
|
MemoryInputStream compressedInput (compressed.getData(), compressed.getDataSize(), false);
|
|
GZIPDecompressorInputStream unzipper (compressedInput);
|
|
|
|
uncompressed << unzipper;
|
|
}
|
|
|
|
expectEquals ((int) uncompressed.getDataSize(),
|
|
(int) original.getDataSize());
|
|
|
|
if (original.getDataSize() == uncompressed.getDataSize())
|
|
expect (memcmp (uncompressed.getData(),
|
|
original.getData(),
|
|
original.getDataSize()) == 0);
|
|
}
|
|
}
|
|
};
|
|
|
|
static GZIPTests gzipTests;
|