diff --git a/include/string.hpp b/include/string.hpp index 70e71cfa..30779269 100644 --- a/include/string.hpp +++ b/include/string.hpp @@ -77,11 +77,10 @@ std::vector compress(const uint8_t* data, size_t dataLen); std::vector compress(const std::vector& data); /** Uncompress bytes with zlib. Before calling this function, set `dataLen` to the capacity of `data`. -After returning, `dataLen` is set to the number of bytes written. -Unfortunately the output buffer cannot be computed from the compressed data, so you may need to hard-code the maximum expected size. +After returning, `dataLen` is set to the actual number of bytes written. */ void uncompress(const uint8_t* compressed, size_t compressedLen, uint8_t* data, size_t* dataLen); -void uncompress(const std::vector& compressed, uint8_t* data, size_t* dataLen); +std::vector uncompress(const std::vector& compressed); struct CaseInsensitiveCompare { diff --git a/src/string.cpp b/src/string.cpp index d980370c..dde1dff5 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -263,8 +263,32 @@ void uncompress(const uint8_t* compressed, size_t compressedLen, uint8_t* data, } -void uncompress(const std::vector& compressed, uint8_t* data, size_t* dataLen) { - uncompress(compressed.data(), compressed.size(), data, dataLen); +std::vector uncompress(const std::vector& compressed) { + // We don't know the uncompressed size, so we can't use the easy compress/uncompress API. + std::vector data; + + z_stream zs; + std::memset(&zs, 0, sizeof(zs)); + zs.next_in = (Bytef*) &compressed[0]; + zs.avail_in = compressed.size(); + inflateInit(&zs); + + while (true) { + uint8_t buffer[16384]; + zs.next_out = (Bytef*) buffer; + zs.avail_out = sizeof(buffer); + int err = inflate(&zs, Z_NO_FLUSH); + + if (err < 0) + throw Exception(string::f("zlib error %d", err)); + + data.insert(data.end(), buffer, zs.next_out); + if (err == Z_STREAM_END) + break; + } + + inflateEnd(&zs); + return data; }