Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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/. */
6 #include "nsCOMPtr.h"
7 #include "nsString.h"
8 #include "nsUnicharUtils.h"
9 #include "nsCharsetAlias.h"
10 #include "nsICategoryManager.h"
11 #include "nsICharsetConverterManager.h"
12 #include "nsEncoderDecoderUtils.h"
13 #include "nsIStringBundle.h"
14 #include "nsTArray.h"
15 #include "nsStringEnumerator.h"
16 #include "mozilla/Services.h"
18 #include "nsComponentManagerUtils.h"
19 #include "nsISupportsPrimitives.h"
20 #include "nsServiceManagerUtils.h"
22 // just for CONTRACTIDs
23 #include "nsCharsetConverterManager.h"
25 static nsIStringBundle * sDataBundle;
26 static nsIStringBundle * sTitleBundle;
28 // Class nsCharsetConverterManager [implementation]
30 NS_IMPL_ISUPPORTS(nsCharsetConverterManager, nsICharsetConverterManager)
32 nsCharsetConverterManager::nsCharsetConverterManager()
33 {
34 }
36 nsCharsetConverterManager::~nsCharsetConverterManager()
37 {
38 }
40 //static
41 void nsCharsetConverterManager::Shutdown()
42 {
43 NS_IF_RELEASE(sDataBundle);
44 NS_IF_RELEASE(sTitleBundle);
45 }
47 static
48 nsresult LoadExtensibleBundle(const char* aCategory,
49 nsIStringBundle ** aResult)
50 {
51 nsCOMPtr<nsIStringBundleService> sbServ =
52 mozilla::services::GetStringBundleService();
53 if (!sbServ)
54 return NS_ERROR_FAILURE;
56 return sbServ->CreateExtensibleBundle(aCategory, aResult);
57 }
59 static
60 nsresult GetBundleValue(nsIStringBundle * aBundle,
61 const char * aName,
62 const nsAFlatString& aProp,
63 char16_t ** aResult)
64 {
65 nsAutoString key;
67 key.AssignWithConversion(aName);
68 ToLowerCase(key); // we lowercase the main comparison key
69 key.Append(aProp);
71 return aBundle->GetStringFromName(key.get(), aResult);
72 }
74 static
75 nsresult GetBundleValue(nsIStringBundle * aBundle,
76 const char * aName,
77 const nsAFlatString& aProp,
78 nsAString& aResult)
79 {
80 nsresult rv = NS_OK;
82 nsXPIDLString value;
83 rv = GetBundleValue(aBundle, aName, aProp, getter_Copies(value));
84 if (NS_FAILED(rv))
85 return rv;
87 aResult = value;
89 return NS_OK;
90 }
92 static
93 nsresult GetCharsetDataImpl(const char * aCharset, const char16_t * aProp,
94 nsAString& aResult)
95 {
96 NS_ENSURE_ARG_POINTER(aCharset);
97 // aProp can be nullptr
99 if (!sDataBundle) {
100 nsresult rv = LoadExtensibleBundle(NS_DATA_BUNDLE_CATEGORY, &sDataBundle);
101 if (NS_FAILED(rv))
102 return rv;
103 }
105 return GetBundleValue(sDataBundle, aCharset, nsDependentString(aProp), aResult);
106 }
108 //static
109 bool nsCharsetConverterManager::IsInternal(const nsACString& aCharset)
110 {
111 nsAutoString str;
112 // fully qualify to possibly avoid vtable call
113 nsresult rv = GetCharsetDataImpl(PromiseFlatCString(aCharset).get(),
114 MOZ_UTF16(".isInternal"),
115 str);
117 return NS_SUCCEEDED(rv);
118 }
121 //----------------------------------------------------------------------------//----------------------------------------------------------------------------
122 // Interface nsICharsetConverterManager [implementation]
124 NS_IMETHODIMP
125 nsCharsetConverterManager::GetUnicodeEncoder(const char * aDest,
126 nsIUnicodeEncoder ** aResult)
127 {
128 // resolve the charset first
129 nsAutoCString charset;
131 // fully qualify to possibly avoid vtable call
132 nsCharsetConverterManager::GetCharsetAlias(aDest, charset);
134 return nsCharsetConverterManager::GetUnicodeEncoderRaw(charset.get(),
135 aResult);
136 }
139 NS_IMETHODIMP
140 nsCharsetConverterManager::GetUnicodeEncoderRaw(const char * aDest,
141 nsIUnicodeEncoder ** aResult)
142 {
143 *aResult= nullptr;
144 nsCOMPtr<nsIUnicodeEncoder> encoder;
146 nsresult rv = NS_OK;
148 nsAutoCString
149 contractid(NS_LITERAL_CSTRING(NS_UNICODEENCODER_CONTRACTID_BASE) +
150 nsDependentCString(aDest));
152 // Always create an instance since encoders hold state.
153 encoder = do_CreateInstance(contractid.get(), &rv);
155 if (NS_FAILED(rv))
156 rv = NS_ERROR_UCONV_NOCONV;
157 else
158 {
159 *aResult = encoder.get();
160 NS_ADDREF(*aResult);
161 }
162 return rv;
163 }
165 NS_IMETHODIMP
166 nsCharsetConverterManager::GetUnicodeDecoder(const char * aSrc,
167 nsIUnicodeDecoder ** aResult)
168 {
169 // resolve the charset first
170 nsAutoCString charset;
172 // fully qualify to possibly avoid vtable call
173 if (NS_FAILED(nsCharsetConverterManager::GetCharsetAlias(aSrc, charset)))
174 return NS_ERROR_UCONV_NOCONV;
176 return nsCharsetConverterManager::GetUnicodeDecoderRaw(charset.get(),
177 aResult);
178 }
180 NS_IMETHODIMP
181 nsCharsetConverterManager::GetUnicodeDecoderInternal(const char * aSrc,
182 nsIUnicodeDecoder ** aResult)
183 {
184 // resolve the charset first
185 nsAutoCString charset;
187 nsresult rv = nsCharsetAlias::GetPreferredInternal(nsDependentCString(aSrc),
188 charset);
189 NS_ENSURE_SUCCESS(rv, rv);
191 return nsCharsetConverterManager::GetUnicodeDecoderRaw(charset.get(),
192 aResult);
193 }
195 NS_IMETHODIMP
196 nsCharsetConverterManager::GetUnicodeDecoderRaw(const char * aSrc,
197 nsIUnicodeDecoder ** aResult)
198 {
199 *aResult= nullptr;
200 nsCOMPtr<nsIUnicodeDecoder> decoder;
202 nsresult rv = NS_OK;
204 NS_NAMED_LITERAL_CSTRING(contractbase, NS_UNICODEDECODER_CONTRACTID_BASE);
205 nsDependentCString src(aSrc);
207 decoder = do_CreateInstance(PromiseFlatCString(contractbase + src).get(),
208 &rv);
209 NS_ENSURE_SUCCESS(rv, NS_ERROR_UCONV_NOCONV);
211 decoder.forget(aResult);
212 return rv;
213 }
215 static
216 nsresult GetList(const nsACString& aCategory,
217 const nsACString& aPrefix,
218 nsIUTF8StringEnumerator** aResult)
219 {
220 NS_ENSURE_ARG_POINTER(aResult);
221 *aResult = nullptr;
223 nsresult rv;
225 nsCOMPtr<nsICategoryManager> catman = do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
226 if (NS_FAILED(rv))
227 return rv;
229 nsTArray<nsCString>* array = new nsTArray<nsCString>;
230 if (!array)
231 return NS_ERROR_OUT_OF_MEMORY;
233 nsCOMPtr<nsISimpleEnumerator> enumerator;
234 catman->EnumerateCategory(PromiseFlatCString(aCategory).get(),
235 getter_AddRefs(enumerator));
237 bool hasMore;
238 while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore) {
239 nsCOMPtr<nsISupports> supports;
240 if (NS_FAILED(enumerator->GetNext(getter_AddRefs(supports))))
241 continue;
243 nsCOMPtr<nsISupportsCString> supStr = do_QueryInterface(supports);
244 if (!supStr)
245 continue;
247 nsAutoCString name;
248 if (NS_FAILED(supStr->GetData(name)))
249 continue;
251 nsAutoCString fullName(aPrefix);
252 fullName.Append(name);
253 NS_ENSURE_TRUE(array->AppendElement(fullName), NS_ERROR_OUT_OF_MEMORY);
254 }
256 return NS_NewAdoptingUTF8StringEnumerator(aResult, array);
257 }
259 // we should change the interface so that we can just pass back a enumerator!
260 NS_IMETHODIMP
261 nsCharsetConverterManager::GetDecoderList(nsIUTF8StringEnumerator ** aResult)
262 {
263 return GetList(NS_LITERAL_CSTRING(NS_UNICODEDECODER_NAME),
264 EmptyCString(), aResult);
265 }
267 NS_IMETHODIMP
268 nsCharsetConverterManager::GetEncoderList(nsIUTF8StringEnumerator ** aResult)
269 {
270 return GetList(NS_LITERAL_CSTRING(NS_UNICODEENCODER_NAME),
271 EmptyCString(), aResult);
272 }
274 NS_IMETHODIMP
275 nsCharsetConverterManager::GetCharsetDetectorList(nsIUTF8StringEnumerator** aResult)
276 {
277 return GetList(NS_LITERAL_CSTRING("charset-detectors"),
278 NS_LITERAL_CSTRING("chardet."), aResult);
279 }
281 // XXX Improve the implementation of this method. Right now, it is build on
282 // top of the nsCharsetAlias service. We can make the nsCharsetAlias
283 // better, with its own hash table (not the StringBundle anymore) and
284 // a nicer file format.
285 NS_IMETHODIMP
286 nsCharsetConverterManager::GetCharsetAlias(const char * aCharset,
287 nsACString& aResult)
288 {
289 NS_ENSURE_ARG_POINTER(aCharset);
291 // We try to obtain the preferred name for this charset from the charset
292 // aliases.
293 nsresult rv;
295 rv = nsCharsetAlias::GetPreferred(nsDependentCString(aCharset), aResult);
296 NS_ENSURE_SUCCESS(rv, rv);
298 return NS_OK;
299 }
302 NS_IMETHODIMP
303 nsCharsetConverterManager::GetCharsetTitle(const char * aCharset,
304 nsAString& aResult)
305 {
306 NS_ENSURE_ARG_POINTER(aCharset);
308 if (!sTitleBundle) {
309 nsresult rv = LoadExtensibleBundle(NS_TITLE_BUNDLE_CATEGORY, &sTitleBundle);
310 NS_ENSURE_SUCCESS(rv, rv);
311 }
313 return GetBundleValue(sTitleBundle, aCharset, NS_LITERAL_STRING(".title"), aResult);
314 }
316 NS_IMETHODIMP
317 nsCharsetConverterManager::GetCharsetData(const char * aCharset,
318 const char16_t * aProp,
319 nsAString& aResult)
320 {
321 return GetCharsetDataImpl(aCharset, aProp, aResult);
322 }
324 NS_IMETHODIMP
325 nsCharsetConverterManager::GetCharsetLangGroup(const char * aCharset,
326 nsIAtom** aResult)
327 {
328 // resolve the charset first
329 nsAutoCString charset;
331 nsresult rv = GetCharsetAlias(aCharset, charset);
332 NS_ENSURE_SUCCESS(rv, rv);
334 // fully qualify to possibly avoid vtable call
335 return nsCharsetConverterManager::GetCharsetLangGroupRaw(charset.get(),
336 aResult);
337 }
339 NS_IMETHODIMP
340 nsCharsetConverterManager::GetCharsetLangGroupRaw(const char * aCharset,
341 nsIAtom** aResult)
342 {
344 *aResult = nullptr;
345 nsAutoString langGroup;
346 // fully qualify to possibly avoid vtable call
347 nsresult rv = nsCharsetConverterManager::GetCharsetData(
348 aCharset, MOZ_UTF16(".LangGroup"), langGroup);
350 if (NS_SUCCEEDED(rv)) {
351 ToLowerCase(langGroup); // use lowercase for all language atoms
352 *aResult = NS_NewAtom(langGroup).take();
353 }
355 return rv;
356 }