1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/uconv/src/nsConverterOutputStream.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,143 @@ 1.4 +/* vim:set expandtab ts=4 sw=4 sts=4 cin: */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsCOMPtr.h" 1.10 + 1.11 +#include "nsIOutputStream.h" 1.12 +#include "nsICharsetConverterManager.h" 1.13 + 1.14 +#include "nsConverterOutputStream.h" 1.15 +#include "nsServiceManagerUtils.h" 1.16 + 1.17 +NS_IMPL_ISUPPORTS(nsConverterOutputStream, 1.18 + nsIUnicharOutputStream, 1.19 + nsIConverterOutputStream) 1.20 + 1.21 +nsConverterOutputStream::~nsConverterOutputStream() 1.22 +{ 1.23 + Close(); 1.24 +} 1.25 + 1.26 +NS_IMETHODIMP 1.27 +nsConverterOutputStream::Init(nsIOutputStream* aOutStream, 1.28 + const char* aCharset, 1.29 + uint32_t aBufferSize /* ignored */, 1.30 + char16_t aReplacementChar) 1.31 +{ 1.32 + NS_PRECONDITION(aOutStream, "Null output stream!"); 1.33 + 1.34 + if (!aCharset) 1.35 + aCharset = "UTF-8"; 1.36 + 1.37 + nsresult rv; 1.38 + nsCOMPtr<nsICharsetConverterManager> ccm = 1.39 + do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv); 1.40 + if (NS_FAILED(rv)) return rv; 1.41 + 1.42 + rv = ccm->GetUnicodeEncoder(aCharset, getter_AddRefs(mConverter)); 1.43 + if (NS_FAILED(rv)) 1.44 + return rv; 1.45 + 1.46 + mOutStream = aOutStream; 1.47 + 1.48 + int32_t behaviour = aReplacementChar ? nsIUnicodeEncoder::kOnError_Replace 1.49 + : nsIUnicodeEncoder::kOnError_Signal; 1.50 + return mConverter-> 1.51 + SetOutputErrorBehavior(behaviour, 1.52 + nullptr, 1.53 + aReplacementChar); 1.54 +} 1.55 + 1.56 +NS_IMETHODIMP 1.57 +nsConverterOutputStream::Write(uint32_t aCount, const char16_t* aChars, 1.58 + bool* aSuccess) 1.59 +{ 1.60 + if (!mOutStream) { 1.61 + NS_ASSERTION(!mConverter, "Closed streams shouldn't have converters"); 1.62 + return NS_BASE_STREAM_CLOSED; 1.63 + } 1.64 + NS_ASSERTION(mConverter, "Must have a converter when not closed"); 1.65 + 1.66 + int32_t inLen = aCount; 1.67 + 1.68 + int32_t maxLen; 1.69 + nsresult rv = mConverter->GetMaxLength(aChars, inLen, &maxLen); 1.70 + NS_ENSURE_SUCCESS(rv, rv); 1.71 + 1.72 + nsAutoCString buf; 1.73 + buf.SetLength(maxLen); 1.74 + if (buf.Length() != (uint32_t) maxLen) 1.75 + return NS_ERROR_OUT_OF_MEMORY; 1.76 + 1.77 + int32_t outLen = maxLen; 1.78 + rv = mConverter->Convert(aChars, &inLen, buf.BeginWriting(), &outLen); 1.79 + if (NS_FAILED(rv)) 1.80 + return rv; 1.81 + if (rv == NS_ERROR_UENC_NOMAPPING) { 1.82 + // Yes, NS_ERROR_UENC_NOMAPPING is a success code 1.83 + return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA; 1.84 + } 1.85 + NS_ASSERTION((uint32_t) inLen == aCount, 1.86 + "Converter didn't consume all the data!"); 1.87 + 1.88 + uint32_t written; 1.89 + rv = mOutStream->Write(buf.get(), outLen, &written); 1.90 + *aSuccess = NS_SUCCEEDED(rv) && written == uint32_t(outLen); 1.91 + return rv; 1.92 + 1.93 +} 1.94 + 1.95 +NS_IMETHODIMP 1.96 +nsConverterOutputStream::WriteString(const nsAString& aString, bool* aSuccess) 1.97 +{ 1.98 + int32_t inLen = aString.Length(); 1.99 + nsAString::const_iterator i; 1.100 + aString.BeginReading(i); 1.101 + return Write(inLen, i.get(), aSuccess); 1.102 +} 1.103 + 1.104 +NS_IMETHODIMP 1.105 +nsConverterOutputStream::Flush() 1.106 +{ 1.107 + if (!mOutStream) 1.108 + return NS_OK; // Already closed. 1.109 + 1.110 + char buf[1024]; 1.111 + int32_t size = sizeof(buf); 1.112 + nsresult rv = mConverter->Finish(buf, &size); 1.113 + NS_ASSERTION(rv != NS_OK_UENC_MOREOUTPUT, 1.114 + "1024 bytes ought to be enough for everyone"); 1.115 + if (NS_FAILED(rv)) 1.116 + return rv; 1.117 + if (size == 0) 1.118 + return NS_OK; 1.119 + 1.120 + uint32_t written; 1.121 + rv = mOutStream->Write(buf, size, &written); 1.122 + if (NS_FAILED(rv)) { 1.123 + NS_WARNING("Flush() lost data!"); 1.124 + return rv; 1.125 + } 1.126 + if (written != uint32_t(size)) { 1.127 + NS_WARNING("Flush() lost data!"); 1.128 + return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA; 1.129 + } 1.130 + return rv; 1.131 +} 1.132 + 1.133 +NS_IMETHODIMP 1.134 +nsConverterOutputStream::Close() 1.135 +{ 1.136 + if (!mOutStream) 1.137 + return NS_OK; // Already closed. 1.138 + 1.139 + nsresult rv1 = Flush(); 1.140 + 1.141 + nsresult rv2 = mOutStream->Close(); 1.142 + mOutStream = nullptr; 1.143 + mConverter = nullptr; 1.144 + return NS_FAILED(rv1) ? rv1 : rv2; 1.145 +} 1.146 +