Compression.cpp (6465B)
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/. */ 6 7 #include "mozilla/Compression.h" 8 #include "mozilla/CheckedInt.h" 9 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 14 #include "lz4/lz4.h" 15 #include "lz4/lz4frame.h" 16 17 using namespace mozilla; 18 using namespace mozilla::Compression; 19 20 /* Our wrappers */ 21 22 size_t LZ4::compress(const char* aSource, size_t aInputSize, char* aDest) { 23 CheckedInt<int> inputSizeChecked = aInputSize; 24 MOZ_RELEASE_ASSERT(inputSizeChecked.isValid()); 25 return LZ4_compress_default(aSource, aDest, inputSizeChecked.value(), 26 LZ4_compressBound(inputSizeChecked.value())); 27 } 28 29 size_t LZ4::compressLimitedOutput(const char* aSource, size_t aInputSize, 30 char* aDest, size_t aMaxOutputSize) { 31 CheckedInt<int> inputSizeChecked = aInputSize; 32 MOZ_RELEASE_ASSERT(inputSizeChecked.isValid()); 33 CheckedInt<int> maxOutputSizeChecked = aMaxOutputSize; 34 MOZ_RELEASE_ASSERT(maxOutputSizeChecked.isValid()); 35 return LZ4_compress_default(aSource, aDest, inputSizeChecked.value(), 36 maxOutputSizeChecked.value()); 37 } 38 39 bool LZ4::decompress(const char* aSource, size_t aInputSize, char* aDest, 40 size_t aMaxOutputSize, size_t* aOutputSize) { 41 CheckedInt<int> maxOutputSizeChecked = aMaxOutputSize; 42 MOZ_RELEASE_ASSERT(maxOutputSizeChecked.isValid()); 43 CheckedInt<int> inputSizeChecked = aInputSize; 44 MOZ_RELEASE_ASSERT(inputSizeChecked.isValid()); 45 46 int ret = LZ4_decompress_safe(aSource, aDest, inputSizeChecked.value(), 47 maxOutputSizeChecked.value()); 48 if (ret >= 0) { 49 *aOutputSize = ret; 50 return true; 51 } 52 53 *aOutputSize = 0; 54 return false; 55 } 56 57 bool LZ4::decompressPartial(const char* aSource, size_t aInputSize, char* aDest, 58 size_t aMaxOutputSize, size_t* aOutputSize) { 59 CheckedInt<int> maxOutputSizeChecked = aMaxOutputSize; 60 MOZ_RELEASE_ASSERT(maxOutputSizeChecked.isValid()); 61 CheckedInt<int> inputSizeChecked = aInputSize; 62 MOZ_RELEASE_ASSERT(inputSizeChecked.isValid()); 63 64 int ret = LZ4_decompress_safe_partial( 65 aSource, aDest, inputSizeChecked.value(), maxOutputSizeChecked.value(), 66 maxOutputSizeChecked.value()); 67 if (ret >= 0) { 68 *aOutputSize = ret; 69 return true; 70 } 71 72 *aOutputSize = 0; 73 return false; 74 } 75 76 LZ4FrameCompressionContext::LZ4FrameCompressionContext(int aCompressionLevel, 77 size_t aMaxSrcSize, 78 bool aChecksum, 79 bool aStableSrc) 80 : mContext(nullptr), 81 mCompressionLevel(aCompressionLevel), 82 mGenerateChecksum(aChecksum), 83 mStableSrc(aStableSrc), 84 mMaxSrcSize(aMaxSrcSize), 85 mWriteBufLen(0) { 86 LZ4F_contentChecksum_t checksum = 87 mGenerateChecksum ? LZ4F_contentChecksumEnabled : LZ4F_noContentChecksum; 88 LZ4F_preferences_t prefs = { 89 { 90 LZ4F_max256KB, 91 LZ4F_blockLinked, 92 checksum, 93 }, 94 mCompressionLevel, 95 }; 96 mWriteBufLen = LZ4F_compressBound(mMaxSrcSize, &prefs); 97 LZ4F_errorCode_t err = LZ4F_createCompressionContext(&mContext, LZ4F_VERSION); 98 MOZ_RELEASE_ASSERT(!LZ4F_isError(err)); 99 } 100 101 LZ4FrameCompressionContext::~LZ4FrameCompressionContext() { 102 LZ4F_freeCompressionContext(mContext); 103 } 104 105 Result<Span<const char>, size_t> LZ4FrameCompressionContext::BeginCompressing( 106 Span<char> aWriteBuffer) { 107 mWriteBuffer = aWriteBuffer; 108 LZ4F_contentChecksum_t checksum = 109 mGenerateChecksum ? LZ4F_contentChecksumEnabled : LZ4F_noContentChecksum; 110 LZ4F_preferences_t prefs = { 111 { 112 LZ4F_max256KB, 113 LZ4F_blockLinked, 114 checksum, 115 }, 116 mCompressionLevel, 117 }; 118 size_t headerSize = LZ4F_compressBegin(mContext, mWriteBuffer.Elements(), 119 mWriteBufLen, &prefs); 120 if (LZ4F_isError(headerSize)) { 121 return Err(headerSize); 122 } 123 124 return Span{static_cast<const char*>(mWriteBuffer.Elements()), headerSize}; 125 } 126 127 Result<Span<const char>, size_t> 128 LZ4FrameCompressionContext::ContinueCompressing(Span<const char> aInput) { 129 LZ4F_compressOptions_t opts = {}; 130 opts.stableSrc = (uint32_t)mStableSrc; 131 size_t outputSize = 132 LZ4F_compressUpdate(mContext, mWriteBuffer.Elements(), mWriteBufLen, 133 aInput.Elements(), aInput.Length(), &opts); 134 if (LZ4F_isError(outputSize)) { 135 return Err(outputSize); 136 } 137 138 return Span{static_cast<const char*>(mWriteBuffer.Elements()), outputSize}; 139 } 140 141 Result<Span<const char>, size_t> LZ4FrameCompressionContext::EndCompressing() { 142 size_t outputSize = 143 LZ4F_compressEnd(mContext, mWriteBuffer.Elements(), mWriteBufLen, 144 /* options */ nullptr); 145 if (LZ4F_isError(outputSize)) { 146 return Err(outputSize); 147 } 148 149 return Span{static_cast<const char*>(mWriteBuffer.Elements()), outputSize}; 150 } 151 152 LZ4FrameDecompressionContext::LZ4FrameDecompressionContext(bool aStableDest) 153 : mContext(nullptr), mStableDest(aStableDest) { 154 LZ4F_errorCode_t err = 155 LZ4F_createDecompressionContext(&mContext, LZ4F_VERSION); 156 MOZ_RELEASE_ASSERT(!LZ4F_isError(err)); 157 } 158 159 LZ4FrameDecompressionContext::~LZ4FrameDecompressionContext() { 160 LZ4F_freeDecompressionContext(mContext); 161 } 162 163 Result<LZ4FrameDecompressionResult, size_t> 164 LZ4FrameDecompressionContext::Decompress(Span<char> aOutput, 165 Span<const char> aInput) { 166 LZ4F_decompressOptions_t opts = {}; 167 opts.stableDst = (uint32_t)mStableDest; 168 size_t outBytes = aOutput.Length(); 169 size_t inBytes = aInput.Length(); 170 size_t result = LZ4F_decompress(mContext, aOutput.Elements(), &outBytes, 171 aInput.Elements(), &inBytes, &opts); 172 if (LZ4F_isError(result)) { 173 return Err(result); 174 } 175 176 LZ4FrameDecompressionResult decompressionResult = {}; 177 decompressionResult.mFinished = !result; 178 decompressionResult.mSizeRead = inBytes; 179 decompressionResult.mSizeWritten = outBytes; 180 return decompressionResult; 181 }