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 }