nsConverterOutputStream.cpp (3344B)
1 /* vim:set expandtab ts=4 sw=2 sts=2 cin: */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "nsCOMPtr.h" 7 #include "nsIOutputStream.h" 8 #include "nsString.h" 9 #include "nsConverterOutputStream.h" 10 #include "mozilla/Encoding.h" 11 12 using namespace mozilla; 13 14 NS_IMPL_ISUPPORTS(nsConverterOutputStream, nsIUnicharOutputStream, 15 nsIConverterOutputStream) 16 17 nsConverterOutputStream::~nsConverterOutputStream() { Close(); } 18 19 NS_IMETHODIMP 20 nsConverterOutputStream::Init(nsIOutputStream* aOutStream, 21 const char* aCharset) { 22 MOZ_ASSERT(aOutStream, "Null output stream!"); 23 24 const Encoding* encoding; 25 if (!aCharset) { 26 encoding = UTF_8_ENCODING; 27 } else { 28 encoding = Encoding::ForLabelNoReplacement(MakeStringSpan(aCharset)); 29 if (!encoding || encoding == UTF_16LE_ENCODING || 30 encoding == UTF_16BE_ENCODING) { 31 return NS_ERROR_UCONV_NOCONV; 32 } 33 } 34 35 mConverter = encoding->NewEncoder(); 36 37 mOutStream = aOutStream; 38 39 return NS_OK; 40 } 41 42 NS_IMETHODIMP 43 nsConverterOutputStream::Write(uint32_t aCount, const char16_t* aChars, 44 bool* aSuccess) { 45 if (!mOutStream) { 46 NS_ASSERTION(!mConverter, "Closed streams shouldn't have converters"); 47 return NS_BASE_STREAM_CLOSED; 48 } 49 MOZ_ASSERT(mConverter, "Must have a converter when not closed"); 50 uint8_t buffer[4096]; 51 auto dst = Span(buffer); 52 auto src = Span(aChars, aCount); 53 for (;;) { 54 uint32_t result; 55 size_t read; 56 size_t written; 57 std::tie(result, read, written, std::ignore) = 58 mConverter->EncodeFromUTF16(src, dst, false); 59 src = src.From(read); 60 uint32_t streamWritten; 61 nsresult rv = mOutStream->Write(reinterpret_cast<char*>(dst.Elements()), 62 written, &streamWritten); 63 *aSuccess = NS_SUCCEEDED(rv) && written == streamWritten; 64 if (!(*aSuccess)) { 65 return rv; 66 } 67 if (result == kInputEmpty) { 68 return NS_OK; 69 } 70 } 71 } 72 73 NS_IMETHODIMP 74 nsConverterOutputStream::WriteString(const nsAString& aString, bool* aSuccess) { 75 int32_t inLen = aString.Length(); 76 nsAString::const_iterator i; 77 aString.BeginReading(i); 78 return Write(inLen, i.get(), aSuccess); 79 } 80 81 NS_IMETHODIMP 82 nsConverterOutputStream::Flush() { 83 if (!mOutStream) return NS_OK; // Already closed. 84 85 // If we are encoding to ISO-2022-JP, potentially 86 // transition back to the ASCII state. The buffer 87 // needs to be large enough for an additional NCR, 88 // though. 89 uint8_t buffer[12]; 90 auto dst = Span(buffer); 91 Span<char16_t> src(nullptr); 92 uint32_t result; 93 size_t written; 94 std::tie(result, std::ignore, written, std::ignore) = 95 mConverter->EncodeFromUTF16(src, dst, true); 96 MOZ_ASSERT(result == kInputEmpty); 97 uint32_t streamWritten; 98 if (!written) { 99 return NS_OK; 100 } 101 return mOutStream->Write(reinterpret_cast<char*>(dst.Elements()), written, 102 &streamWritten); 103 } 104 105 NS_IMETHODIMP 106 nsConverterOutputStream::Close() { 107 if (!mOutStream) return NS_OK; // Already closed. 108 109 nsresult rv1 = Flush(); 110 111 nsresult rv2 = mOutStream->Close(); 112 mOutStream = nullptr; 113 mConverter = nullptr; 114 return NS_FAILED(rv1) ? rv1 : rv2; 115 }