mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-01 08:42:13 +00:00
dea5b543db
Differential Revision: https://phabricator.services.mozilla.com/D83812
183 lines
6.3 KiB
C++
183 lines
6.3 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "mozilla/Compression.h"
|
|
#include "mozilla/CheckedInt.h"
|
|
|
|
// Without including <string>, MSVC 2015 complains about e.g. the impossibility
|
|
// to convert `const void* const` to `void*` when calling memchr from
|
|
// corecrt_memory.h.
|
|
#include <string>
|
|
|
|
#include "lz4/lz4.h"
|
|
#include "lz4/lz4frame.h"
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::Compression;
|
|
|
|
/* Our wrappers */
|
|
|
|
size_t LZ4::compress(const char* aSource, size_t aInputSize, char* aDest) {
|
|
CheckedInt<int> inputSizeChecked = aInputSize;
|
|
MOZ_ASSERT(inputSizeChecked.isValid());
|
|
return LZ4_compress_default(aSource, aDest, inputSizeChecked.value(),
|
|
LZ4_compressBound(inputSizeChecked.value()));
|
|
}
|
|
|
|
size_t LZ4::compressLimitedOutput(const char* aSource, size_t aInputSize,
|
|
char* aDest, size_t aMaxOutputSize) {
|
|
CheckedInt<int> inputSizeChecked = aInputSize;
|
|
MOZ_ASSERT(inputSizeChecked.isValid());
|
|
CheckedInt<int> maxOutputSizeChecked = aMaxOutputSize;
|
|
MOZ_ASSERT(maxOutputSizeChecked.isValid());
|
|
return LZ4_compress_default(aSource, aDest, inputSizeChecked.value(),
|
|
maxOutputSizeChecked.value());
|
|
}
|
|
|
|
bool LZ4::decompress(const char* aSource, size_t aInputSize, char* aDest,
|
|
size_t aMaxOutputSize, size_t* aOutputSize) {
|
|
CheckedInt<int> maxOutputSizeChecked = aMaxOutputSize;
|
|
MOZ_ASSERT(maxOutputSizeChecked.isValid());
|
|
CheckedInt<int> inputSizeChecked = aInputSize;
|
|
MOZ_ASSERT(inputSizeChecked.isValid());
|
|
|
|
int ret = LZ4_decompress_safe(aSource, aDest, inputSizeChecked.value(),
|
|
maxOutputSizeChecked.value());
|
|
if (ret >= 0) {
|
|
*aOutputSize = ret;
|
|
return true;
|
|
}
|
|
|
|
*aOutputSize = 0;
|
|
return false;
|
|
}
|
|
|
|
bool LZ4::decompressPartial(const char* aSource, size_t aInputSize, char* aDest,
|
|
size_t aMaxOutputSize, size_t* aOutputSize) {
|
|
CheckedInt<int> maxOutputSizeChecked = aMaxOutputSize;
|
|
MOZ_ASSERT(maxOutputSizeChecked.isValid());
|
|
CheckedInt<int> inputSizeChecked = aInputSize;
|
|
MOZ_ASSERT(inputSizeChecked.isValid());
|
|
|
|
int ret = LZ4_decompress_safe_partial(
|
|
aSource, aDest, inputSizeChecked.value(), maxOutputSizeChecked.value(),
|
|
maxOutputSizeChecked.value());
|
|
if (ret >= 0) {
|
|
*aOutputSize = ret;
|
|
return true;
|
|
}
|
|
|
|
*aOutputSize = 0;
|
|
return false;
|
|
}
|
|
|
|
LZ4FrameCompressionContext::LZ4FrameCompressionContext(int aCompressionLevel,
|
|
size_t aMaxSrcSize,
|
|
bool aChecksum,
|
|
bool aStableSrc)
|
|
: mContext(nullptr),
|
|
mCompressionLevel(aCompressionLevel),
|
|
mGenerateChecksum(aChecksum),
|
|
mStableSrc(aStableSrc),
|
|
mMaxSrcSize(aMaxSrcSize),
|
|
mWriteBufLen(0) {
|
|
LZ4F_contentChecksum_t checksum =
|
|
mGenerateChecksum ? LZ4F_contentChecksumEnabled : LZ4F_noContentChecksum;
|
|
LZ4F_preferences_t prefs = {
|
|
{
|
|
LZ4F_max256KB,
|
|
LZ4F_blockLinked,
|
|
checksum,
|
|
},
|
|
mCompressionLevel,
|
|
};
|
|
mWriteBufLen = LZ4F_compressBound(mMaxSrcSize, &prefs);
|
|
LZ4F_errorCode_t err = LZ4F_createCompressionContext(&mContext, LZ4F_VERSION);
|
|
MOZ_RELEASE_ASSERT(!LZ4F_isError(err));
|
|
}
|
|
|
|
LZ4FrameCompressionContext::~LZ4FrameCompressionContext() {
|
|
LZ4F_freeCompressionContext(mContext);
|
|
}
|
|
|
|
Result<Span<const char>, size_t> LZ4FrameCompressionContext::BeginCompressing(
|
|
Span<char> aWriteBuffer) {
|
|
mWriteBuffer = aWriteBuffer;
|
|
LZ4F_contentChecksum_t checksum =
|
|
mGenerateChecksum ? LZ4F_contentChecksumEnabled : LZ4F_noContentChecksum;
|
|
LZ4F_preferences_t prefs = {
|
|
{
|
|
LZ4F_max256KB,
|
|
LZ4F_blockLinked,
|
|
checksum,
|
|
},
|
|
mCompressionLevel,
|
|
};
|
|
size_t headerSize = LZ4F_compressBegin(mContext, mWriteBuffer.Elements(),
|
|
mWriteBufLen, &prefs);
|
|
if (LZ4F_isError(headerSize)) {
|
|
return Err(headerSize);
|
|
}
|
|
|
|
return Span{static_cast<const char*>(mWriteBuffer.Elements()), headerSize};
|
|
}
|
|
|
|
Result<Span<const char>, size_t>
|
|
LZ4FrameCompressionContext::ContinueCompressing(Span<const char> aInput) {
|
|
LZ4F_compressOptions_t opts = {};
|
|
opts.stableSrc = (uint32_t)mStableSrc;
|
|
size_t outputSize =
|
|
LZ4F_compressUpdate(mContext, mWriteBuffer.Elements(), mWriteBufLen,
|
|
aInput.Elements(), aInput.Length(), &opts);
|
|
if (LZ4F_isError(outputSize)) {
|
|
return Err(outputSize);
|
|
}
|
|
|
|
return Span{static_cast<const char*>(mWriteBuffer.Elements()), outputSize};
|
|
}
|
|
|
|
Result<Span<const char>, size_t> LZ4FrameCompressionContext::EndCompressing() {
|
|
size_t outputSize =
|
|
LZ4F_compressEnd(mContext, mWriteBuffer.Elements(), mWriteBufLen,
|
|
/* options */ nullptr);
|
|
if (LZ4F_isError(outputSize)) {
|
|
return Err(outputSize);
|
|
}
|
|
|
|
return Span{static_cast<const char*>(mWriteBuffer.Elements()), outputSize};
|
|
}
|
|
|
|
LZ4FrameDecompressionContext::LZ4FrameDecompressionContext(bool aStableDest)
|
|
: mContext(nullptr), mStableDest(aStableDest) {
|
|
LZ4F_errorCode_t err =
|
|
LZ4F_createDecompressionContext(&mContext, LZ4F_VERSION);
|
|
MOZ_RELEASE_ASSERT(!LZ4F_isError(err));
|
|
}
|
|
|
|
LZ4FrameDecompressionContext::~LZ4FrameDecompressionContext() {
|
|
LZ4F_freeDecompressionContext(mContext);
|
|
}
|
|
|
|
Result<LZ4FrameDecompressionResult, size_t>
|
|
LZ4FrameDecompressionContext::Decompress(Span<char> aOutput,
|
|
Span<const char> aInput) {
|
|
LZ4F_decompressOptions_t opts = {};
|
|
opts.stableDst = (uint32_t)mStableDest;
|
|
size_t outBytes = aOutput.Length();
|
|
size_t inBytes = aInput.Length();
|
|
size_t result = LZ4F_decompress(mContext, aOutput.Elements(), &outBytes,
|
|
aInput.Elements(), &inBytes, &opts);
|
|
if (LZ4F_isError(result)) {
|
|
return Err(result);
|
|
}
|
|
|
|
LZ4FrameDecompressionResult decompressionResult = {};
|
|
decompressionResult.mFinished = !result;
|
|
decompressionResult.mSizeRead = inBytes;
|
|
decompressionResult.mSizeWritten = outBytes;
|
|
return decompressionResult;
|
|
}
|