1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/TextDecoderStream.h"
9 #include "nsContentUtils.h"
10 #include "nsIGlobalObject.h"
11 #include "mozilla/Encoding.h"
12 #include "mozilla/dom/Promise.h"
13 #include "mozilla/dom/TextDecoderStreamBinding.h"
14 #include "mozilla/dom/TransformerCallbackHelpers.h"
15 #include "mozilla/dom/TransformStream.h"
16 #include "mozilla/dom/UnionTypes.h"
18 namespace mozilla::dom
{
20 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TextDecoderStream
, mGlobal
, mStream
)
21 NS_IMPL_CYCLE_COLLECTING_ADDREF(TextDecoderStream
)
22 NS_IMPL_CYCLE_COLLECTING_RELEASE(TextDecoderStream
)
23 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TextDecoderStream
)
24 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
25 NS_INTERFACE_MAP_ENTRY(nsISupports
)
28 TextDecoderStream::TextDecoderStream(nsISupports
* aGlobal
,
29 const Encoding
& aEncoding
, bool aFatal
,
30 bool aIgnoreBOM
, TransformStream
& aStream
)
31 : mGlobal(aGlobal
), mStream(&aStream
) {
33 mIgnoreBOM
= aIgnoreBOM
;
34 aEncoding
.Name(mEncoding
);
36 mDecoder
= aEncoding
.NewDecoderWithoutBOMHandling();
38 mDecoder
= aEncoding
.NewDecoderWithBOMRemoval();
42 TextDecoderStream::~TextDecoderStream() = default;
44 JSObject
* TextDecoderStream::WrapObject(JSContext
* aCx
,
45 JS::Handle
<JSObject
*> aGivenProto
) {
46 return TextDecoderStream_Binding::Wrap(aCx
, this, aGivenProto
);
49 class TextDecoderStreamAlgorithms
: public TransformerAlgorithmsWrapper
{
50 NS_DECL_ISUPPORTS_INHERITED
51 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(TextDecoderStreamAlgorithms
,
52 TransformerAlgorithmsBase
)
54 void SetDecoderStream(TextDecoderStream
& aStream
) {
55 mDecoderStream
= &aStream
;
58 // The common part of decode-and-enqueue and flush-and-enqueue.
59 // Note that the most of the decoding algorithm is implemented in
60 // mozilla::Decoder, and this is mainly about calling it properly.
61 // https://encoding.spec.whatwg.org/#decode-and-enqueue-a-chunk
62 // TODO: This does not allow shared array buffers, just as the non-stream
63 // TextDecoder/Encoder don't. (Bug 1561594)
64 MOZ_CAN_RUN_SCRIPT
void DecodeBufferSourceAndEnqueue(
65 JSContext
* aCx
, OwningArrayBufferViewOrArrayBuffer
* aInput
, bool aFlush
,
66 TransformStreamDefaultController
& aController
, ErrorResult
& aRv
) {
67 nsString outDecodedString
;
69 ProcessTypedArrays(*aInput
, [&](const Span
<const uint8_t>& aData
,
70 JS::AutoCheckCannotGC
&&) {
71 mDecoderStream
->DecodeNative(aData
, !aFlush
, outDecodedString
, aRv
);
74 mDecoderStream
->DecodeNative(Span
<const uint8_t>(), !aFlush
,
75 outDecodedString
, aRv
);
82 if (outDecodedString
.Length()) {
83 // Step 4.2. If outputChunk is non-empty, then enqueue outputChunk in
84 // decoder’s transform.
85 JS::Rooted
<JS::Value
> outputChunk(aCx
);
86 if (!ToJSValue(aCx
, outDecodedString
, &outputChunk
)) {
87 JS_ClearPendingException(aCx
);
88 aRv
.Throw(NS_ERROR_UNEXPECTED
);
91 aController
.Enqueue(aCx
, outputChunk
, aRv
);
95 // https://encoding.spec.whatwg.org/#dom-textdecoderstream
96 MOZ_CAN_RUN_SCRIPT
void TransformCallbackImpl(
97 JS::Handle
<JS::Value
> aChunk
,
98 TransformStreamDefaultController
& aController
,
99 ErrorResult
& aRv
) override
{
100 // Step 7. Let transformAlgorithm be an algorithm which takes a chunk
101 // argument and runs the decode and enqueue a chunk algorithm with this and
104 // https://encoding.spec.whatwg.org/#decode-and-enqueue-a-chunk
107 if (!jsapi
.Init(aController
.GetParentObject())) {
108 aRv
.ThrowUnknownError("Internal error");
111 JSContext
* cx
= jsapi
.cx();
113 // Step 1. Let bufferSource be the result of converting chunk to an
114 // [AllowShared] BufferSource.
115 RootedUnion
<OwningArrayBufferViewOrArrayBuffer
> bufferSource(cx
);
116 if (!bufferSource
.Init(cx
, aChunk
)) {
117 aRv
.MightThrowJSException();
118 aRv
.StealExceptionFromJSContext(cx
);
122 DecodeBufferSourceAndEnqueue(cx
, &bufferSource
, false, aController
, aRv
);
125 // https://encoding.spec.whatwg.org/#dom-textdecoderstream
126 MOZ_CAN_RUN_SCRIPT
void FlushCallbackImpl(
127 TransformStreamDefaultController
& aController
,
128 ErrorResult
& aRv
) override
{
129 // Step 8. Let flushAlgorithm be an algorithm which takes no arguments and
130 // runs the flush and enqueue algorithm with this.
133 if (!jsapi
.Init(aController
.GetParentObject())) {
134 aRv
.ThrowUnknownError("Internal error");
137 JSContext
* cx
= jsapi
.cx();
139 // https://encoding.spec.whatwg.org/#flush-and-enqueue
140 // (The flush and enqueue algorithm is basically a subset of decode and
141 // enqueue one, so let's reuse it)
142 DecodeBufferSourceAndEnqueue(cx
, nullptr, true, aController
, aRv
);
146 ~TextDecoderStreamAlgorithms() override
= default;
148 RefPtr
<TextDecoderStream
> mDecoderStream
;
151 NS_IMPL_CYCLE_COLLECTION_INHERITED(TextDecoderStreamAlgorithms
,
152 TransformerAlgorithmsBase
, mDecoderStream
)
153 NS_IMPL_ADDREF_INHERITED(TextDecoderStreamAlgorithms
, TransformerAlgorithmsBase
)
154 NS_IMPL_RELEASE_INHERITED(TextDecoderStreamAlgorithms
,
155 TransformerAlgorithmsBase
)
156 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TextDecoderStreamAlgorithms
)
157 NS_INTERFACE_MAP_END_INHERITING(TransformerAlgorithmsBase
)
159 // https://encoding.spec.whatwg.org/#dom-textdecoderstream
160 already_AddRefed
<TextDecoderStream
> TextDecoderStream::Constructor(
161 const GlobalObject
& aGlobal
, const nsAString
& aLabel
,
162 const TextDecoderOptions
& aOptions
, ErrorResult
& aRv
) {
163 // Step 1. Let encoding be the result of getting an encoding from label.
164 const Encoding
* encoding
= Encoding::ForLabelNoReplacement(aLabel
);
166 // Step 2. If encoding is failure or replacement, then throw a RangeError
168 NS_ConvertUTF16toUTF8
label(aLabel
);
169 label
.Trim(" \t\n\f\r");
170 aRv
.ThrowRangeError
<MSG_ENCODING_NOT_SUPPORTED
>(label
);
174 // Step 3-6. (Done in the constructor)
177 auto algorithms
= MakeRefPtr
<TextDecoderStreamAlgorithms
>();
180 RefPtr
<TransformStream
> transformStream
=
181 TransformStream::CreateGeneric(aGlobal
, *algorithms
, aRv
);
186 // Step 11. (Done in the constructor)
187 auto decoderStream
= MakeRefPtr
<TextDecoderStream
>(
188 aGlobal
.GetAsSupports(), *encoding
, aOptions
.mFatal
, aOptions
.mIgnoreBOM
,
190 algorithms
->SetDecoderStream(*decoderStream
);
191 return decoderStream
.forget();
194 ReadableStream
* TextDecoderStream::Readable() const {
195 return mStream
->Readable();
198 WritableStream
* TextDecoderStream::Writable() const {
199 return mStream
->Writable();
202 } // namespace mozilla::dom