/src/mozilla-central/intl/uconv/nsConverterOutputStream.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | NS_IMPL_ISUPPORTS(nsConverterOutputStream, |
18 | | nsIUnicharOutputStream, |
19 | | nsIConverterOutputStream) |
20 | | |
21 | | nsConverterOutputStream::~nsConverterOutputStream() |
22 | 0 | { |
23 | 0 | Close(); |
24 | 0 | } |
25 | | |
26 | | NS_IMETHODIMP |
27 | | nsConverterOutputStream::Init(nsIOutputStream* aOutStream, |
28 | | const char* aCharset) |
29 | 0 | { |
30 | 0 | MOZ_ASSERT(aOutStream, "Null output stream!"); |
31 | 0 |
|
32 | 0 | const Encoding* encoding; |
33 | 0 | if (!aCharset) { |
34 | 0 | encoding = UTF_8_ENCODING; |
35 | 0 | } 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 | 0 | } |
41 | 0 | } |
42 | 0 | |
43 | 0 | mConverter = encoding->NewEncoder(); |
44 | 0 |
|
45 | 0 | mOutStream = aOutStream; |
46 | 0 |
|
47 | 0 | return NS_OK; |
48 | 0 | } |
49 | | |
50 | | NS_IMETHODIMP |
51 | | nsConverterOutputStream::Write(uint32_t aCount, const char16_t* aChars, |
52 | | bool* aSuccess) |
53 | 0 | { |
54 | 0 | if (!mOutStream) { |
55 | 0 | NS_ASSERTION(!mConverter, "Closed streams shouldn't have converters"); |
56 | 0 | return NS_BASE_STREAM_CLOSED; |
57 | 0 | } |
58 | 0 | MOZ_ASSERT(mConverter, "Must have a converter when not closed"); |
59 | 0 | uint8_t buffer[4096]; |
60 | 0 | auto dst = MakeSpan(buffer); |
61 | 0 | auto src = MakeSpan(aChars, aCount); |
62 | 0 | for (;;) { |
63 | 0 | uint32_t result; |
64 | 0 | size_t read; |
65 | 0 | size_t written; |
66 | 0 | bool hadErrors; |
67 | 0 | Tie(result, read, written, hadErrors) = |
68 | 0 | mConverter->EncodeFromUTF16(src, dst, false); |
69 | 0 | Unused << hadErrors; |
70 | 0 | src = src.From(read); |
71 | 0 | 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 | 0 | } |
78 | 0 | if (result == kInputEmpty) { |
79 | 0 | return NS_OK; |
80 | 0 | } |
81 | 0 | } |
82 | 0 | } |
83 | | |
84 | | NS_IMETHODIMP |
85 | | nsConverterOutputStream::WriteString(const nsAString& aString, bool* aSuccess) |
86 | 0 | { |
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 | 0 | } |
92 | | |
93 | | NS_IMETHODIMP |
94 | | nsConverterOutputStream::Flush() |
95 | 0 | { |
96 | 0 | if (!mOutStream) |
97 | 0 | return NS_OK; // Already closed. |
98 | 0 | |
99 | 0 | // If we are encoding to ISO-2022-JP, potentially |
100 | 0 | // transition back to the ASCII state. The buffer |
101 | 0 | // needs to be large enough for an additional NCR, |
102 | 0 | // though. |
103 | 0 | uint8_t buffer[12]; |
104 | 0 | auto dst = MakeSpan(buffer); |
105 | 0 | Span<char16_t> src(nullptr); |
106 | 0 | uint32_t result; |
107 | 0 | size_t read; |
108 | 0 | size_t written; |
109 | 0 | bool hadErrors; |
110 | 0 | Tie(result, read, written, hadErrors) = |
111 | 0 | mConverter->EncodeFromUTF16(src, dst, true); |
112 | 0 | Unused << hadErrors; |
113 | 0 | MOZ_ASSERT(result == kInputEmpty); |
114 | 0 | uint32_t streamWritten; |
115 | 0 | if (!written) { |
116 | 0 | return NS_OK; |
117 | 0 | } |
118 | 0 | return mOutStream->Write( |
119 | 0 | reinterpret_cast<char*>(dst.Elements()), written, &streamWritten); |
120 | 0 | } |
121 | | |
122 | | NS_IMETHODIMP |
123 | | nsConverterOutputStream::Close() |
124 | 0 | { |
125 | 0 | if (!mOutStream) |
126 | 0 | return NS_OK; // Already closed. |
127 | 0 | |
128 | 0 | nsresult rv1 = Flush(); |
129 | 0 |
|
130 | 0 | nsresult rv2 = mOutStream->Close(); |
131 | 0 | mOutStream = nullptr; |
132 | 0 | mConverter = nullptr; |
133 | 0 | return NS_FAILED(rv1) ? rv1 : rv2; |
134 | 0 | } |