tor-browser

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

ArrayBufferInputStream.cpp (3913B)


      1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include <algorithm>
      7 #include "ArrayBufferInputStream.h"
      8 #include "nsStreamUtils.h"
      9 #include "js/ArrayBuffer.h"  // JS::{GetArrayBuffer{ByteLength,Data},IsArrayBufferObject}
     10 #include "js/RootingAPI.h"  // JS::{Handle,Rooted}
     11 #include "js/Value.h"       // JS::Value
     12 #include "mozilla/UniquePtrExtensions.h"
     13 #include "mozilla/dom/ScriptSettings.h"
     14 
     15 using mozilla::dom::RootingCx;
     16 
     17 NS_IMPL_ISUPPORTS(ArrayBufferInputStream, nsIArrayBufferInputStream,
     18                  nsIInputStream);
     19 
     20 NS_IMETHODIMP
     21 ArrayBufferInputStream::SetDataFromJS(JS::Handle<JS::Value> aBuffer,
     22                                      uint64_t aByteOffset, uint64_t aLength) {
     23  NS_ASSERT_OWNINGTHREAD(ArrayBufferInputStream);
     24 
     25  if (!aBuffer.isObject()) {
     26    return NS_ERROR_FAILURE;
     27  }
     28  JS::Rooted<JSObject*> arrayBuffer(RootingCx(), &aBuffer.toObject());
     29  if (!JS::IsArrayBufferObject(arrayBuffer)) {
     30    return NS_ERROR_FAILURE;
     31  }
     32 
     33  uint64_t buflen = JS::GetArrayBufferByteLength(arrayBuffer);
     34  uint64_t offset = std::min(buflen, aByteOffset);
     35  uint64_t bufferLength = std::min(buflen - offset, aLength);
     36 
     37  // Prevent truncation.
     38  if (bufferLength > UINT32_MAX) {
     39    return NS_ERROR_INVALID_ARG;
     40  }
     41 
     42  mArrayBuffer = mozilla::MakeUniqueFallible<uint8_t[]>(bufferLength);
     43  if (!mArrayBuffer) {
     44    return NS_ERROR_OUT_OF_MEMORY;
     45  }
     46 
     47  mBufferLength = bufferLength;
     48 
     49  JS::AutoCheckCannotGC nogc;
     50  bool isShared;
     51  uint8_t* src = JS::GetArrayBufferData(arrayBuffer, &isShared, nogc) + offset;
     52  memcpy(&mArrayBuffer[0], src, mBufferLength);
     53  return NS_OK;
     54 }
     55 
     56 nsresult ArrayBufferInputStream::SetData(mozilla::UniquePtr<uint8_t[]> aBytes,
     57                                         uint64_t aByteLen) {
     58  mArrayBuffer = std::move(aBytes);
     59  mBufferLength = aByteLen;
     60  return NS_OK;
     61 }
     62 
     63 NS_IMETHODIMP
     64 ArrayBufferInputStream::Close() {
     65  mClosed = true;
     66  return NS_OK;
     67 }
     68 
     69 NS_IMETHODIMP
     70 ArrayBufferInputStream::Available(uint64_t* aCount) {
     71  if (mClosed) {
     72    return NS_BASE_STREAM_CLOSED;
     73  }
     74  if (mArrayBuffer) {
     75    *aCount = mBufferLength ? mBufferLength - mPos : 0;
     76  } else {
     77    *aCount = 0;
     78  }
     79  return NS_OK;
     80 }
     81 
     82 NS_IMETHODIMP
     83 ArrayBufferInputStream::StreamStatus() {
     84  return mClosed ? NS_BASE_STREAM_CLOSED : NS_OK;
     85 }
     86 
     87 NS_IMETHODIMP
     88 ArrayBufferInputStream::Read(char* aBuf, uint32_t aCount,
     89                             uint32_t* aReadCount) {
     90  return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, aReadCount);
     91 }
     92 
     93 NS_IMETHODIMP
     94 ArrayBufferInputStream::ReadSegments(nsWriteSegmentFun writer, void* closure,
     95                                     uint32_t aCount, uint32_t* result) {
     96  NS_ASSERTION(result, "null ptr");
     97  NS_ASSERTION(mBufferLength >= mPos, "bad stream state");
     98 
     99  if (mClosed) {
    100    return NS_BASE_STREAM_CLOSED;
    101  }
    102 
    103  MOZ_ASSERT(mArrayBuffer || (mPos == mBufferLength),
    104             "stream inited incorrectly");
    105 
    106  *result = 0;
    107  while (mPos < mBufferLength) {
    108    uint32_t remaining = mBufferLength - mPos;
    109    MOZ_ASSERT(mArrayBuffer);
    110 
    111    uint32_t count = std::min(aCount, remaining);
    112    if (count == 0) {
    113      break;
    114    }
    115 
    116    uint32_t written;
    117    nsresult rv = writer(this, closure, (char*)&mArrayBuffer[0] + mPos, *result,
    118                         count, &written);
    119    if (NS_FAILED(rv)) {
    120      // InputStreams do not propagate errors to caller.
    121      return NS_OK;
    122    }
    123 
    124    NS_ASSERTION(written <= count,
    125                 "writer should not write more than we asked it to write");
    126    mPos += written;
    127    *result += written;
    128    aCount -= written;
    129  }
    130 
    131  return NS_OK;
    132 }
    133 
    134 NS_IMETHODIMP
    135 ArrayBufferInputStream::IsNonBlocking(bool* aNonBlocking) {
    136  *aNonBlocking = true;
    137  return NS_OK;
    138 }