Line data Source code
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/. */
6 :
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"
12 : #include <stdint.h>
13 :
14 : namespace mozilla {
15 : namespace dom {
16 :
17 : static const char16_t kReplacementChar = static_cast<char16_t>(0xFFFD);
18 :
19 : void
20 0 : TextDecoder::Init(const nsAString& aLabel, const bool aFatal,
21 : ErrorResult& aRv)
22 : {
23 : // Let encoding be the result of getting an encoding from label.
24 : // If encoding is failure or replacement, throw a RangeError
25 : // (https://encoding.spec.whatwg.org/#dom-textdecoder).
26 0 : const Encoding* encoding = Encoding::ForLabelNoReplacement(aLabel);
27 0 : if (!encoding) {
28 0 : nsAutoString label(aLabel);
29 0 : label.Trim(" \t\n\f\r");
30 0 : aRv.ThrowRangeError<MSG_ENCODING_NOT_SUPPORTED>(label);
31 0 : return;
32 : }
33 0 : InitWithEncoding(WrapNotNull(encoding), aFatal);
34 : }
35 :
36 : void
37 0 : TextDecoder::InitWithEncoding(NotNull<const Encoding*> aEncoding,
38 : const bool aFatal)
39 : {
40 0 : aEncoding->Name(mEncoding);
41 : // If the constructor is called with an options argument,
42 : // and the fatal property of the dictionary is set,
43 : // set the internal fatal flag of the decoder object.
44 0 : mFatal = aFatal;
45 :
46 : // Create a decoder object for mEncoding.
47 0 : mDecoder = aEncoding->NewDecoderWithBOMRemoval();
48 0 : }
49 :
50 : void
51 0 : TextDecoder::Decode(Span<const uint8_t> aInput,
52 : const bool aStream,
53 : nsAString& aOutDecodedString,
54 : ErrorResult& aRv)
55 : {
56 0 : aOutDecodedString.Truncate();
57 :
58 0 : CheckedInt<size_t> needed = mDecoder->MaxUTF16BufferLength(aInput.Length());
59 0 : if (!needed.isValid() ||
60 0 : needed.value() > MaxValue<nsAString::size_type>::value) {
61 0 : aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
62 0 : return;
63 : }
64 :
65 0 : if (!aOutDecodedString.SetLength(needed.value(), fallible)) {
66 0 : aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
67 0 : return;
68 : }
69 :
70 : uint32_t result;
71 : size_t read;
72 : size_t written;
73 : bool hadErrors;
74 0 : if (mFatal) {
75 0 : Tie(result, read, written) = mDecoder->DecodeToUTF16WithoutReplacement(
76 0 : aInput, aOutDecodedString, !aStream);
77 0 : if (result != kInputEmpty) {
78 0 : aRv.ThrowTypeError<MSG_DOM_DECODING_FAILED>();
79 0 : return;
80 : }
81 : } else {
82 0 : Tie(result, read, written, hadErrors) =
83 0 : mDecoder->DecodeToUTF16(aInput, aOutDecodedString, !aStream);
84 : }
85 0 : MOZ_ASSERT(result == kInputEmpty);
86 0 : MOZ_ASSERT(read == aInput.Length());
87 0 : MOZ_ASSERT(written <= aOutDecodedString.Length());
88 : Unused << hadErrors;
89 :
90 0 : if (!aOutDecodedString.SetLength(written, fallible)) {
91 0 : aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
92 0 : return;
93 : }
94 :
95 : // If the internal streaming flag of the decoder object is not set,
96 : // then reset the encoding algorithm state to the default values
97 0 : if (!aStream) {
98 0 : mDecoder->Encoding()->NewDecoderWithBOMRemovalInto(*mDecoder);
99 : }
100 : }
101 :
102 : void
103 0 : TextDecoder::Decode(const Optional<ArrayBufferViewOrArrayBuffer>& aBuffer,
104 : const TextDecodeOptions& aOptions,
105 : nsAString& aOutDecodedString,
106 : ErrorResult& aRv)
107 : {
108 0 : if (!aBuffer.WasPassed()) {
109 0 : Decode(nullptr, aOptions.mStream, aOutDecodedString, aRv);
110 0 : return;
111 : }
112 0 : const ArrayBufferViewOrArrayBuffer& buf = aBuffer.Value();
113 : uint8_t* data;
114 : uint32_t length;
115 0 : if (buf.IsArrayBufferView()) {
116 0 : buf.GetAsArrayBufferView().ComputeLengthAndData();
117 0 : data = buf.GetAsArrayBufferView().Data();
118 0 : length = buf.GetAsArrayBufferView().Length();
119 : } else {
120 0 : MOZ_ASSERT(buf.IsArrayBuffer());
121 0 : buf.GetAsArrayBuffer().ComputeLengthAndData();
122 0 : data = buf.GetAsArrayBuffer().Data();
123 0 : length = buf.GetAsArrayBuffer().Length();
124 : }
125 0 : Decode(MakeSpan(data, length), aOptions.mStream, aOutDecodedString, aRv);
126 : }
127 :
128 : void
129 0 : TextDecoder::GetEncoding(nsAString& aEncoding)
130 : {
131 0 : CopyASCIItoUTF16(mEncoding, aEncoding);
132 0 : nsContentUtils::ASCIIToLower(aEncoding);
133 0 : }
134 :
135 : } // namespace dom
136 : } // namespace mozilla
|