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::Compress(std::string& compressed, const void* uncompressed, size_t uncompressedSize) { if (uncompressedSize == 0) { compressed.clear(); return; } uLongf compressedSize = compressBound(uncompressedSize) + 1024 /* security margin */; if (compressedSize == 0) { compressedSize = 1; } uint8_t* target; if (HasPrefixWithUncompressedSize()) { compressed.resize(compressedSize + sizeof(uint64_t)); target = reinterpret_cast<uint8_t*>(&compressed[0]) + sizeof(uint64_t); } else { compressed.resize(compressedSize); target = reinterpret_cast<uint8_t*>(&compressed[0]); } int error = compress2(target, &compressedSize, const_cast<Bytef *>(static_cast<const Bytef *>(uncompressed)), uncompressedSize, GetCompressionLevel()); if (error != Z_OK) { compressed.clear(); switch (error) { case Z_MEM_ERROR: throw OrthancException(ErrorCode_NotEnoughMemory); default: throw OrthancException(ErrorCode_InternalError); } } // The compression was successful if (HasPrefixWithUncompressedSize()) { uint64_t s = static_cast<uint64_t>(uncompressedSize); memcpy(&compressed[0], &s, sizeof(uint64_t)); compressed.resize(compressedSize + sizeof(uint64_t)); } else { compressed.resize(compressedSize); } }
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); } } }
void GzipCompressor::Compress(std::string& compressed, const void* uncompressed, size_t uncompressedSize) { uLongf compressedSize = compressBound(uncompressedSize) + 1024 /* security margin */; if (compressedSize == 0) { compressedSize = 1; } uint8_t* target; if (HasPrefixWithUncompressedSize()) { compressed.resize(compressedSize + sizeof(uint64_t)); target = reinterpret_cast<uint8_t*>(&compressed[0]) + sizeof(uint64_t); } else { compressed.resize(compressedSize); target = reinterpret_cast<uint8_t*>(&compressed[0]); } z_stream stream; memset(&stream, 0, sizeof(stream)); stream.next_in = const_cast<Bytef*>(reinterpret_cast<const Bytef*>(uncompressed)); stream.next_out = reinterpret_cast<Bytef*>(target); stream.avail_in = static_cast<uInt>(uncompressedSize); stream.avail_out = static_cast<uInt>(compressedSize); // Ensure no overflow (if the buffer is too large for the current archicture) if (static_cast<size_t>(stream.avail_in) != uncompressedSize || static_cast<size_t>(stream.avail_out) != compressedSize) { throw OrthancException(ErrorCode_NotEnoughMemory); } // Initialize the compression engine int error = deflateInit2(&stream, GetCompressionLevel(), Z_DEFLATED, MAX_WBITS + 16, // ask for gzip output 8, // default memory level Z_DEFAULT_STRATEGY); if (error != Z_OK) { // Cannot initialize zlib compressed.clear(); throw OrthancException(ErrorCode_InternalError); } // Compress the input buffer error = deflate(&stream, Z_FINISH); if (error != Z_STREAM_END) { deflateEnd(&stream); compressed.clear(); switch (error) { case Z_MEM_ERROR: throw OrthancException(ErrorCode_NotEnoughMemory); default: throw OrthancException(ErrorCode_InternalError); } } size_t size = stream.total_out; if (deflateEnd(&stream) != Z_OK) { throw OrthancException(ErrorCode_InternalError); } // The compression was successful if (HasPrefixWithUncompressedSize()) { uint64_t s = static_cast<uint64_t>(uncompressedSize); memcpy(&compressed[0], &s, sizeof(uint64_t)); compressed.resize(size + sizeof(uint64_t)); } else { compressed.resize(size); } }