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_ */