Anvil: switched inflate to stream mode.
This removes the fixed-size buffer which could have caused #1307 and #1366.
This commit is contained in:
parent
1cc65b6264
commit
44c1d9c248
@ -180,3 +180,65 @@ extern int UncompressStringGZIP(const char * a_Data, size_t a_Length, AString &
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extern int InflateString(const char * a_Data, size_t a_Length, AString & a_Uncompressed)
|
||||||
|
{
|
||||||
|
a_Uncompressed.reserve(a_Length);
|
||||||
|
|
||||||
|
char Buffer[64 KiB];
|
||||||
|
z_stream strm;
|
||||||
|
memset(&strm, 0, sizeof(strm));
|
||||||
|
strm.next_in = (Bytef *)a_Data;
|
||||||
|
strm.avail_in = (uInt)a_Length;
|
||||||
|
strm.next_out = (Bytef *)Buffer;
|
||||||
|
strm.avail_out = sizeof(Buffer);
|
||||||
|
|
||||||
|
int res = inflateInit(&strm); // Force GZIP decoding
|
||||||
|
if (res != Z_OK)
|
||||||
|
{
|
||||||
|
LOG("%s: inflation initialization failed: %d (\"%s\").", __FUNCTION__, res, strm.msg);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
res = inflate(&strm, Z_NO_FLUSH);
|
||||||
|
switch (res)
|
||||||
|
{
|
||||||
|
case Z_OK:
|
||||||
|
{
|
||||||
|
// Some data has been uncompressed. Consume the buffer and continue uncompressing
|
||||||
|
a_Uncompressed.append(Buffer, sizeof(Buffer) - strm.avail_out);
|
||||||
|
strm.next_out = (Bytef *)Buffer;
|
||||||
|
strm.avail_out = sizeof(Buffer);
|
||||||
|
if (strm.avail_in == 0)
|
||||||
|
{
|
||||||
|
// All data has been uncompressed
|
||||||
|
inflateEnd(&strm);
|
||||||
|
return Z_OK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Z_STREAM_END:
|
||||||
|
{
|
||||||
|
// Finished uncompressing. Consume the rest of the buffer and return
|
||||||
|
a_Uncompressed.append(Buffer, sizeof(Buffer) - strm.avail_out);
|
||||||
|
inflateEnd(&strm);
|
||||||
|
return Z_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// An error has occurred, log it and return the error value
|
||||||
|
LOG("%s: inflation failed: %d (\"%s\").", __FUNCTION__, res, strm.msg);
|
||||||
|
inflateEnd(&strm);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
} // switch (res)
|
||||||
|
} // while (true)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,5 +21,7 @@ extern int CompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_
|
|||||||
/// Uncompresses a_Data into a_Uncompressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib
|
/// Uncompresses a_Data into a_Uncompressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib
|
||||||
extern int UncompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Uncompressed);
|
extern int UncompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Uncompressed);
|
||||||
|
|
||||||
|
/** Uncompresses a_Data into a_Uncompressed using Inflate; returns Z_OK for success or Z_XXX error constants same as zlib */
|
||||||
|
extern int InflateString(const char * a_Data, size_t a_Length, AString & a_Uncompressed);
|
||||||
|
|
||||||
|
|
||||||
|
@ -66,9 +66,6 @@ Since only the header is actually in the memory, this number can be high, but st
|
|||||||
*/
|
*/
|
||||||
#define MAX_MCA_FILES 32
|
#define MAX_MCA_FILES 32
|
||||||
|
|
||||||
/// The maximum size of an inflated chunk; raw chunk data is 192 KiB, allow 64 KiB more of entities
|
|
||||||
#define CHUNK_INFLATE_MAX 256 KiB
|
|
||||||
|
|
||||||
#define LOAD_FAILED(CHX, CHZ) \
|
#define LOAD_FAILED(CHX, CHZ) \
|
||||||
{ \
|
{ \
|
||||||
const int RegionX = FAST_FLOOR_DIV(CHX, 32); \
|
const int RegionX = FAST_FLOOR_DIV(CHX, 32); \
|
||||||
@ -260,27 +257,18 @@ cWSSAnvil::cMCAFile * cWSSAnvil::LoadMCAFile(const cChunkCoords & a_Chunk)
|
|||||||
|
|
||||||
bool cWSSAnvil::LoadChunkFromData(const cChunkCoords & a_Chunk, const AString & a_Data)
|
bool cWSSAnvil::LoadChunkFromData(const cChunkCoords & a_Chunk, const AString & a_Data)
|
||||||
{
|
{
|
||||||
// Decompress the data:
|
// Uncompress the data:
|
||||||
char Uncompressed[CHUNK_INFLATE_MAX];
|
AString Uncompressed;
|
||||||
z_stream strm;
|
int res = InflateString(a_Data.data(), a_Data.size(), Uncompressed);
|
||||||
strm.zalloc = (alloc_func)NULL;
|
if (res != Z_OK)
|
||||||
strm.zfree = (free_func)NULL;
|
|
||||||
strm.opaque = NULL;
|
|
||||||
inflateInit(&strm);
|
|
||||||
strm.next_out = (Bytef *)Uncompressed;
|
|
||||||
strm.avail_out = sizeof(Uncompressed);
|
|
||||||
strm.next_in = (Bytef *)a_Data.data();
|
|
||||||
strm.avail_in = (uInt)a_Data.size();
|
|
||||||
int res = inflate(&strm, Z_FINISH);
|
|
||||||
inflateEnd(&strm);
|
|
||||||
if (res != Z_STREAM_END)
|
|
||||||
{
|
{
|
||||||
|
LOGWARNING("Uncompressing chunk [%d, %d] failed: %d", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, res);
|
||||||
LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
|
LOAD_FAILED(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the NBT data:
|
// Parse the NBT data:
|
||||||
cParsedNBT NBT(Uncompressed, strm.total_out);
|
cParsedNBT NBT(Uncompressed.data(), Uncompressed.size());
|
||||||
if (!NBT.IsValid())
|
if (!NBT.IsValid())
|
||||||
{
|
{
|
||||||
// NBT Parsing failed
|
// NBT Parsing failed
|
||||||
|
Loading…
Reference in New Issue
Block a user