tor-browser

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

FormatZstd.cpp (3925B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
      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 "FormatZstd.h"
      8 
      9 #include "BaseAlgorithms.h"
     10 #include "mozilla/dom/TransformStreamDefaultController.h"
     11 #include "zstd/zstd.h"
     12 
     13 namespace mozilla::dom::compression {
     14 
     15 NS_IMPL_CYCLE_COLLECTION_INHERITED(ZstdDecompressionStreamAlgorithms,
     16                                   TransformerAlgorithmsBase)
     17 NS_IMPL_ADDREF_INHERITED(ZstdDecompressionStreamAlgorithms,
     18                         TransformerAlgorithmsBase)
     19 NS_IMPL_RELEASE_INHERITED(ZstdDecompressionStreamAlgorithms,
     20                          TransformerAlgorithmsBase)
     21 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ZstdDecompressionStreamAlgorithms)
     22 NS_INTERFACE_MAP_END_INHERITING(TransformerAlgorithmsBase)
     23 
     24 Result<already_AddRefed<ZstdDecompressionStreamAlgorithms>, nsresult>
     25 ZstdDecompressionStreamAlgorithms::Create() {
     26  RefPtr<ZstdDecompressionStreamAlgorithms> alg =
     27      new ZstdDecompressionStreamAlgorithms();
     28  MOZ_TRY(alg->Init());
     29  return alg.forget();
     30 }
     31 
     32 [[nodiscard]] nsresult ZstdDecompressionStreamAlgorithms::Init() {
     33  mDStream = ZSTD_createDStream();
     34  if (!mDStream) {
     35    return NS_ERROR_OUT_OF_MEMORY;
     36  }
     37 
     38  // Refuse any frame requiring larger than (1 << WINDOW_LOG_MAX) window size.
     39  // Note: 1 << 23 == 8 * 1024 * 1024
     40  static const uint8_t WINDOW_LOG_MAX = 23;
     41  ZSTD_DCtx_setParameter(mDStream, ZSTD_d_windowLogMax, WINDOW_LOG_MAX);
     42 
     43  return NS_OK;
     44 }
     45 
     46 // Shared by:
     47 // https://wicg.github.io/compression/#decompress-and-enqueue-a-chunk
     48 // https://wicg.github.io/compression/#decompress-flush-and-enqueue
     49 // All data errors throw TypeError by step 2: If this results in an error,
     50 // then throw a TypeError.
     51 bool ZstdDecompressionStreamAlgorithms::Decompress(
     52    JSContext* aCx, Span<const uint8_t> aInput,
     53    JS::MutableHandleVector<JSObject*> aOutput, Flush aFlush,
     54    ErrorResult& aRv) {
     55  ZSTD_inBuffer inBuffer = {/* src  */ const_cast<uint8_t*>(aInput.Elements()),
     56                            /* size */ aInput.Length(),
     57                            /* pos  */ 0};
     58 
     59  while (inBuffer.pos < inBuffer.size && !mObservedStreamEnd) {
     60    UniquePtr<uint8_t[], JS::FreePolicy> buffer(
     61        static_cast<uint8_t*>(JS_malloc(aCx, kBufferSize)));
     62    if (!buffer) {
     63      aRv.ThrowTypeError("Out of memory");
     64      return false;
     65    }
     66 
     67    ZSTD_outBuffer outBuffer = {/* dst  */ buffer.get(),
     68                                /* size */ kBufferSize,
     69                                /* pos  */ 0};
     70 
     71    size_t rv = ZSTD_decompressStream(mDStream, &outBuffer, &inBuffer);
     72    if (ZSTD_isError(rv)) {
     73      aRv.ThrowTypeError("zstd decompression error: "_ns +
     74                         nsDependentCString(ZSTD_getErrorName(rv)));
     75      return false;
     76    }
     77 
     78    if (rv == 0) {
     79      mObservedStreamEnd = true;
     80    }
     81 
     82    // Step 3: If buffer is empty, return.
     83    // (We'll implicitly return when the array is empty.)
     84 
     85    // Step 4: Split buffer into one or more non-empty pieces and convert them
     86    // into Uint8Arrays.
     87    // (The buffer is 'split' by having a fixed sized buffer above.)
     88 
     89    size_t written = outBuffer.pos;
     90    if (written > 0) {
     91      JS::Rooted<JSObject*> view(aCx, nsJSUtils::MoveBufferAsUint8Array(
     92                                          aCx, written, std::move(buffer)));
     93      if (!view || !aOutput.append(view)) {
     94        JS_ClearPendingException(aCx);
     95        aRv.ThrowTypeError("Out of memory");
     96        return false;
     97      }
     98    }
     99  }
    100 
    101  return inBuffer.pos == inBuffer.size;
    102 }
    103 
    104 ZstdDecompressionStreamAlgorithms::~ZstdDecompressionStreamAlgorithms() {
    105  if (mDStream) {
    106    ZSTD_freeDStream(mDStream);
    107    mDStream = nullptr;
    108  }
    109 }
    110 
    111 }  // namespace mozilla::dom::compression