TextDecoder.cpp (3968B)
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 9 #include <stdint.h> 10 11 #include "mozilla/Encoding.h" 12 #include "mozilla/dom/BufferSourceBinding.h" 13 #include "mozilla/dom/UnionTypes.h" 14 #include "nsContentUtils.h" 15 16 namespace mozilla::dom { 17 18 void TextDecoder::Init(const nsAString& aLabel, 19 const TextDecoderOptions& aOptions, ErrorResult& aRv) { 20 // Let encoding be the result of getting an encoding from label. 21 // If encoding is failure or replacement, throw a RangeError 22 // (https://encoding.spec.whatwg.org/#dom-textdecoder). 23 const Encoding* encoding = Encoding::ForLabelNoReplacement(aLabel); 24 if (!encoding) { 25 NS_ConvertUTF16toUTF8 label(aLabel); 26 label.Trim(" \t\n\f\r"); 27 aRv.ThrowRangeError<MSG_ENCODING_NOT_SUPPORTED>(label); 28 return; 29 } 30 InitWithEncoding(WrapNotNull(encoding), aOptions); 31 } 32 33 void TextDecoder::InitWithEncoding(NotNull<const Encoding*> aEncoding, 34 const TextDecoderOptions& aOptions) { 35 aEncoding->Name(mEncoding); 36 // Store the flags passed via our options dictionary. 37 mFatal = aOptions.mFatal; 38 mIgnoreBOM = aOptions.mIgnoreBOM; 39 40 // Create a decoder object for mEncoding. 41 if (mIgnoreBOM) { 42 mDecoder = aEncoding->NewDecoderWithoutBOMHandling(); 43 } else { 44 mDecoder = aEncoding->NewDecoderWithBOMRemoval(); 45 } 46 } 47 48 void TextDecoderCommon::DecodeNative(Span<const uint8_t> aInput, 49 const bool aStream, 50 nsAString& aOutDecodedString, 51 ErrorResult& aRv) { 52 aOutDecodedString.Truncate(); 53 54 CheckedInt<nsAString::size_type> needed = 55 mDecoder->MaxUTF16BufferLength(aInput.Length()); 56 if (!needed.isValid()) { 57 aRv.Throw(NS_ERROR_OUT_OF_MEMORY); 58 return; 59 } 60 61 auto output = aOutDecodedString.GetMutableData(needed.value(), fallible); 62 if (!output) { 63 aRv.Throw(NS_ERROR_OUT_OF_MEMORY); 64 return; 65 } 66 67 uint32_t result; 68 size_t read; 69 size_t written; 70 if (mFatal) { 71 std::tie(result, read, written) = 72 mDecoder->DecodeToUTF16WithoutReplacement(aInput, *output, !aStream); 73 if (result != kInputEmpty) { 74 aRv.ThrowTypeError<MSG_DOM_DECODING_FAILED>(); 75 return; 76 } 77 } else { 78 std::tie(result, read, written, std::ignore) = 79 mDecoder->DecodeToUTF16(aInput, *output, !aStream); 80 } 81 MOZ_ASSERT(result == kInputEmpty); 82 MOZ_ASSERT(read == aInput.Length()); 83 MOZ_ASSERT(written <= aOutDecodedString.Length()); 84 85 if (!aOutDecodedString.SetLength(written, fallible)) { 86 aRv.Throw(NS_ERROR_OUT_OF_MEMORY); 87 return; 88 } 89 90 // If the internal streaming flag of the decoder object is not set, 91 // then reset the encoding algorithm state to the default values 92 if (!aStream) { 93 if (mIgnoreBOM) { 94 mDecoder->Encoding()->NewDecoderWithoutBOMHandlingInto(*mDecoder); 95 } else { 96 mDecoder->Encoding()->NewDecoderWithBOMRemovalInto(*mDecoder); 97 } 98 } 99 } 100 101 void TextDecoder::Decode(const Optional<BufferSource>& aBuffer, 102 const TextDecodeOptions& aOptions, 103 nsAString& aOutDecodedString, ErrorResult& aRv) { 104 if (!aBuffer.WasPassed()) { 105 DecodeNative(nullptr, aOptions.mStream, aOutDecodedString, aRv); 106 return; 107 } 108 109 ProcessTypedArrays(aBuffer.Value(), [&](const Span<uint8_t>& aData, 110 JS::AutoCheckCannotGC&&) { 111 DecodeNative(aData, aOptions.mStream, aOutDecodedString, aRv); 112 }); 113 } 114 115 void TextDecoderCommon::GetEncoding(nsAString& aEncoding) { 116 CopyASCIItoUTF16(mEncoding, aEncoding); 117 nsContentUtils::ASCIIToLower(aEncoding); 118 } 119 120 } // namespace mozilla::dom