NS_IMETHODIMP ArrayBufferInputStream::SetData(JS::Handle<JS::Value> aBuffer, uint32_t aByteOffset, uint32_t aLength, JSContext* aCx) { if (!aBuffer.isObject()) { return NS_ERROR_FAILURE; } JS::RootedObject arrayBuffer(aCx, &aBuffer.toObject()); if (!JS_IsArrayBufferObject(arrayBuffer)) { return NS_ERROR_FAILURE; } mArrayBuffer.construct(aCx, aBuffer); uint32_t buflen = JS_GetArrayBufferByteLength(arrayBuffer); mOffset = std::min(buflen, aByteOffset); mBufferLength = std::min(buflen - mOffset, aLength); mBuffer = JS_GetStableArrayBufferData(aCx, arrayBuffer); if (!mBuffer) { return NS_ERROR_FAILURE; } return NS_OK; }
already_AddRefed<ThreadSharedFloatArrayBufferList> AudioBuffer::StealJSArrayDataIntoSharedChannels(JSContext* aJSContext) { // "1. If any of the AudioBuffer's ArrayBuffer have been detached, abort // these steps, and return a zero-length channel data buffers to the // invoker." for (uint32_t i = 0; i < mJSChannels.Length(); ++i) { JSObject* channelArray = mJSChannels[i]; if (!channelArray || mLength != JS_GetTypedArrayLength(channelArray)) { // Either empty buffer or one of the arrays' buffers was detached. return nullptr; } } // "2. Detach all ArrayBuffers for arrays previously returned by // getChannelData on this AudioBuffer." // "3. Retain the underlying data buffers from those ArrayBuffers and return // references to them to the invoker." RefPtr<ThreadSharedFloatArrayBufferList> result = new ThreadSharedFloatArrayBufferList(mJSChannels.Length()); for (uint32_t i = 0; i < mJSChannels.Length(); ++i) { if (mJSChannels[i]) { JS::ExposeObjectToActiveJS(mJSChannels[i]); } JS::Rooted<JSObject*> arrayBufferView(aJSContext, mJSChannels[i]); bool isSharedMemory; JS::Rooted<JSObject*> arrayBuffer(aJSContext, JS_GetArrayBufferViewBuffer(aJSContext, arrayBufferView, &isSharedMemory)); if (arrayBuffer) { JS::ExposeObjectToActiveJS(arrayBuffer); } // The channel data arrays should all have originated in // RestoreJSChannelData, where they are created unshared. MOZ_ASSERT(!isSharedMemory); auto stolenData = arrayBuffer ? static_cast<float*>(JS_StealArrayBufferContents(aJSContext, arrayBuffer)) : nullptr; if (stolenData) { result->SetData(i, stolenData, js_free, stolenData); } else { NS_ASSERTION(i == 0, "some channels lost when contents not acquired"); return nullptr; } } for (uint32_t i = 0; i < mJSChannels.Length(); ++i) { mJSChannels[i] = nullptr; } return result.forget(); }
nsresult ReadHelper::GetSuccessResult(JSContext* aCx, JS::MutableHandle<JS::Value> aVal) { JS::Rooted<JSObject*> arrayBuffer(aCx); nsresult rv = nsContentUtils::CreateArrayBuffer(aCx, mStream->Data(), arrayBuffer.address()); NS_ENSURE_SUCCESS(rv, rv); aVal.setObject(*arrayBuffer); return NS_OK; }
nsresult GetResult(JSContext* aCx, const nsCString* aString, JS::MutableHandle<JS::Value> aResult) { const nsCString& data = *aString; nsresult rv; if (!mFileRequest->HasEncoding()) { JS::Rooted<JSObject*> arrayBuffer(aCx); rv = nsContentUtils::CreateArrayBuffer(aCx, data, arrayBuffer.address()); if (NS_WARN_IF(NS_FAILED(rv))) { return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR; } aResult.setObject(*arrayBuffer); return NS_OK; } nsAutoCString encoding; // The BOM sniffing is baked into the "decode" part of the Encoding // Standard, which the File API references. if (!nsContentUtils::CheckForBOM( reinterpret_cast<const unsigned char *>(data.get()), data.Length(), encoding)) { // BOM sniffing failed. Try the API argument. if (!EncodingUtils::FindEncodingForLabel(mFileRequest->GetEncoding(), encoding)) { // API argument failed. Since we are dealing with a file system file, // we don't have a meaningful type attribute for the blob available, // so proceeding to the next step, which is defaulting to UTF-8. encoding.AssignLiteral("UTF-8"); } } nsString tmpString; rv = nsContentUtils::ConvertStringFromEncoding(encoding, data, tmpString); if (NS_WARN_IF(NS_FAILED(rv))) { return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR; } if (NS_WARN_IF(!xpc::StringToJsval(aCx, tmpString, aResult))) { return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR; } return NS_OK; }
void WebSocket::send(ArrayBufferView* arrayBufferView, ExceptionState& exceptionState) { WTF_LOG(Network, "WebSocket %p send() Sending ArrayBufferView %p", this, arrayBufferView); ASSERT(arrayBufferView); if (m_state == CONNECTING) { setInvalidStateErrorForSendMethod(exceptionState); return; } if (m_state == CLOSING || m_state == CLOSED) { updateBufferedAmountAfterClose(arrayBufferView->byteLength()); return; } ASSERT(m_channel); RefPtr<ArrayBuffer> arrayBuffer(arrayBufferView->buffer()); handleSendResult(m_channel->send(*arrayBuffer, arrayBufferView->byteOffset(), arrayBufferView->byteLength()), exceptionState); }
void WebSocket::send(ArrayBufferView* arrayBufferView, ExceptionCode& ec) { LOG(Network, "WebSocket %p send() Sending ArrayBufferView %p", this, arrayBufferView); ASSERT(arrayBufferView); if (m_state == CONNECTING) { ec = INVALID_STATE_ERR; return; } if (m_state == CLOSING || m_state == CLOSED) { unsigned payloadSize = arrayBufferView->byteLength(); m_bufferedAmountAfterClose = saturateAdd(m_bufferedAmountAfterClose, payloadSize); m_bufferedAmountAfterClose = saturateAdd(m_bufferedAmountAfterClose, getFramingOverhead(payloadSize)); return; } ASSERT(m_channel); RefPtr<ArrayBuffer> arrayBuffer(arrayBufferView->buffer()); m_channel->send(*arrayBuffer, arrayBufferView->byteOffset(), arrayBufferView->byteLength()); }
static already_AddRefed<ThreadSharedFloatArrayBufferList> StealJSArrayDataIntoThreadSharedFloatArrayBufferList(JSContext* aJSContext, const nsTArray<JSObject*>& aJSArrays) { nsRefPtr<ThreadSharedFloatArrayBufferList> result = new ThreadSharedFloatArrayBufferList(aJSArrays.Length()); for (uint32_t i = 0; i < aJSArrays.Length(); ++i) { JS::RootedObject arrayBuffer(aJSContext, JS_GetArrayBufferViewBuffer(aJSArrays[i])); void* dataToFree = nullptr; uint8_t* stolenData = nullptr; if (arrayBuffer && JS_StealArrayBufferContents(aJSContext, arrayBuffer, &dataToFree, &stolenData)) { result->SetData(i, dataToFree, reinterpret_cast<float*>(stolenData)); } else { return nullptr; } } return result.forget(); }
bool AudioBuffer::SetChannelDataFromArrayBufferContents(JSContext* aJSContext, uint32_t aChannel, void* aContents) { if (!RestoreJSChannelData(aJSContext)) { return false; } MOZ_ASSERT(aChannel < NumberOfChannels()); JS::RootedObject arrayBuffer(aJSContext, JS_NewArrayBufferWithContents(aJSContext, aContents)); if (!arrayBuffer) { return false; } mJSChannels[aChannel] = JS_NewFloat32ArrayWithBuffer(aJSContext, arrayBuffer, 0, -1); if (!mJSChannels[aChannel]) { return false; } MOZ_ASSERT(mLength == JS_GetTypedArrayLength(mJSChannels[aChannel])); return true; }
NS_IMETHODIMP ArrayBufferInputStream::SetData(const JS::Value& aBuffer, uint32_t aByteOffset, uint32_t aLength, JSContext* aCx) { if (!aBuffer.isObject()) { return NS_ERROR_FAILURE; } JS::RootedObject arrayBuffer(aCx, &aBuffer.toObject()); if (!JS_IsArrayBufferObject(arrayBuffer)) { return NS_ERROR_FAILURE; } mRt = JS_GetRuntime(aCx); mArrayBuffer = aBuffer; JS_AddNamedValueRootRT(mRt, &mArrayBuffer, "mArrayBuffer"); uint32_t buflen = JS_GetArrayBufferByteLength(arrayBuffer); mOffset = std::min(buflen, aByteOffset); mBufferLength = std::min(buflen - mOffset, aLength); mBuffer = JS_GetArrayBufferData(arrayBuffer); return NS_OK; }
void RTCDataChannel::send(PassRefPtr<ArrayBufferView> data, ExceptionCode& ec) { RefPtr<ArrayBuffer> arrayBuffer(data->buffer()); send(arrayBuffer.release(), ec); }
already_AddRefed<Promise> Request::ConsumeBody(ConsumeType aType, ErrorResult& aRv) { nsRefPtr<Promise> promise = Promise::Create(mOwner, aRv); if (aRv.Failed()) { return nullptr; } if (BodyUsed()) { aRv.ThrowTypeError(MSG_REQUEST_BODY_CONSUMED_ERROR); return nullptr; } SetBodyUsed(); // While the spec says to do this asynchronously, all the body constructors // right now only accept bodies whose streams are backed by an in-memory // buffer that can be read without blocking. So I think this is fine. nsCOMPtr<nsIInputStream> stream; mRequest->GetBody(getter_AddRefs(stream)); if (!stream) { aRv = NS_NewByteInputStream(getter_AddRefs(stream), "", 0, NS_ASSIGNMENT_COPY); if (aRv.Failed()) { return nullptr; } } AutoJSAPI api; api.Init(mOwner); JSContext* cx = api.cx(); // We can make this assertion because for now we only support memory backed // structures for the body argument for a Request. MOZ_ASSERT(NS_InputStreamIsBuffered(stream)); nsCString buffer; uint64_t len; aRv = stream->Available(&len); if (aRv.Failed()) { return nullptr; } aRv = NS_ReadInputStreamToString(stream, buffer, len); if (aRv.Failed()) { return nullptr; } buffer.SetLength(len); switch (aType) { case CONSUME_ARRAYBUFFER: { JS::Rooted<JSObject*> arrayBuffer(cx); arrayBuffer = ArrayBuffer::Create(cx, buffer.Length(), reinterpret_cast<const uint8_t*>(buffer.get())); JS::Rooted<JS::Value> val(cx); val.setObjectOrNull(arrayBuffer); promise->MaybeResolve(cx, val); return promise.forget(); } case CONSUME_BLOB: { // XXXnsm it is actually possible to avoid these duplicate allocations // for the Blob case by having the Blob adopt the stream's memory // directly, but I've not added a special case for now. // // This is similar to nsContentUtils::CreateBlobBuffer, but also deals // with worker wrapping. uint32_t blobLen = buffer.Length(); void* blobData = moz_malloc(blobLen); nsRefPtr<File> blob; if (blobData) { memcpy(blobData, buffer.BeginReading(), blobLen); blob = File::CreateMemoryFile(GetParentObject(), blobData, blobLen, NS_ConvertUTF8toUTF16(mMimeType)); } else { aRv = NS_ERROR_OUT_OF_MEMORY; return nullptr; } promise->MaybeResolve(blob); return promise.forget(); } case CONSUME_JSON: { nsString decoded; aRv = DecodeUTF8(buffer, decoded); if (aRv.Failed()) { return nullptr; } JS::Rooted<JS::Value> json(cx); if (!JS_ParseJSON(cx, decoded.get(), decoded.Length(), &json)) { JS::Rooted<JS::Value> exn(cx); if (JS_GetPendingException(cx, &exn)) { JS_ClearPendingException(cx); promise->MaybeReject(cx, exn); } } promise->MaybeResolve(cx, json); return promise.forget(); } case CONSUME_TEXT: { nsString decoded; aRv = DecodeUTF8(buffer, decoded); if (aRv.Failed()) { return nullptr; } promise->MaybeResolve(decoded); return promise.forget(); } } NS_NOTREACHED("Unexpected consume body type"); // Silence warnings. return nullptr; }