void GzipCompressor::Uncompress(std::string& uncompressed, const void* compressed, size_t compressedSize) { uint64_t uncompressedSize; const uint8_t* source = reinterpret_cast<const uint8_t*>(compressed); if (HasPrefixWithUncompressedSize()) { uncompressedSize = ReadUncompressedSizePrefix(compressed, compressedSize); source += sizeof(uint64_t); compressedSize -= sizeof(uint64_t); } else { uncompressedSize = GuessUncompressedSize(compressed, compressedSize); } try { uncompressed.resize(static_cast<size_t>(uncompressedSize)); } catch (...) { throw OrthancException(ErrorCode_NotEnoughMemory); } z_stream stream; memset(&stream, 0, sizeof(stream)); char dummy = '\0'; // zlib does not like NULL output buffers (even if the uncompressed data is empty) stream.next_in = const_cast<Bytef*>(source); stream.next_out = reinterpret_cast<Bytef*>(uncompressedSize == 0 ? &dummy : &uncompressed[0]); stream.avail_in = static_cast<uInt>(compressedSize); stream.avail_out = static_cast<uInt>(uncompressedSize); // Ensure no overflow (if the buffer is too large for the current archicture) if (static_cast<size_t>(stream.avail_in) != compressedSize || static_cast<size_t>(stream.avail_out) != uncompressedSize) { throw OrthancException(ErrorCode_NotEnoughMemory); } // Initialize the compression engine int error = inflateInit2(&stream, MAX_WBITS + 16); // this is a gzip input if (error != Z_OK) { // Cannot initialize zlib uncompressed.clear(); throw OrthancException(ErrorCode_InternalError); } // Uncompress the input buffer error = inflate(&stream, Z_FINISH); if (error != Z_STREAM_END) { inflateEnd(&stream); uncompressed.clear(); switch (error) { case Z_MEM_ERROR: throw OrthancException(ErrorCode_NotEnoughMemory); case Z_BUF_ERROR: case Z_NEED_DICT: throw OrthancException(ErrorCode_BadFileFormat); default: throw OrthancException(ErrorCode_InternalError); } } size_t size = stream.total_out; if (inflateEnd(&stream) != Z_OK) { uncompressed.clear(); throw OrthancException(ErrorCode_InternalError); } if (size != uncompressedSize) { uncompressed.clear(); // The uncompressed size was not that properly guess, presumably // because of a file size over 4GB. Should fallback to // stream-based decompression. LOG(ERROR) << "The uncompressed size of a gzip-encoded buffer was not properly guessed"; throw OrthancException(ErrorCode_NotImplemented); } }
void ZlibCompressor::Uncompress(std::string& uncompressed, const void* compressed, size_t compressedSize) { if (compressedSize == 0) { uncompressed.clear(); return; } if (!HasPrefixWithUncompressedSize()) { LOG(ERROR) << "Cannot guess the uncompressed size of a zlib-encoded buffer"; throw OrthancException(ErrorCode_InternalError); } uint64_t uncompressedSize = ReadUncompressedSizePrefix(compressed, compressedSize); try { uncompressed.resize(static_cast<size_t>(uncompressedSize)); } catch (...) { throw OrthancException(ErrorCode_NotEnoughMemory); } uLongf tmp = static_cast<uLongf>(uncompressedSize); int error = uncompress (reinterpret_cast<uint8_t*>(&uncompressed[0]), &tmp, reinterpret_cast<const uint8_t*>(compressed) + sizeof(uint64_t), compressedSize - sizeof(uint64_t)); if (error != Z_OK) { uncompressed.clear(); switch (error) { case Z_DATA_ERROR: throw OrthancException(ErrorCode_CorruptedFile); case Z_MEM_ERROR: throw OrthancException(ErrorCode_NotEnoughMemory); default: throw OrthancException(ErrorCode_InternalError); } } }