123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- /* vim:set expandtab ts=4 sw=4 sts=4 cin: */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "nsCOMPtr.h"
- #include "nsIOutputStream.h"
- #include "nsString.h"
- #include "nsConverterOutputStream.h"
- #include "nsIUnicodeEncoder.h"
- #include "mozilla/dom/EncodingUtils.h"
- using mozilla::dom::EncodingUtils;
- NS_IMPL_ISUPPORTS(nsConverterOutputStream,
- nsIUnicharOutputStream,
- nsIConverterOutputStream)
- nsConverterOutputStream::~nsConverterOutputStream()
- {
- Close();
- }
- NS_IMETHODIMP
- nsConverterOutputStream::Init(nsIOutputStream* aOutStream,
- const char* aCharset,
- uint32_t aBufferSize /* ignored */,
- char16_t aReplacementChar)
- {
- NS_PRECONDITION(aOutStream, "Null output stream!");
- nsAutoCString label;
- if (!aCharset) {
- label.AssignLiteral("UTF-8");
- } else {
- label = aCharset;
- }
- nsAutoCString encoding;
- if (label.EqualsLiteral("UTF-16")) {
- // Make sure to output a BOM when UTF-16 requested
- encoding.Assign(label);
- } else if (!EncodingUtils::FindEncodingForLabelNoReplacement(label,
- encoding)) {
- return NS_ERROR_UCONV_NOCONV;
- }
- mConverter = EncodingUtils::EncoderForEncoding(encoding);
- mOutStream = aOutStream;
- int32_t behaviour = aReplacementChar ? nsIUnicodeEncoder::kOnError_Replace
- : nsIUnicodeEncoder::kOnError_Signal;
- return mConverter->
- SetOutputErrorBehavior(behaviour,
- nullptr,
- aReplacementChar);
- }
- NS_IMETHODIMP
- nsConverterOutputStream::Write(uint32_t aCount, const char16_t* aChars,
- bool* aSuccess)
- {
- if (!mOutStream) {
- NS_ASSERTION(!mConverter, "Closed streams shouldn't have converters");
- return NS_BASE_STREAM_CLOSED;
- }
- NS_ASSERTION(mConverter, "Must have a converter when not closed");
- int32_t inLen = aCount;
- int32_t maxLen;
- nsresult rv = mConverter->GetMaxLength(aChars, inLen, &maxLen);
- NS_ENSURE_SUCCESS(rv, rv);
- nsAutoCString buf;
- buf.SetLength(maxLen);
- if (buf.Length() != (uint32_t) maxLen)
- return NS_ERROR_OUT_OF_MEMORY;
- int32_t outLen = maxLen;
- rv = mConverter->Convert(aChars, &inLen, buf.BeginWriting(), &outLen);
- if (NS_FAILED(rv))
- return rv;
- if (rv == NS_ERROR_UENC_NOMAPPING) {
- // Yes, NS_ERROR_UENC_NOMAPPING is a success code
- return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA;
- }
- NS_ASSERTION((uint32_t) inLen == aCount,
- "Converter didn't consume all the data!");
- uint32_t written;
- rv = mOutStream->Write(buf.get(), outLen, &written);
- *aSuccess = NS_SUCCEEDED(rv) && written == uint32_t(outLen);
- return rv;
- }
- NS_IMETHODIMP
- nsConverterOutputStream::WriteString(const nsAString& aString, bool* aSuccess)
- {
- int32_t inLen = aString.Length();
- nsAString::const_iterator i;
- aString.BeginReading(i);
- return Write(inLen, i.get(), aSuccess);
- }
- NS_IMETHODIMP
- nsConverterOutputStream::Flush()
- {
- if (!mOutStream)
- return NS_OK; // Already closed.
- char buf[1024];
- int32_t size = sizeof(buf);
- nsresult rv = mConverter->Finish(buf, &size);
- NS_ASSERTION(rv != NS_OK_UENC_MOREOUTPUT,
- "1024 bytes ought to be enough for everyone");
- if (NS_FAILED(rv))
- return rv;
- if (size == 0)
- return NS_OK;
- uint32_t written;
- rv = mOutStream->Write(buf, size, &written);
- if (NS_FAILED(rv)) {
- NS_WARNING("Flush() lost data!");
- return rv;
- }
- if (written != uint32_t(size)) {
- NS_WARNING("Flush() lost data!");
- return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA;
- }
- return rv;
- }
- NS_IMETHODIMP
- nsConverterOutputStream::Close()
- {
- if (!mOutStream)
- return NS_OK; // Already closed.
- nsresult rv1 = Flush();
- nsresult rv2 = mOutStream->Close();
- mOutStream = nullptr;
- mConverter = nullptr;
- return NS_FAILED(rv1) ? rv1 : rv2;
- }
|