tor-browser

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

Compression.h (7701B)


      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 /* Various simple compression/decompression functions. */
      8 
      9 #ifndef mozilla_Compression_h_
     10 #define mozilla_Compression_h_
     11 
     12 #include "mozilla/Assertions.h"
     13 #include "mozilla/ResultVariant.h"
     14 #include "mozilla/Span.h"
     15 
     16 struct LZ4F_cctx_s;  // compression context
     17 struct LZ4F_dctx_s;  // decompression context
     18 
     19 namespace mozilla {
     20 namespace Compression {
     21 
     22 /**
     23 * LZ4 is a very fast byte-wise compression algorithm.
     24 *
     25 * Compared to Google's Snappy it is faster to compress and decompress and
     26 * generally produces output of about the same size.
     27 *
     28 * Compared to zlib it compresses at about 10x the speed, decompresses at about
     29 * 4x the speed and produces output of about 1.5x the size.
     30 */
     31 
     32 class LZ4 {
     33 public:
     34  /**
     35   * Compresses |aInputSize| bytes from |aSource| into |aDest|. Destination
     36   * buffer must be already allocated, and must be sized to handle worst cases
     37   * situations (input data not compressible). Worst case size evaluation is
     38   * provided by function maxCompressedSize()
     39   *
     40   * @param aInputSize is the input size. Max supported value is ~1.9GB
     41   * @return the number of bytes written in buffer |aDest|
     42   */
     43  static size_t compress(const char* aSource, size_t aInputSize, char* aDest);
     44 
     45  /**
     46   * Compress |aInputSize| bytes from |aSource| into an output buffer
     47   * |aDest| of maximum size |aMaxOutputSize|.  If it cannot achieve it,
     48   * compression will stop, and result of the function will be zero,
     49   * |aDest| will still be written to, but since the number of input
     50   * bytes consumed is not returned the result is not usable.
     51   *
     52   * This function never writes outside of provided output buffer.
     53   *
     54   * @param aInputSize is the input size. Max supported value is ~1.9GB
     55   * @param aMaxOutputSize is the size of the destination buffer (which must
     56   *   be already allocated)
     57   * @return the number of bytes written in buffer |aDest| or 0 if the
     58   *   compression fails
     59   */
     60  static size_t compressLimitedOutput(const char* aSource, size_t aInputSize,
     61                                      char* aDest, size_t aMaxOutputSize);
     62 
     63  /**
     64   * If the source stream is malformed, the function will stop decoding
     65   * and return false.
     66   *
     67   * This function never writes beyond aDest + aMaxOutputSize, and is
     68   * therefore protected against malicious data packets.
     69   *
     70   * Note: Destination buffer must be already allocated.  This version is
     71   *       slightly slower than the decompress without the aMaxOutputSize.
     72   *
     73   * @param aInputSize is the length of the input compressed data
     74   * @param aMaxOutputSize is the size of the destination buffer (which must be
     75   *   already allocated)
     76   * @param aOutputSize the actual number of bytes decoded in the destination
     77   *   buffer (necessarily <= aMaxOutputSize)
     78   * @return true on success, false on failure
     79   */
     80  [[nodiscard]] static bool decompress(const char* aSource, size_t aInputSize,
     81                                       char* aDest, size_t aMaxOutputSize,
     82                                       size_t* aOutputSize);
     83 
     84  /**
     85   * If the source stream is malformed, the function will stop decoding
     86   * and return false.
     87   *
     88   * This function never writes beyond aDest + aMaxOutputSize, and is
     89   * therefore protected against malicious data packets. It also ignores
     90   * unconsumed input upon reaching aMaxOutputSize and can therefore be used
     91   * for partial decompression.
     92   *
     93   * Note: Destination buffer must be already allocated.  This version is
     94   *       slightly slower than the decompress without the aMaxOutputSize.
     95   *
     96   * @param aInputSize is the length of the input compressed data
     97   * @param aMaxOutputSize is the size of the destination buffer (which must be
     98   *   already allocated)
     99   * @param aOutputSize the actual number of bytes decoded in the destination
    100   *   buffer (necessarily <= aMaxOutputSize)
    101   * @return true on success, false on failure
    102   */
    103  [[nodiscard]] static bool decompressPartial(const char* aSource,
    104                                              size_t aInputSize, char* aDest,
    105                                              size_t aMaxOutputSize,
    106                                              size_t* aOutputSize);
    107 
    108  /*
    109   * Provides the maximum size that LZ4 may output in a "worst case"
    110   * scenario (input data not compressible) primarily useful for memory
    111   * allocation of output buffer.
    112   * note : this function is limited by "int" range (2^31-1)
    113   *
    114   * @param aInputSize is the input size. Max supported value is ~1.9GB
    115   * @return maximum output size in a "worst case" scenario
    116   */
    117  static inline size_t maxCompressedSize(size_t aInputSize) {
    118    size_t max = (aInputSize + (aInputSize / 255) + 16);
    119    MOZ_RELEASE_ASSERT(max > aInputSize);
    120    return max;
    121  }
    122 };
    123 
    124 /**
    125 * Context for LZ4 Frame-based streaming compression. Use this if you
    126 * want to incrementally compress something or if you want to compress
    127 * something such that another application can read it.
    128 */
    129 class LZ4FrameCompressionContext final {
    130 public:
    131  LZ4FrameCompressionContext(int aCompressionLevel, size_t aMaxSrcSize,
    132                             bool aChecksum, bool aStableSrc = false);
    133 
    134  ~LZ4FrameCompressionContext();
    135 
    136  size_t GetRequiredWriteBufferLength() { return mWriteBufLen; }
    137 
    138  /**
    139   * Begin streaming frame-based compression.
    140   *
    141   * @return a Result with a Span containing the frame header, or an lz4 error
    142   * code (size_t).
    143   */
    144  Result<Span<const char>, size_t> BeginCompressing(Span<char> aWriteBuffer);
    145 
    146  /**
    147   * Continue streaming frame-based compression with the provided input.
    148   *
    149   * @param aInput input buffer to be compressed.
    150   * @return a Result with a Span containing compressed output, or an lz4 error
    151   * code (size_t).
    152   */
    153  Result<Span<const char>, size_t> ContinueCompressing(Span<const char> aInput);
    154 
    155  /**
    156   * Finalize streaming frame-based compression with the provided input.
    157   *
    158   * @return a Result with a Span containing compressed output and the frame
    159   * footer, or an lz4 error code (size_t).
    160   */
    161  Result<Span<const char>, size_t> EndCompressing();
    162 
    163 private:
    164  LZ4F_cctx_s* mContext;
    165  int mCompressionLevel;
    166  bool mGenerateChecksum;
    167  bool mStableSrc;
    168  size_t mMaxSrcSize;
    169  size_t mWriteBufLen;
    170  Span<char> mWriteBuffer;
    171 };
    172 
    173 struct LZ4FrameDecompressionResult {
    174  size_t mSizeRead;
    175  size_t mSizeWritten;
    176  bool mFinished;
    177 };
    178 
    179 /**
    180 * Context for LZ4 Frame-based streaming decompression. Use this if you
    181 * want to decompress something compressed by LZ4FrameCompressionContext
    182 * or by another application.
    183 */
    184 class LZ4FrameDecompressionContext final {
    185 public:
    186  explicit LZ4FrameDecompressionContext(bool aStableDest = false);
    187  ~LZ4FrameDecompressionContext();
    188 
    189  /**
    190   * Decompress a buffer/part of a buffer compressed with
    191   * LZ4FrameCompressionContext or another application.
    192   *
    193   * @param aOutput output buffer to be write results into.
    194   * @param aInput input buffer to be decompressed.
    195   * @return a Result with information on bytes read/written and whether we
    196   * completely decompressed the input into the output, or an lz4 error code
    197   * (size_t).
    198   */
    199  Result<LZ4FrameDecompressionResult, size_t> Decompress(
    200      Span<char> aOutput, Span<const char> aInput);
    201 
    202 private:
    203  LZ4F_dctx_s* mContext;
    204  bool mStableDest;
    205 };
    206 
    207 } /* namespace Compression */
    208 } /* namespace mozilla */
    209 
    210 #endif /* mozilla_Compression_h_ */