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"
14 namespace mozilla::dom
{
16 void TextDecoder::Init(const nsAString
& aLabel
,
17 const TextDecoderOptions
& aOptions
, ErrorResult
& aRv
) {
18 // Let encoding be the result of getting an encoding from label.
19 // If encoding is failure or replacement, throw a RangeError
20 // (https://encoding.spec.whatwg.org/#dom-textdecoder).
21 const Encoding
* encoding
= Encoding::ForLabelNoReplacement(aLabel
);
23 NS_ConvertUTF16toUTF8
label(aLabel
);
24 label
.Trim(" \t\n\f\r");
25 aRv
.ThrowRangeError
<MSG_ENCODING_NOT_SUPPORTED
>(label
);
28 InitWithEncoding(WrapNotNull(encoding
), aOptions
);
31 void TextDecoder::InitWithEncoding(NotNull
<const Encoding
*> aEncoding
,
32 const TextDecoderOptions
& aOptions
) {
33 aEncoding
->Name(mEncoding
);
34 // Store the flags passed via our options dictionary.
35 mFatal
= aOptions
.mFatal
;
36 mIgnoreBOM
= aOptions
.mIgnoreBOM
;
38 // Create a decoder object for mEncoding.
40 mDecoder
= aEncoding
->NewDecoderWithoutBOMHandling();
42 mDecoder
= aEncoding
->NewDecoderWithBOMRemoval();
46 void TextDecoder::Decode(Span
<const uint8_t> aInput
, const bool aStream
,
47 nsAString
& aOutDecodedString
, ErrorResult
& aRv
) {
48 aOutDecodedString
.Truncate();
50 CheckedInt
<size_t> needed
= mDecoder
->MaxUTF16BufferLength(aInput
.Length());
51 if (!needed
.isValid() ||
52 needed
.value() > std::numeric_limits
<nsAString::size_type
>::max()) {
53 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
57 if (!aOutDecodedString
.SetLength(needed
.value(), fallible
)) {
58 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
67 Tie(result
, read
, written
) = mDecoder
->DecodeToUTF16WithoutReplacement(
68 aInput
, aOutDecodedString
, !aStream
);
69 if (result
!= kInputEmpty
) {
70 aRv
.ThrowTypeError
<MSG_DOM_DECODING_FAILED
>();
74 Tie(result
, read
, written
, hadErrors
) =
75 mDecoder
->DecodeToUTF16(aInput
, aOutDecodedString
, !aStream
);
77 MOZ_ASSERT(result
== kInputEmpty
);
78 MOZ_ASSERT(read
== aInput
.Length());
79 MOZ_ASSERT(written
<= aOutDecodedString
.Length());
82 if (!aOutDecodedString
.SetLength(written
, fallible
)) {
83 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
87 // If the internal streaming flag of the decoder object is not set,
88 // then reset the encoding algorithm state to the default values
91 mDecoder
->Encoding()->NewDecoderWithoutBOMHandlingInto(*mDecoder
);
93 mDecoder
->Encoding()->NewDecoderWithBOMRemovalInto(*mDecoder
);
98 void TextDecoder::Decode(const Optional
<ArrayBufferViewOrArrayBuffer
>& aBuffer
,
99 const TextDecodeOptions
& aOptions
,
100 nsAString
& aOutDecodedString
, ErrorResult
& aRv
) {
101 if (!aBuffer
.WasPassed()) {
102 Decode(nullptr, aOptions
.mStream
, aOutDecodedString
, aRv
);
105 const ArrayBufferViewOrArrayBuffer
& buf
= aBuffer
.Value();
108 if (buf
.IsArrayBufferView()) {
109 buf
.GetAsArrayBufferView().ComputeState();
110 data
= buf
.GetAsArrayBufferView().Data();
111 length
= buf
.GetAsArrayBufferView().Length();
113 MOZ_ASSERT(buf
.IsArrayBuffer());
114 buf
.GetAsArrayBuffer().ComputeState();
115 data
= buf
.GetAsArrayBuffer().Data();
116 length
= buf
.GetAsArrayBuffer().Length();
118 Decode(Span(data
, length
), aOptions
.mStream
, aOutDecodedString
, aRv
);
121 void TextDecoder::GetEncoding(nsAString
& aEncoding
) {
122 CopyASCIItoUTF16(mEncoding
, aEncoding
);
123 nsContentUtils::ASCIIToLower(aEncoding
);
126 } // namespace mozilla::dom