michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/dom/TextDecoder.h" michael@0: #include "mozilla/dom/EncodingUtils.h" michael@0: #include "nsContentUtils.h" michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: static const char16_t kReplacementChar = static_cast(0xFFFD); michael@0: michael@0: void michael@0: TextDecoder::Init(const nsAString& aLabel, const bool aFatal, michael@0: ErrorResult& aRv) michael@0: { michael@0: nsAutoString label(aLabel); michael@0: EncodingUtils::TrimSpaceCharacters(label); michael@0: michael@0: nsAutoCString encoding; michael@0: // Let encoding be the result of getting an encoding from label. michael@0: // If encoding is failure or replacement, throw a TypeError. michael@0: if (!EncodingUtils::FindEncodingForLabel(label, encoding) || michael@0: encoding.EqualsLiteral("replacement")) { michael@0: aRv.ThrowTypeError(MSG_ENCODING_NOT_SUPPORTED, &label); michael@0: return; michael@0: } michael@0: InitWithEncoding(encoding, aFatal); michael@0: } michael@0: michael@0: void michael@0: TextDecoder::InitWithEncoding(const nsACString& aEncoding, const bool aFatal) michael@0: { michael@0: mEncoding = aEncoding; michael@0: // If the constructor is called with an options argument, michael@0: // and the fatal property of the dictionary is set, michael@0: // set the internal fatal flag of the decoder object. michael@0: mFatal = aFatal; michael@0: michael@0: // Create a decoder object for mEncoding. michael@0: mDecoder = EncodingUtils::DecoderForEncoding(mEncoding); michael@0: michael@0: if (mFatal) { michael@0: mDecoder->SetInputErrorBehavior(nsIUnicodeDecoder::kOnError_Signal); michael@0: } michael@0: } michael@0: michael@0: void michael@0: TextDecoder::Decode(const char* aInput, const int32_t aLength, michael@0: const bool aStream, nsAString& aOutDecodedString, michael@0: ErrorResult& aRv) michael@0: { michael@0: aOutDecodedString.Truncate(); michael@0: michael@0: // Run or resume the decoder algorithm of the decoder object's encoder. michael@0: int32_t outLen; michael@0: nsresult rv = mDecoder->GetMaxLength(aInput, aLength, &outLen); michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(rv); michael@0: return; michael@0: } michael@0: // Need a fallible allocator because the caller may be a content michael@0: // and the content can specify the length of the string. michael@0: static const fallible_t fallible = fallible_t(); michael@0: nsAutoArrayPtr buf(new (fallible) char16_t[outLen + 1]); michael@0: if (!buf) { michael@0: aRv.Throw(NS_ERROR_OUT_OF_MEMORY); michael@0: return; michael@0: } michael@0: michael@0: int32_t length = aLength; michael@0: rv = mDecoder->Convert(aInput, &length, buf, &outLen); michael@0: MOZ_ASSERT(mFatal || rv != NS_ERROR_ILLEGAL_INPUT); michael@0: buf[outLen] = 0; michael@0: aOutDecodedString.Append(buf, outLen); michael@0: michael@0: // If the internal streaming flag of the decoder object is not set, michael@0: // then reset the encoding algorithm state to the default values michael@0: if (!aStream) { michael@0: mDecoder->Reset(); michael@0: if (rv == NS_OK_UDEC_MOREINPUT) { michael@0: if (mFatal) { michael@0: aRv.Throw(NS_ERROR_DOM_ENCODING_DECODE_ERR); michael@0: } else { michael@0: // Need to emit a decode error manually michael@0: // to simulate the EOF handling of the Encoding spec. michael@0: aOutDecodedString.Append(kReplacementChar); michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(NS_ERROR_DOM_ENCODING_DECODE_ERR); michael@0: } michael@0: } michael@0: michael@0: void michael@0: TextDecoder::GetEncoding(nsAString& aEncoding) michael@0: { michael@0: CopyASCIItoUTF16(mEncoding, aEncoding); michael@0: nsContentUtils::ASCIIToLower(aEncoding); michael@0: } michael@0: michael@0: } // dom michael@0: } // mozilla