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/. */
8 #include "nsIOutputStream.h"
11 #include "nsConverterOutputStream.h"
12 #include "nsIUnicodeEncoder.h"
13 #include "mozilla/dom/EncodingUtils.h"
15 using mozilla::dom::EncodingUtils
;
17 NS_IMPL_ISUPPORTS(nsConverterOutputStream
,
18 nsIUnicharOutputStream
,
19 nsIConverterOutputStream
)
21 nsConverterOutputStream::~nsConverterOutputStream()
27 nsConverterOutputStream::Init(nsIOutputStream
* aOutStream
,
29 uint32_t aBufferSize
/* ignored */,
30 char16_t aReplacementChar
)
32 NS_PRECONDITION(aOutStream
, "Null output stream!");
36 label
.AssignLiteral("UTF-8");
41 nsAutoCString encoding
;
42 if (label
.EqualsLiteral("UTF-16")) {
43 // Make sure to output a BOM when UTF-16 requested
44 encoding
.Assign(label
);
45 } else if (!EncodingUtils::FindEncodingForLabelNoReplacement(label
,
47 return NS_ERROR_UCONV_NOCONV
;
49 mConverter
= EncodingUtils::EncoderForEncoding(encoding
);
51 mOutStream
= aOutStream
;
53 int32_t behaviour
= aReplacementChar
? nsIUnicodeEncoder::kOnError_Replace
54 : nsIUnicodeEncoder::kOnError_Signal
;
56 SetOutputErrorBehavior(behaviour
,
62 nsConverterOutputStream::Write(uint32_t aCount
, const char16_t
* aChars
,
66 NS_ASSERTION(!mConverter
, "Closed streams shouldn't have converters");
67 return NS_BASE_STREAM_CLOSED
;
69 NS_ASSERTION(mConverter
, "Must have a converter when not closed");
71 int32_t inLen
= aCount
;
74 nsresult rv
= mConverter
->GetMaxLength(aChars
, inLen
, &maxLen
);
75 NS_ENSURE_SUCCESS(rv
, rv
);
78 buf
.SetLength(maxLen
);
79 if (buf
.Length() != (uint32_t) maxLen
)
80 return NS_ERROR_OUT_OF_MEMORY
;
82 int32_t outLen
= maxLen
;
83 rv
= mConverter
->Convert(aChars
, &inLen
, buf
.BeginWriting(), &outLen
);
86 if (rv
== NS_ERROR_UENC_NOMAPPING
) {
87 // Yes, NS_ERROR_UENC_NOMAPPING is a success code
88 return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA
;
90 NS_ASSERTION((uint32_t) inLen
== aCount
,
91 "Converter didn't consume all the data!");
94 rv
= mOutStream
->Write(buf
.get(), outLen
, &written
);
95 *aSuccess
= NS_SUCCEEDED(rv
) && written
== uint32_t(outLen
);
101 nsConverterOutputStream::WriteString(const nsAString
& aString
, bool* aSuccess
)
103 int32_t inLen
= aString
.Length();
104 nsAString::const_iterator i
;
105 aString
.BeginReading(i
);
106 return Write(inLen
, i
.get(), aSuccess
);
110 nsConverterOutputStream::Flush()
113 return NS_OK
; // Already closed.
116 int32_t size
= sizeof(buf
);
117 nsresult rv
= mConverter
->Finish(buf
, &size
);
118 NS_ASSERTION(rv
!= NS_OK_UENC_MOREOUTPUT
,
119 "1024 bytes ought to be enough for everyone");
126 rv
= mOutStream
->Write(buf
, size
, &written
);
128 NS_WARNING("Flush() lost data!");
131 if (written
!= uint32_t(size
)) {
132 NS_WARNING("Flush() lost data!");
133 return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA
;
139 nsConverterOutputStream::Close()
142 return NS_OK
; // Already closed.
144 nsresult rv1
= Flush();
146 nsresult rv2
= mOutStream
->Close();
147 mOutStream
= nullptr;
148 mConverter
= nullptr;
149 return NS_FAILED(rv1
) ? rv1
: rv2
;