summaryrefslogtreecommitdiffstats
path: root/intl/uconv/nsConverterOutputStream.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'intl/uconv/nsConverterOutputStream.cpp')
-rw-r--r--intl/uconv/nsConverterOutputStream.cpp115
1 files changed, 115 insertions, 0 deletions
diff --git a/intl/uconv/nsConverterOutputStream.cpp b/intl/uconv/nsConverterOutputStream.cpp
new file mode 100644
index 0000000000..a24adb0377
--- /dev/null
+++ b/intl/uconv/nsConverterOutputStream.cpp
@@ -0,0 +1,115 @@
+/* vim:set expandtab ts=4 sw=2 sts=2 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 "mozilla/Encoding.h"
+
+using namespace mozilla;
+
+NS_IMPL_ISUPPORTS(nsConverterOutputStream, nsIUnicharOutputStream,
+ nsIConverterOutputStream)
+
+nsConverterOutputStream::~nsConverterOutputStream() { Close(); }
+
+NS_IMETHODIMP
+nsConverterOutputStream::Init(nsIOutputStream* aOutStream,
+ const char* aCharset) {
+ MOZ_ASSERT(aOutStream, "Null output stream!");
+
+ const Encoding* encoding;
+ if (!aCharset) {
+ encoding = UTF_8_ENCODING;
+ } else {
+ encoding = Encoding::ForLabelNoReplacement(MakeStringSpan(aCharset));
+ if (!encoding || encoding == UTF_16LE_ENCODING ||
+ encoding == UTF_16BE_ENCODING) {
+ return NS_ERROR_UCONV_NOCONV;
+ }
+ }
+
+ mConverter = encoding->NewEncoder();
+
+ mOutStream = aOutStream;
+
+ return NS_OK;
+}
+
+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;
+ }
+ MOZ_ASSERT(mConverter, "Must have a converter when not closed");
+ uint8_t buffer[4096];
+ auto dst = Span(buffer);
+ auto src = Span(aChars, aCount);
+ for (;;) {
+ uint32_t result;
+ size_t read;
+ size_t written;
+ std::tie(result, read, written, std::ignore) =
+ mConverter->EncodeFromUTF16(src, dst, false);
+ src = src.From(read);
+ uint32_t streamWritten;
+ nsresult rv = mOutStream->Write(reinterpret_cast<char*>(dst.Elements()),
+ written, &streamWritten);
+ *aSuccess = NS_SUCCEEDED(rv) && written == streamWritten;
+ if (!(*aSuccess)) {
+ return rv;
+ }
+ if (result == kInputEmpty) {
+ return NS_OK;
+ }
+ }
+}
+
+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.
+
+ // If we are encoding to ISO-2022-JP, potentially
+ // transition back to the ASCII state. The buffer
+ // needs to be large enough for an additional NCR,
+ // though.
+ uint8_t buffer[12];
+ auto dst = Span(buffer);
+ Span<char16_t> src(nullptr);
+ uint32_t result;
+ size_t written;
+ std::tie(result, std::ignore, written, std::ignore) =
+ mConverter->EncodeFromUTF16(src, dst, true);
+ MOZ_ASSERT(result == kInputEmpty);
+ uint32_t streamWritten;
+ if (!written) {
+ return NS_OK;
+ }
+ return mOutStream->Write(reinterpret_cast<char*>(dst.Elements()), written,
+ &streamWritten);
+}
+
+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;
+}