Source code

Revision control

Other Tools

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