tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }