|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
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 "nsString.h" |
|
7 #include "nsICharsetConverterManager.h" |
|
8 #include "nsIScriptableUConv.h" |
|
9 #include "nsScriptableUConv.h" |
|
10 #include "nsIStringStream.h" |
|
11 #include "nsComponentManagerUtils.h" |
|
12 #include "nsCharsetAlias.h" |
|
13 #include "nsServiceManagerUtils.h" |
|
14 |
|
15 /* Implementation file */ |
|
16 NS_IMPL_ISUPPORTS(nsScriptableUnicodeConverter, nsIScriptableUnicodeConverter) |
|
17 |
|
18 nsScriptableUnicodeConverter::nsScriptableUnicodeConverter() |
|
19 : mIsInternal(false) |
|
20 { |
|
21 } |
|
22 |
|
23 nsScriptableUnicodeConverter::~nsScriptableUnicodeConverter() |
|
24 { |
|
25 } |
|
26 |
|
27 nsresult |
|
28 nsScriptableUnicodeConverter::ConvertFromUnicodeWithLength(const nsAString& aSrc, |
|
29 int32_t* aOutLen, |
|
30 char **_retval) |
|
31 { |
|
32 if (!mEncoder) |
|
33 return NS_ERROR_FAILURE; |
|
34 |
|
35 nsresult rv = NS_OK; |
|
36 int32_t inLength = aSrc.Length(); |
|
37 const nsAFlatString& flatSrc = PromiseFlatString(aSrc); |
|
38 rv = mEncoder->GetMaxLength(flatSrc.get(), inLength, aOutLen); |
|
39 if (NS_SUCCEEDED(rv)) { |
|
40 *_retval = (char*)moz_malloc(*aOutLen+1); |
|
41 if (!*_retval) |
|
42 return NS_ERROR_OUT_OF_MEMORY; |
|
43 |
|
44 rv = mEncoder->Convert(flatSrc.get(), &inLength, *_retval, aOutLen); |
|
45 if (NS_SUCCEEDED(rv)) |
|
46 { |
|
47 (*_retval)[*aOutLen] = '\0'; |
|
48 return NS_OK; |
|
49 } |
|
50 moz_free(*_retval); |
|
51 } |
|
52 *_retval = nullptr; |
|
53 return NS_ERROR_FAILURE; |
|
54 } |
|
55 |
|
56 /* ACString ConvertFromUnicode (in AString src); */ |
|
57 NS_IMETHODIMP |
|
58 nsScriptableUnicodeConverter::ConvertFromUnicode(const nsAString& aSrc, |
|
59 nsACString& _retval) |
|
60 { |
|
61 int32_t len; |
|
62 char* str; |
|
63 nsresult rv = ConvertFromUnicodeWithLength(aSrc, &len, &str); |
|
64 if (NS_SUCCEEDED(rv)) { |
|
65 // No Adopt on nsACString :( |
|
66 if (!_retval.Assign(str, len, mozilla::fallible_t())) { |
|
67 rv = NS_ERROR_OUT_OF_MEMORY; |
|
68 } |
|
69 moz_free(str); |
|
70 } |
|
71 return rv; |
|
72 } |
|
73 |
|
74 nsresult |
|
75 nsScriptableUnicodeConverter::FinishWithLength(char **_retval, int32_t* aLength) |
|
76 { |
|
77 if (!mEncoder) |
|
78 return NS_ERROR_FAILURE; |
|
79 |
|
80 int32_t finLength = 32; |
|
81 |
|
82 *_retval = (char *)moz_malloc(finLength); |
|
83 if (!*_retval) |
|
84 return NS_ERROR_OUT_OF_MEMORY; |
|
85 |
|
86 nsresult rv = mEncoder->Finish(*_retval, &finLength); |
|
87 if (NS_SUCCEEDED(rv)) |
|
88 *aLength = finLength; |
|
89 else |
|
90 moz_free(*_retval); |
|
91 |
|
92 return rv; |
|
93 |
|
94 } |
|
95 |
|
96 /* ACString Finish(); */ |
|
97 NS_IMETHODIMP |
|
98 nsScriptableUnicodeConverter::Finish(nsACString& _retval) |
|
99 { |
|
100 int32_t len; |
|
101 char* str; |
|
102 nsresult rv = FinishWithLength(&str, &len); |
|
103 if (NS_SUCCEEDED(rv)) { |
|
104 // No Adopt on nsACString :( |
|
105 if (!_retval.Assign(str, len, mozilla::fallible_t())) { |
|
106 rv = NS_ERROR_OUT_OF_MEMORY; |
|
107 } |
|
108 moz_free(str); |
|
109 } |
|
110 return rv; |
|
111 } |
|
112 |
|
113 /* AString ConvertToUnicode (in ACString src); */ |
|
114 NS_IMETHODIMP |
|
115 nsScriptableUnicodeConverter::ConvertToUnicode(const nsACString& aSrc, nsAString& _retval) |
|
116 { |
|
117 nsACString::const_iterator i; |
|
118 aSrc.BeginReading(i); |
|
119 return ConvertFromByteArray(reinterpret_cast<const uint8_t*>(i.get()), |
|
120 aSrc.Length(), |
|
121 _retval); |
|
122 } |
|
123 |
|
124 /* AString convertFromByteArray([const,array,size_is(aCount)] in octet aData, |
|
125 in unsigned long aCount); |
|
126 */ |
|
127 NS_IMETHODIMP |
|
128 nsScriptableUnicodeConverter::ConvertFromByteArray(const uint8_t* aData, |
|
129 uint32_t aCount, |
|
130 nsAString& _retval) |
|
131 { |
|
132 if (!mDecoder) |
|
133 return NS_ERROR_FAILURE; |
|
134 |
|
135 nsresult rv = NS_OK; |
|
136 int32_t inLength = aCount; |
|
137 int32_t outLength; |
|
138 rv = mDecoder->GetMaxLength(reinterpret_cast<const char*>(aData), |
|
139 inLength, &outLength); |
|
140 if (NS_SUCCEEDED(rv)) |
|
141 { |
|
142 char16_t* buf = (char16_t*)moz_malloc((outLength+1)*sizeof(char16_t)); |
|
143 if (!buf) |
|
144 return NS_ERROR_OUT_OF_MEMORY; |
|
145 |
|
146 rv = mDecoder->Convert(reinterpret_cast<const char*>(aData), |
|
147 &inLength, buf, &outLength); |
|
148 if (NS_SUCCEEDED(rv)) |
|
149 { |
|
150 buf[outLength] = 0; |
|
151 if (!_retval.Assign(buf, outLength, mozilla::fallible_t())) { |
|
152 rv = NS_ERROR_OUT_OF_MEMORY; |
|
153 } |
|
154 } |
|
155 moz_free(buf); |
|
156 return rv; |
|
157 } |
|
158 return NS_ERROR_FAILURE; |
|
159 |
|
160 } |
|
161 |
|
162 /* void convertToByteArray(in AString aString, |
|
163 [optional] out unsigned long aLen, |
|
164 [array, size_is(aLen),retval] out octet aData); |
|
165 */ |
|
166 NS_IMETHODIMP |
|
167 nsScriptableUnicodeConverter::ConvertToByteArray(const nsAString& aString, |
|
168 uint32_t* aLen, |
|
169 uint8_t** _aData) |
|
170 { |
|
171 char* data; |
|
172 int32_t len; |
|
173 nsresult rv = ConvertFromUnicodeWithLength(aString, &len, &data); |
|
174 if (NS_FAILED(rv)) |
|
175 return rv; |
|
176 nsXPIDLCString str; |
|
177 str.Adopt(data, len); // NOTE: This uses the XPIDLCString as a byte array |
|
178 |
|
179 rv = FinishWithLength(&data, &len); |
|
180 if (NS_FAILED(rv)) |
|
181 return rv; |
|
182 |
|
183 str.Append(data, len); |
|
184 moz_free(data); |
|
185 // NOTE: this being a byte array, it needs no null termination |
|
186 *_aData = reinterpret_cast<uint8_t*>(moz_malloc(str.Length())); |
|
187 if (!*_aData) |
|
188 return NS_ERROR_OUT_OF_MEMORY; |
|
189 memcpy(*_aData, str.get(), str.Length()); |
|
190 *aLen = str.Length(); |
|
191 return NS_OK; |
|
192 } |
|
193 |
|
194 /* nsIInputStream convertToInputStream(in AString aString); */ |
|
195 NS_IMETHODIMP |
|
196 nsScriptableUnicodeConverter::ConvertToInputStream(const nsAString& aString, |
|
197 nsIInputStream** _retval) |
|
198 { |
|
199 nsresult rv; |
|
200 nsCOMPtr<nsIStringInputStream> inputStream = |
|
201 do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv); |
|
202 if (NS_FAILED(rv)) |
|
203 return rv; |
|
204 |
|
205 uint8_t* data; |
|
206 uint32_t dataLen; |
|
207 rv = ConvertToByteArray(aString, &dataLen, &data); |
|
208 if (NS_FAILED(rv)) |
|
209 return rv; |
|
210 |
|
211 rv = inputStream->AdoptData(reinterpret_cast<char*>(data), dataLen); |
|
212 if (NS_FAILED(rv)) { |
|
213 moz_free(data); |
|
214 return rv; |
|
215 } |
|
216 |
|
217 NS_ADDREF(*_retval = inputStream); |
|
218 return rv; |
|
219 } |
|
220 |
|
221 /* attribute string charset; */ |
|
222 NS_IMETHODIMP |
|
223 nsScriptableUnicodeConverter::GetCharset(char * *aCharset) |
|
224 { |
|
225 *aCharset = ToNewCString(mCharset); |
|
226 if (!*aCharset) |
|
227 return NS_ERROR_OUT_OF_MEMORY; |
|
228 |
|
229 return NS_OK; |
|
230 } |
|
231 |
|
232 NS_IMETHODIMP |
|
233 nsScriptableUnicodeConverter::SetCharset(const char * aCharset) |
|
234 { |
|
235 mCharset.Assign(aCharset); |
|
236 return InitConverter(); |
|
237 } |
|
238 |
|
239 NS_IMETHODIMP |
|
240 nsScriptableUnicodeConverter::GetIsInternal(bool *aIsInternal) |
|
241 { |
|
242 *aIsInternal = mIsInternal; |
|
243 return NS_OK; |
|
244 } |
|
245 |
|
246 NS_IMETHODIMP |
|
247 nsScriptableUnicodeConverter::SetIsInternal(const bool aIsInternal) |
|
248 { |
|
249 mIsInternal = aIsInternal; |
|
250 return NS_OK; |
|
251 } |
|
252 |
|
253 nsresult |
|
254 nsScriptableUnicodeConverter::InitConverter() |
|
255 { |
|
256 nsresult rv = NS_OK; |
|
257 mEncoder = nullptr; |
|
258 |
|
259 nsCOMPtr<nsICharsetConverterManager> ccm = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv); |
|
260 if (NS_FAILED(rv) || !ccm) { |
|
261 return rv; |
|
262 } |
|
263 |
|
264 // get an unicode converter |
|
265 rv = ccm->GetUnicodeEncoder(mCharset.get(), getter_AddRefs(mEncoder)); |
|
266 if (NS_FAILED(rv)) { |
|
267 return rv; |
|
268 } |
|
269 |
|
270 rv = mEncoder->SetOutputErrorBehavior(nsIUnicodeEncoder::kOnError_Replace, nullptr, (char16_t)'?'); |
|
271 if (NS_FAILED(rv)) { |
|
272 return rv; |
|
273 } |
|
274 |
|
275 nsAutoCString charset; |
|
276 rv = mIsInternal ? nsCharsetAlias::GetPreferredInternal(mCharset, charset) |
|
277 : nsCharsetAlias::GetPreferred(mCharset, charset); |
|
278 if (NS_FAILED(rv)) { |
|
279 return rv; |
|
280 } |
|
281 |
|
282 rv = ccm->GetUnicodeDecoderRaw(charset.get(), getter_AddRefs(mDecoder)); |
|
283 if (NS_FAILED(rv)) { |
|
284 return rv; |
|
285 } |
|
286 |
|
287 // The UTF-8 decoder used to throw regardless of the error behavior. |
|
288 // Simulating the old behavior for compatibility with legacy callers |
|
289 // (including addons). If callers want a control over the behavior, |
|
290 // they should switch to TextDecoder. |
|
291 if (charset.EqualsLiteral("UTF-8")) { |
|
292 mDecoder->SetInputErrorBehavior(nsIUnicodeDecoder::kOnError_Signal); |
|
293 } |
|
294 |
|
295 return rv ; |
|
296 } |