|
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 |
|
12 NS_IMPL_ISUPPORTS(ArrayBufferInputStream, nsIArrayBufferInputStream, nsIInputStream); |
|
13 |
|
14 ArrayBufferInputStream::ArrayBufferInputStream() |
|
15 : mBuffer(nullptr) |
|
16 , mBufferLength(0) |
|
17 , mOffset(0) |
|
18 , mPos(0) |
|
19 , mClosed(false) |
|
20 { |
|
21 } |
|
22 |
|
23 NS_IMETHODIMP |
|
24 ArrayBufferInputStream::SetData(JS::Handle<JS::Value> aBuffer, |
|
25 uint32_t aByteOffset, |
|
26 uint32_t aLength, |
|
27 JSContext* aCx) |
|
28 { |
|
29 if (!aBuffer.isObject()) { |
|
30 return NS_ERROR_FAILURE; |
|
31 } |
|
32 JS::RootedObject arrayBuffer(aCx, &aBuffer.toObject()); |
|
33 if (!JS_IsArrayBufferObject(arrayBuffer)) { |
|
34 return NS_ERROR_FAILURE; |
|
35 } |
|
36 |
|
37 mArrayBuffer.construct(aCx, aBuffer); |
|
38 |
|
39 uint32_t buflen = JS_GetArrayBufferByteLength(arrayBuffer); |
|
40 mOffset = std::min(buflen, aByteOffset); |
|
41 mBufferLength = std::min(buflen - mOffset, aLength); |
|
42 mBuffer = JS_GetStableArrayBufferData(aCx, arrayBuffer); |
|
43 if (!mBuffer) { |
|
44 return NS_ERROR_FAILURE; |
|
45 } |
|
46 return NS_OK; |
|
47 } |
|
48 |
|
49 NS_IMETHODIMP |
|
50 ArrayBufferInputStream::Close() |
|
51 { |
|
52 mClosed = true; |
|
53 return NS_OK; |
|
54 } |
|
55 |
|
56 NS_IMETHODIMP |
|
57 ArrayBufferInputStream::Available(uint64_t* aCount) |
|
58 { |
|
59 if (mClosed) { |
|
60 return NS_BASE_STREAM_CLOSED; |
|
61 } |
|
62 *aCount = mBufferLength - mPos; |
|
63 return NS_OK; |
|
64 } |
|
65 |
|
66 NS_IMETHODIMP |
|
67 ArrayBufferInputStream::Read(char* aBuf, uint32_t aCount, uint32_t *aReadCount) |
|
68 { |
|
69 return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, aReadCount); |
|
70 } |
|
71 |
|
72 NS_IMETHODIMP |
|
73 ArrayBufferInputStream::ReadSegments(nsWriteSegmentFun writer, void *closure, |
|
74 uint32_t aCount, uint32_t *result) |
|
75 { |
|
76 NS_ASSERTION(result, "null ptr"); |
|
77 NS_ASSERTION(mBufferLength >= mPos, "bad stream state"); |
|
78 |
|
79 if (mClosed) { |
|
80 return NS_BASE_STREAM_CLOSED; |
|
81 } |
|
82 |
|
83 uint32_t remaining = mBufferLength - mPos; |
|
84 if (!mArrayBuffer.empty()) { |
|
85 JSObject* buf = &mArrayBuffer.ref().get().toObject(); |
|
86 uint32_t byteLength = JS_GetArrayBufferByteLength(buf); |
|
87 if (byteLength == 0 && remaining != 0) { |
|
88 mClosed = true; |
|
89 return NS_BASE_STREAM_CLOSED; |
|
90 } |
|
91 } else { |
|
92 MOZ_ASSERT(remaining == 0, "stream inited incorrectly"); |
|
93 } |
|
94 |
|
95 if (!remaining) { |
|
96 *result = 0; |
|
97 return NS_OK; |
|
98 } |
|
99 |
|
100 if (aCount > remaining) { |
|
101 aCount = remaining; |
|
102 } |
|
103 nsresult rv = writer(this, closure, (char*)(mBuffer + mOffset) + mPos, |
|
104 0, aCount, result); |
|
105 if (NS_SUCCEEDED(rv)) { |
|
106 NS_ASSERTION(*result <= aCount, |
|
107 "writer should not write more than we asked it to write"); |
|
108 mPos += *result; |
|
109 } |
|
110 |
|
111 return NS_OK; |
|
112 } |
|
113 |
|
114 NS_IMETHODIMP |
|
115 ArrayBufferInputStream::IsNonBlocking(bool *aNonBlocking) |
|
116 { |
|
117 *aNonBlocking = true; |
|
118 return NS_OK; |
|
119 } |