mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 02:09:05 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			182 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			182 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;
 | 
						|
}
 |