Line data Source code
1 : /* vim:set expandtab ts=4 sw=4 sts=4 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 :
8 : #include "nsIOutputStream.h"
9 : #include "nsString.h"
10 :
11 : #include "nsConverterOutputStream.h"
12 : #include "mozilla/Encoding.h"
13 : #include "mozilla/Unused.h"
14 :
15 : using namespace mozilla;
16 :
17 0 : NS_IMPL_ISUPPORTS(nsConverterOutputStream,
18 : nsIUnicharOutputStream,
19 : nsIConverterOutputStream)
20 :
21 0 : nsConverterOutputStream::~nsConverterOutputStream()
22 : {
23 0 : Close();
24 0 : }
25 :
26 : NS_IMETHODIMP
27 0 : nsConverterOutputStream::Init(nsIOutputStream* aOutStream,
28 : const char* aCharset)
29 : {
30 0 : NS_PRECONDITION(aOutStream, "Null output stream!");
31 :
32 : const Encoding* encoding;
33 0 : if (!aCharset) {
34 0 : encoding = UTF_8_ENCODING;
35 : } else {
36 0 : encoding = Encoding::ForLabelNoReplacement(MakeStringSpan(aCharset));
37 0 : if (!encoding || encoding == UTF_16LE_ENCODING ||
38 0 : encoding == UTF_16BE_ENCODING) {
39 0 : return NS_ERROR_UCONV_NOCONV;
40 : }
41 : }
42 :
43 0 : mConverter = encoding->NewEncoder();
44 :
45 0 : mOutStream = aOutStream;
46 :
47 0 : return NS_OK;
48 : }
49 :
50 : NS_IMETHODIMP
51 0 : nsConverterOutputStream::Write(uint32_t aCount, const char16_t* aChars,
52 : bool* aSuccess)
53 : {
54 0 : if (!mOutStream) {
55 0 : NS_ASSERTION(!mConverter, "Closed streams shouldn't have converters");
56 0 : return NS_BASE_STREAM_CLOSED;
57 : }
58 0 : MOZ_ASSERT(mConverter, "Must have a converter when not closed");
59 : uint8_t buffer[4096];
60 0 : auto dst = MakeSpan(buffer);
61 0 : auto src = MakeSpan(aChars, aCount);
62 : for (;;) {
63 : uint32_t result;
64 : size_t read;
65 : size_t written;
66 : bool hadErrors;
67 0 : Tie(result, read, written, hadErrors) =
68 0 : mConverter->EncodeFromUTF16(src, dst, false);
69 : Unused << hadErrors;
70 0 : src = src.From(read);
71 : uint32_t streamWritten;
72 0 : nsresult rv = mOutStream->Write(
73 0 : reinterpret_cast<char*>(dst.Elements()), written, &streamWritten);
74 0 : *aSuccess = NS_SUCCEEDED(rv) && written == streamWritten;
75 0 : if (!(*aSuccess)) {
76 0 : return rv;
77 : }
78 0 : if (result == kInputEmpty) {
79 0 : return NS_OK;
80 : }
81 0 : }
82 : }
83 :
84 : NS_IMETHODIMP
85 0 : nsConverterOutputStream::WriteString(const nsAString& aString, bool* aSuccess)
86 : {
87 0 : int32_t inLen = aString.Length();
88 0 : nsAString::const_iterator i;
89 0 : aString.BeginReading(i);
90 0 : return Write(inLen, i.get(), aSuccess);
91 : }
92 :
93 : NS_IMETHODIMP
94 0 : nsConverterOutputStream::Flush()
95 : {
96 0 : if (!mOutStream)
97 0 : return NS_OK; // Already closed.
98 :
99 : // If we are encoding to ISO-2022-JP, potentially
100 : // transition back to the ASCII state. The buffer
101 : // needs to be large enough for an additional NCR,
102 : // though.
103 : uint8_t buffer[12];
104 0 : auto dst = MakeSpan(buffer);
105 0 : Span<char16_t> src(nullptr);
106 : uint32_t result;
107 : size_t read;
108 : size_t written;
109 : bool hadErrors;
110 0 : Tie(result, read, written, hadErrors) =
111 0 : mConverter->EncodeFromUTF16(src, dst, true);
112 : Unused << hadErrors;
113 0 : MOZ_ASSERT(result == kInputEmpty);
114 : uint32_t streamWritten;
115 0 : if (!written) {
116 0 : return NS_OK;
117 : }
118 0 : return mOutStream->Write(
119 0 : reinterpret_cast<char*>(dst.Elements()), written, &streamWritten);
120 : }
121 :
122 : NS_IMETHODIMP
123 0 : nsConverterOutputStream::Close()
124 : {
125 0 : if (!mOutStream)
126 0 : return NS_OK; // Already closed.
127 :
128 0 : nsresult rv1 = Flush();
129 :
130 0 : nsresult rv2 = mOutStream->Close();
131 0 : mOutStream = nullptr;
132 0 : mConverter = nullptr;
133 0 : return NS_FAILED(rv1) ? rv1 : rv2;
134 : }
135 :
|