Line data Source code
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 "jsapi.h"
10 : #include "jsfriendapi.h"
11 : #include "mozilla/UniquePtrExtensions.h"
12 :
13 0 : NS_IMPL_ISUPPORTS(ArrayBufferInputStream, nsIArrayBufferInputStream, nsIInputStream);
14 :
15 0 : ArrayBufferInputStream::ArrayBufferInputStream()
16 : : mBufferLength(0)
17 : , mPos(0)
18 0 : , mClosed(false)
19 : {
20 0 : }
21 :
22 : NS_IMETHODIMP
23 0 : ArrayBufferInputStream::SetData(JS::Handle<JS::Value> aBuffer,
24 : uint32_t aByteOffset,
25 : uint32_t aLength,
26 : JSContext* aCx)
27 : {
28 0 : if (!aBuffer.isObject()) {
29 0 : return NS_ERROR_FAILURE;
30 : }
31 0 : JS::RootedObject arrayBuffer(aCx, &aBuffer.toObject());
32 0 : if (!JS_IsArrayBufferObject(arrayBuffer)) {
33 0 : return NS_ERROR_FAILURE;
34 : }
35 :
36 0 : uint32_t buflen = JS_GetArrayBufferByteLength(arrayBuffer);
37 0 : uint32_t offset = std::min(buflen, aByteOffset);
38 0 : uint32_t bufferLength = std::min(buflen - offset, aLength);
39 :
40 0 : mArrayBuffer = mozilla::MakeUniqueFallible<char[]>(bufferLength);
41 0 : if (!mArrayBuffer) {
42 0 : return NS_ERROR_OUT_OF_MEMORY;
43 : }
44 :
45 0 : mBufferLength = bufferLength;
46 :
47 0 : JS::AutoCheckCannotGC nogc;
48 : bool isShared;
49 0 : char* src = (char*) JS_GetArrayBufferData(arrayBuffer, &isShared, nogc) + offset;
50 0 : memcpy(&mArrayBuffer[0], src, mBufferLength);
51 0 : return NS_OK;
52 : }
53 :
54 : NS_IMETHODIMP
55 0 : ArrayBufferInputStream::Close()
56 : {
57 0 : mClosed = true;
58 0 : return NS_OK;
59 : }
60 :
61 : NS_IMETHODIMP
62 0 : ArrayBufferInputStream::Available(uint64_t* aCount)
63 : {
64 0 : if (mClosed) {
65 0 : return NS_BASE_STREAM_CLOSED;
66 : }
67 0 : if (mArrayBuffer) {
68 0 : *aCount = mBufferLength ? mBufferLength - mPos : 0;
69 : } else {
70 0 : *aCount = 0;
71 : }
72 0 : return NS_OK;
73 : }
74 :
75 : NS_IMETHODIMP
76 0 : ArrayBufferInputStream::Read(char* aBuf, uint32_t aCount, uint32_t *aReadCount)
77 : {
78 0 : return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, aReadCount);
79 : }
80 :
81 : NS_IMETHODIMP
82 0 : ArrayBufferInputStream::ReadSegments(nsWriteSegmentFun writer, void *closure,
83 : uint32_t aCount, uint32_t *result)
84 : {
85 0 : NS_ASSERTION(result, "null ptr");
86 0 : NS_ASSERTION(mBufferLength >= mPos, "bad stream state");
87 :
88 0 : if (mClosed) {
89 0 : return NS_BASE_STREAM_CLOSED;
90 : }
91 :
92 0 : MOZ_ASSERT(mArrayBuffer || (mPos == mBufferLength), "stream inited incorrectly");
93 :
94 0 : *result = 0;
95 0 : while (mPos < mBufferLength) {
96 0 : uint32_t remaining = mBufferLength - mPos;
97 0 : MOZ_ASSERT(mArrayBuffer);
98 :
99 0 : uint32_t count = std::min(aCount, remaining);
100 0 : if (count == 0) {
101 0 : break;
102 : }
103 :
104 : uint32_t written;
105 0 : nsresult rv = writer(this, closure, &mArrayBuffer[0] + mPos, *result, count, &written);
106 0 : if (NS_FAILED(rv)) {
107 : // InputStreams do not propagate errors to caller.
108 0 : return NS_OK;
109 : }
110 :
111 0 : NS_ASSERTION(written <= count,
112 : "writer should not write more than we asked it to write");
113 0 : mPos += written;
114 0 : *result += written;
115 0 : aCount -= written;
116 : }
117 :
118 0 : return NS_OK;
119 : }
120 :
121 : NS_IMETHODIMP
122 0 : ArrayBufferInputStream::IsNonBlocking(bool *aNonBlocking)
123 : {
124 0 : *aNonBlocking = true;
125 0 : return NS_OK;
126 : }
|