1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/Compression.h"
8 #include "mozilla/CheckedInt.h"
10 // Without including <string>, MSVC 2015 complains about e.g. the impossibility
11 // to convert `const void* const` to `void*` when calling memchr from
16 #include "lz4/lz4frame.h"
18 using namespace mozilla
;
19 using namespace mozilla::Compression
;
23 size_t LZ4::compress(const char* aSource
, size_t aInputSize
, char* aDest
) {
24 CheckedInt
<int> inputSizeChecked
= aInputSize
;
25 MOZ_ASSERT(inputSizeChecked
.isValid());
26 return LZ4_compress_default(aSource
, aDest
, inputSizeChecked
.value(),
27 LZ4_compressBound(inputSizeChecked
.value()));
30 size_t LZ4::compressLimitedOutput(const char* aSource
, size_t aInputSize
,
31 char* aDest
, size_t aMaxOutputSize
) {
32 CheckedInt
<int> inputSizeChecked
= aInputSize
;
33 MOZ_ASSERT(inputSizeChecked
.isValid());
34 CheckedInt
<int> maxOutputSizeChecked
= aMaxOutputSize
;
35 MOZ_ASSERT(maxOutputSizeChecked
.isValid());
36 return LZ4_compress_default(aSource
, aDest
, inputSizeChecked
.value(),
37 maxOutputSizeChecked
.value());
40 bool LZ4::decompress(const char* aSource
, size_t aInputSize
, char* aDest
,
41 size_t aMaxOutputSize
, size_t* aOutputSize
) {
42 CheckedInt
<int> maxOutputSizeChecked
= aMaxOutputSize
;
43 MOZ_ASSERT(maxOutputSizeChecked
.isValid());
44 CheckedInt
<int> inputSizeChecked
= aInputSize
;
45 MOZ_ASSERT(inputSizeChecked
.isValid());
47 int ret
= LZ4_decompress_safe(aSource
, aDest
, inputSizeChecked
.value(),
48 maxOutputSizeChecked
.value());
58 bool LZ4::decompressPartial(const char* aSource
, size_t aInputSize
, char* aDest
,
59 size_t aMaxOutputSize
, size_t* aOutputSize
) {
60 CheckedInt
<int> maxOutputSizeChecked
= aMaxOutputSize
;
61 MOZ_ASSERT(maxOutputSizeChecked
.isValid());
62 CheckedInt
<int> inputSizeChecked
= aInputSize
;
63 MOZ_ASSERT(inputSizeChecked
.isValid());
65 int ret
= LZ4_decompress_safe_partial(
66 aSource
, aDest
, inputSizeChecked
.value(), maxOutputSizeChecked
.value(),
67 maxOutputSizeChecked
.value());
77 LZ4FrameCompressionContext::LZ4FrameCompressionContext(int aCompressionLevel
,
82 mCompressionLevel(aCompressionLevel
),
83 mGenerateChecksum(aChecksum
),
84 mStableSrc(aStableSrc
),
85 mMaxSrcSize(aMaxSrcSize
),
87 LZ4F_contentChecksum_t checksum
=
88 mGenerateChecksum
? LZ4F_contentChecksumEnabled
: LZ4F_noContentChecksum
;
89 LZ4F_preferences_t prefs
= {
97 mWriteBufLen
= LZ4F_compressBound(mMaxSrcSize
, &prefs
);
98 LZ4F_errorCode_t err
= LZ4F_createCompressionContext(&mContext
, LZ4F_VERSION
);
99 MOZ_RELEASE_ASSERT(!LZ4F_isError(err
));
102 LZ4FrameCompressionContext::~LZ4FrameCompressionContext() {
103 LZ4F_freeCompressionContext(mContext
);
106 Result
<Span
<const char>, size_t> LZ4FrameCompressionContext::BeginCompressing(
107 Span
<char> aWriteBuffer
) {
108 mWriteBuffer
= aWriteBuffer
;
109 LZ4F_contentChecksum_t checksum
=
110 mGenerateChecksum
? LZ4F_contentChecksumEnabled
: LZ4F_noContentChecksum
;
111 LZ4F_preferences_t prefs
= {
119 size_t headerSize
= LZ4F_compressBegin(mContext
, mWriteBuffer
.Elements(),
120 mWriteBufLen
, &prefs
);
121 if (LZ4F_isError(headerSize
)) {
122 return Err(headerSize
);
125 return Span
{static_cast<const char*>(mWriteBuffer
.Elements()), headerSize
};
128 Result
<Span
<const char>, size_t>
129 LZ4FrameCompressionContext::ContinueCompressing(Span
<const char> aInput
) {
130 LZ4F_compressOptions_t opts
= {};
131 opts
.stableSrc
= (uint32_t)mStableSrc
;
133 LZ4F_compressUpdate(mContext
, mWriteBuffer
.Elements(), mWriteBufLen
,
134 aInput
.Elements(), aInput
.Length(), &opts
);
135 if (LZ4F_isError(outputSize
)) {
136 return Err(outputSize
);
139 return Span
{static_cast<const char*>(mWriteBuffer
.Elements()), outputSize
};
142 Result
<Span
<const char>, size_t> LZ4FrameCompressionContext::EndCompressing() {
144 LZ4F_compressEnd(mContext
, mWriteBuffer
.Elements(), mWriteBufLen
,
145 /* options */ nullptr);
146 if (LZ4F_isError(outputSize
)) {
147 return Err(outputSize
);
150 return Span
{static_cast<const char*>(mWriteBuffer
.Elements()), outputSize
};
153 LZ4FrameDecompressionContext::LZ4FrameDecompressionContext(bool aStableDest
)
154 : mContext(nullptr), mStableDest(aStableDest
) {
155 LZ4F_errorCode_t err
=
156 LZ4F_createDecompressionContext(&mContext
, LZ4F_VERSION
);
157 MOZ_RELEASE_ASSERT(!LZ4F_isError(err
));
160 LZ4FrameDecompressionContext::~LZ4FrameDecompressionContext() {
161 LZ4F_freeDecompressionContext(mContext
);
164 Result
<LZ4FrameDecompressionResult
, size_t>
165 LZ4FrameDecompressionContext::Decompress(Span
<char> aOutput
,
166 Span
<const char> aInput
) {
167 LZ4F_decompressOptions_t opts
= {};
168 opts
.stableDst
= (uint32_t)mStableDest
;
169 size_t outBytes
= aOutput
.Length();
170 size_t inBytes
= aInput
.Length();
171 size_t result
= LZ4F_decompress(mContext
, aOutput
.Elements(), &outBytes
,
172 aInput
.Elements(), &inBytes
, &opts
);
173 if (LZ4F_isError(result
)) {
177 LZ4FrameDecompressionResult decompressionResult
= {};
178 decompressionResult
.mFinished
= !result
;
179 decompressionResult
.mSizeRead
= inBytes
;
180 decompressionResult
.mSizeWritten
= outBytes
;
181 return decompressionResult
;