michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include michael@0: #include "ArrayBufferInputStream.h" michael@0: #include "nsStreamUtils.h" michael@0: #include "jsapi.h" michael@0: #include "jsfriendapi.h" michael@0: michael@0: NS_IMPL_ISUPPORTS(ArrayBufferInputStream, nsIArrayBufferInputStream, nsIInputStream); michael@0: michael@0: ArrayBufferInputStream::ArrayBufferInputStream() michael@0: : mBuffer(nullptr) michael@0: , mBufferLength(0) michael@0: , mOffset(0) michael@0: , mPos(0) michael@0: , mClosed(false) michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ArrayBufferInputStream::SetData(JS::Handle aBuffer, michael@0: uint32_t aByteOffset, michael@0: uint32_t aLength, michael@0: JSContext* aCx) michael@0: { michael@0: if (!aBuffer.isObject()) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: JS::RootedObject arrayBuffer(aCx, &aBuffer.toObject()); michael@0: if (!JS_IsArrayBufferObject(arrayBuffer)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: mArrayBuffer.construct(aCx, aBuffer); michael@0: michael@0: uint32_t buflen = JS_GetArrayBufferByteLength(arrayBuffer); michael@0: mOffset = std::min(buflen, aByteOffset); michael@0: mBufferLength = std::min(buflen - mOffset, aLength); michael@0: mBuffer = JS_GetStableArrayBufferData(aCx, arrayBuffer); michael@0: if (!mBuffer) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ArrayBufferInputStream::Close() michael@0: { michael@0: mClosed = true; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ArrayBufferInputStream::Available(uint64_t* aCount) michael@0: { michael@0: if (mClosed) { michael@0: return NS_BASE_STREAM_CLOSED; michael@0: } michael@0: *aCount = mBufferLength - mPos; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ArrayBufferInputStream::Read(char* aBuf, uint32_t aCount, uint32_t *aReadCount) michael@0: { michael@0: return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, aReadCount); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ArrayBufferInputStream::ReadSegments(nsWriteSegmentFun writer, void *closure, michael@0: uint32_t aCount, uint32_t *result) michael@0: { michael@0: NS_ASSERTION(result, "null ptr"); michael@0: NS_ASSERTION(mBufferLength >= mPos, "bad stream state"); michael@0: michael@0: if (mClosed) { michael@0: return NS_BASE_STREAM_CLOSED; michael@0: } michael@0: michael@0: uint32_t remaining = mBufferLength - mPos; michael@0: if (!mArrayBuffer.empty()) { michael@0: JSObject* buf = &mArrayBuffer.ref().get().toObject(); michael@0: uint32_t byteLength = JS_GetArrayBufferByteLength(buf); michael@0: if (byteLength == 0 && remaining != 0) { michael@0: mClosed = true; michael@0: return NS_BASE_STREAM_CLOSED; michael@0: } michael@0: } else { michael@0: MOZ_ASSERT(remaining == 0, "stream inited incorrectly"); michael@0: } michael@0: michael@0: if (!remaining) { michael@0: *result = 0; michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (aCount > remaining) { michael@0: aCount = remaining; michael@0: } michael@0: nsresult rv = writer(this, closure, (char*)(mBuffer + mOffset) + mPos, michael@0: 0, aCount, result); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: NS_ASSERTION(*result <= aCount, michael@0: "writer should not write more than we asked it to write"); michael@0: mPos += *result; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ArrayBufferInputStream::IsNonBlocking(bool *aNonBlocking) michael@0: { michael@0: *aNonBlocking = true; michael@0: return NS_OK; michael@0: }