Bug 1732219 - Add API for fetching the preview image. r=geckoview-reviewers,agi,mconley
[gecko.git] / mfbt / Compression.cpp
blobb0c3db6980b4f9580015d66b400f0fcab47cdba2
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
12 // corecrt_memory.h.
13 #include <string>
15 #include "lz4/lz4.h"
16 #include "lz4/lz4frame.h"
18 using namespace mozilla;
19 using namespace mozilla::Compression;
21 /* Our wrappers */
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());
49 if (ret >= 0) {
50 *aOutputSize = ret;
51 return true;
54 *aOutputSize = 0;
55 return false;
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());
68 if (ret >= 0) {
69 *aOutputSize = ret;
70 return true;
73 *aOutputSize = 0;
74 return false;
77 LZ4FrameCompressionContext::LZ4FrameCompressionContext(int aCompressionLevel,
78 size_t aMaxSrcSize,
79 bool aChecksum,
80 bool aStableSrc)
81 : mContext(nullptr),
82 mCompressionLevel(aCompressionLevel),
83 mGenerateChecksum(aChecksum),
84 mStableSrc(aStableSrc),
85 mMaxSrcSize(aMaxSrcSize),
86 mWriteBufLen(0) {
87 LZ4F_contentChecksum_t checksum =
88 mGenerateChecksum ? LZ4F_contentChecksumEnabled : LZ4F_noContentChecksum;
89 LZ4F_preferences_t prefs = {
91 LZ4F_max256KB,
92 LZ4F_blockLinked,
93 checksum,
95 mCompressionLevel,
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 = {
113 LZ4F_max256KB,
114 LZ4F_blockLinked,
115 checksum,
117 mCompressionLevel,
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;
132 size_t outputSize =
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() {
143 size_t outputSize =
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)) {
174 return Err(result);
177 LZ4FrameDecompressionResult decompressionResult = {};
178 decompressionResult.mFinished = !result;
179 decompressionResult.mSizeRead = inBytes;
180 decompressionResult.mSizeWritten = outBytes;
181 return decompressionResult;