1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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/TextDecoder.h"
8 #include "mozilla/dom/UnionTypes.h"
9 #include "mozilla/Encoding.h"
10 #include "mozilla/UniquePtrExtensions.h"
11 #include "nsContentUtils.h"
15 namespace mozilla::dom
{
17 void TextDecoder::Init(const nsAString
& aLabel
,
18 const TextDecoderOptions
& aOptions
, ErrorResult
& aRv
) {
19 // Let encoding be the result of getting an encoding from label.
20 // If encoding is failure or replacement, throw a RangeError
21 // (https://encoding.spec.whatwg.org/#dom-textdecoder).
22 const Encoding
* encoding
= Encoding::ForLabelNoReplacement(aLabel
);
24 NS_ConvertUTF16toUTF8
label(aLabel
);
25 label
.Trim(" \t\n\f\r");
26 aRv
.ThrowRangeError
<MSG_ENCODING_NOT_SUPPORTED
>(label
);
29 InitWithEncoding(WrapNotNull(encoding
), aOptions
);
32 void TextDecoder::InitWithEncoding(NotNull
<const Encoding
*> aEncoding
,
33 const TextDecoderOptions
& aOptions
) {
34 aEncoding
->Name(mEncoding
);
35 // Store the flags passed via our options dictionary.
36 mFatal
= aOptions
.mFatal
;
37 mIgnoreBOM
= aOptions
.mIgnoreBOM
;
39 // Create a decoder object for mEncoding.
41 mDecoder
= aEncoding
->NewDecoderWithoutBOMHandling();
43 mDecoder
= aEncoding
->NewDecoderWithBOMRemoval();
47 void TextDecoderCommon::DecodeNative(Span
<const uint8_t> aInput
,
49 nsAString
& aOutDecodedString
,
51 aOutDecodedString
.Truncate();
53 CheckedInt
<nsAString::size_type
> needed
=
54 mDecoder
->MaxUTF16BufferLength(aInput
.Length());
55 if (!needed
.isValid()) {
56 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
60 auto output
= aOutDecodedString
.GetMutableData(needed
.value(), fallible
);
62 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
70 std::tie(result
, read
, written
) =
71 mDecoder
->DecodeToUTF16WithoutReplacement(aInput
, *output
, !aStream
);
72 if (result
!= kInputEmpty
) {
73 aRv
.ThrowTypeError
<MSG_DOM_DECODING_FAILED
>();
77 std::tie(result
, read
, written
, std::ignore
) =
78 mDecoder
->DecodeToUTF16(aInput
, *output
, !aStream
);
80 MOZ_ASSERT(result
== kInputEmpty
);
81 MOZ_ASSERT(read
== aInput
.Length());
82 MOZ_ASSERT(written
<= aOutDecodedString
.Length());
84 if (!aOutDecodedString
.SetLength(written
, fallible
)) {
85 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
89 // If the internal streaming flag of the decoder object is not set,
90 // then reset the encoding algorithm state to the default values
93 mDecoder
->Encoding()->NewDecoderWithoutBOMHandlingInto(*mDecoder
);
95 mDecoder
->Encoding()->NewDecoderWithBOMRemovalInto(*mDecoder
);
100 void TextDecoder::Decode(const Optional
<ArrayBufferViewOrArrayBuffer
>& aBuffer
,
101 const TextDecodeOptions
& aOptions
,
102 nsAString
& aOutDecodedString
, ErrorResult
& aRv
) {
103 if (!aBuffer
.WasPassed()) {
104 DecodeNative(nullptr, aOptions
.mStream
, aOutDecodedString
, aRv
);
107 const ArrayBufferViewOrArrayBuffer
& buf
= aBuffer
.Value();
110 if (buf
.IsArrayBufferView()) {
111 buf
.GetAsArrayBufferView().ComputeState();
112 data
= buf
.GetAsArrayBufferView().Data();
113 length
= buf
.GetAsArrayBufferView().Length();
115 MOZ_ASSERT(buf
.IsArrayBuffer());
116 buf
.GetAsArrayBuffer().ComputeState();
117 data
= buf
.GetAsArrayBuffer().Data();
118 length
= buf
.GetAsArrayBuffer().Length();
120 DecodeNative(Span(data
, length
), aOptions
.mStream
, aOutDecodedString
, aRv
);
123 void TextDecoderCommon::GetEncoding(nsAString
& aEncoding
) {
124 CopyASCIItoUTF16(mEncoding
, aEncoding
);
125 nsContentUtils::ASCIIToLower(aEncoding
);
128 } // namespace mozilla::dom