This repository has been archived on 2025-03-20. You can view files and clone it, but cannot push or open issues or pull requests.
The-Powder-Toy/src/bzip2/bz2wrap.cpp
Tamás Bálint Misius ab600780d0
Clean up GameSave somewhat
Namely:

 - get rid of unsafe memory management;
   - use vectors / Planes everywhere;
   - return a vector from serialization functions;
   - have read functions take a vector;
 - improve constness;
 - hide a few implementation details from GameSave.h;
 - get rid of GameSave copy constructor;
 - better member initialization;
 - use the slightly more C++-looking BZ2 wrappers.

The BSON library still takes ownership of the data it parses, and GameSave
ownership is still a joke. Those will need to be fixed later.
2022-11-10 15:15:10 +01:00

121 lines
2.7 KiB
C++

#include "bz2wrap.h"
#include "bzlib.h"
#include <memory>
#include <functional>
#include <vector>
#include <algorithm>
static size_t outputSizeIncrement = 0x100000U;
BZ2WCompressResult BZ2WCompress(std::vector<char> &dest, const char *srcData, size_t srcSize, size_t maxSize)
{
bz_stream stream;
stream.bzalloc = NULL;
stream.bzfree = NULL;
stream.opaque = NULL;
if (BZ2_bzCompressInit(&stream, 9, 0, 0) != BZ_OK)
{
return BZ2WCompressNomem;
}
std::unique_ptr<bz_stream, std::function<int (bz_stream *)>> bz2Data(&stream, BZ2_bzCompressEnd);
stream.next_in = const_cast<char *>(srcData); // I hope bz2 doesn't actually write anything here...
stream.avail_in = srcSize;
dest.resize(0);
bool done = false;
while (!done)
{
size_t oldSize = dest.size();
size_t newSize = oldSize + outputSizeIncrement;
if (maxSize && newSize > maxSize)
{
newSize = maxSize;
}
if (oldSize == newSize)
{
return BZ2WCompressLimit;
}
try
{
dest.resize(newSize);
}
catch (const std::bad_alloc &)
{
return BZ2WCompressNomem;
}
stream.next_out = &dest[stream.total_out_lo32];
stream.avail_out = dest.size() - stream.total_out_lo32;
if (BZ2_bzCompress(&stream, BZ_FINISH) == BZ_STREAM_END)
{
done = true;
}
}
dest.resize(stream.total_out_lo32);
return BZ2WCompressOk;
}
BZ2WDecompressResult BZ2WDecompress(std::vector<char> &dest, const char *srcData, size_t srcSize, size_t maxSize)
{
bz_stream stream;
stream.bzalloc = NULL;
stream.bzfree = NULL;
stream.opaque = NULL;
if (BZ2_bzDecompressInit(&stream, 0, 0) != BZ_OK)
{
return BZ2WDecompressNomem;
}
std::unique_ptr<bz_stream, std::function<int (bz_stream *)>> bz2Data(&stream, BZ2_bzDecompressEnd);
stream.next_in = const_cast<char *>(srcData); // I hope bz2 doesn't actually write anything here...
stream.avail_in = srcSize;
dest.resize(0);
bool done = false;
while (!done)
{
size_t oldSize = dest.size();
size_t newSize = oldSize + outputSizeIncrement;
if (maxSize && newSize > maxSize)
{
newSize = maxSize;
}
if (oldSize == newSize)
{
return BZ2WDecompressLimit;
}
try
{
dest.resize(newSize);
}
catch (const std::bad_alloc &)
{
return BZ2WDecompressNomem;
}
stream.next_out = &dest[stream.total_out_lo32];
stream.avail_out = dest.size() - stream.total_out_lo32;
switch (BZ2_bzDecompress(&stream))
{
case BZ_OK:
if (!stream.avail_in && stream.avail_out)
{
return BZ2WDecompressEof;
}
break;
case BZ_MEM_ERROR:
return BZ2WDecompressNomem;
case BZ_DATA_ERROR:
return BZ2WDecompressBad;
case BZ_DATA_ERROR_MAGIC:
return BZ2WDecompressType;
case BZ_STREAM_END:
done = true;
break;
}
}
dest.resize(stream.total_out_lo32);
return BZ2WDecompressOk;
}