Backed out changeset af2c13b9fdb7 (bug 1801244) per developer request.
[gecko.git] / intl / uconv / nsConverterOutputStream.cpp
bloba24adb03777f1fcd079910211e1001542e7122e5
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/. */
6 #include "nsCOMPtr.h"
7 #include "nsIOutputStream.h"
8 #include "nsString.h"
9 #include "nsConverterOutputStream.h"
10 #include "mozilla/Encoding.h"
12 using namespace mozilla;
14 NS_IMPL_ISUPPORTS(nsConverterOutputStream, nsIUnicharOutputStream,
15 nsIConverterOutputStream)
17 nsConverterOutputStream::~nsConverterOutputStream() { Close(); }
19 NS_IMETHODIMP
20 nsConverterOutputStream::Init(nsIOutputStream* aOutStream,
21 const char* aCharset) {
22 MOZ_ASSERT(aOutStream, "Null output stream!");
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;
35 mConverter = encoding->NewEncoder();
37 mOutStream = aOutStream;
39 return NS_OK;
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;
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;
67 if (result == kInputEmpty) {
68 return NS_OK;
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);
81 NS_IMETHODIMP
82 nsConverterOutputStream::Flush() {
83 if (!mOutStream) return NS_OK; // Already closed.
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;
101 return mOutStream->Write(reinterpret_cast<char*>(dst.Elements()), written,
102 &streamWritten);
105 NS_IMETHODIMP
106 nsConverterOutputStream::Close() {
107 if (!mOutStream) return NS_OK; // Already closed.
109 nsresult rv1 = Flush();
111 nsresult rv2 = mOutStream->Close();
112 mOutStream = nullptr;
113 mConverter = nullptr;
114 return NS_FAILED(rv1) ? rv1 : rv2;