1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/uconv/src/nsCharsetConverterManager.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,356 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsCOMPtr.h" 1.10 +#include "nsString.h" 1.11 +#include "nsUnicharUtils.h" 1.12 +#include "nsCharsetAlias.h" 1.13 +#include "nsICategoryManager.h" 1.14 +#include "nsICharsetConverterManager.h" 1.15 +#include "nsEncoderDecoderUtils.h" 1.16 +#include "nsIStringBundle.h" 1.17 +#include "nsTArray.h" 1.18 +#include "nsStringEnumerator.h" 1.19 +#include "mozilla/Services.h" 1.20 + 1.21 +#include "nsComponentManagerUtils.h" 1.22 +#include "nsISupportsPrimitives.h" 1.23 +#include "nsServiceManagerUtils.h" 1.24 + 1.25 +// just for CONTRACTIDs 1.26 +#include "nsCharsetConverterManager.h" 1.27 + 1.28 +static nsIStringBundle * sDataBundle; 1.29 +static nsIStringBundle * sTitleBundle; 1.30 + 1.31 +// Class nsCharsetConverterManager [implementation] 1.32 + 1.33 +NS_IMPL_ISUPPORTS(nsCharsetConverterManager, nsICharsetConverterManager) 1.34 + 1.35 +nsCharsetConverterManager::nsCharsetConverterManager() 1.36 +{ 1.37 +} 1.38 + 1.39 +nsCharsetConverterManager::~nsCharsetConverterManager() 1.40 +{ 1.41 +} 1.42 + 1.43 +//static 1.44 +void nsCharsetConverterManager::Shutdown() 1.45 +{ 1.46 + NS_IF_RELEASE(sDataBundle); 1.47 + NS_IF_RELEASE(sTitleBundle); 1.48 +} 1.49 + 1.50 +static 1.51 +nsresult LoadExtensibleBundle(const char* aCategory, 1.52 + nsIStringBundle ** aResult) 1.53 +{ 1.54 + nsCOMPtr<nsIStringBundleService> sbServ = 1.55 + mozilla::services::GetStringBundleService(); 1.56 + if (!sbServ) 1.57 + return NS_ERROR_FAILURE; 1.58 + 1.59 + return sbServ->CreateExtensibleBundle(aCategory, aResult); 1.60 +} 1.61 + 1.62 +static 1.63 +nsresult GetBundleValue(nsIStringBundle * aBundle, 1.64 + const char * aName, 1.65 + const nsAFlatString& aProp, 1.66 + char16_t ** aResult) 1.67 +{ 1.68 + nsAutoString key; 1.69 + 1.70 + key.AssignWithConversion(aName); 1.71 + ToLowerCase(key); // we lowercase the main comparison key 1.72 + key.Append(aProp); 1.73 + 1.74 + return aBundle->GetStringFromName(key.get(), aResult); 1.75 +} 1.76 + 1.77 +static 1.78 +nsresult GetBundleValue(nsIStringBundle * aBundle, 1.79 + const char * aName, 1.80 + const nsAFlatString& aProp, 1.81 + nsAString& aResult) 1.82 +{ 1.83 + nsresult rv = NS_OK; 1.84 + 1.85 + nsXPIDLString value; 1.86 + rv = GetBundleValue(aBundle, aName, aProp, getter_Copies(value)); 1.87 + if (NS_FAILED(rv)) 1.88 + return rv; 1.89 + 1.90 + aResult = value; 1.91 + 1.92 + return NS_OK; 1.93 +} 1.94 + 1.95 +static 1.96 +nsresult GetCharsetDataImpl(const char * aCharset, const char16_t * aProp, 1.97 + nsAString& aResult) 1.98 +{ 1.99 + NS_ENSURE_ARG_POINTER(aCharset); 1.100 + // aProp can be nullptr 1.101 + 1.102 + if (!sDataBundle) { 1.103 + nsresult rv = LoadExtensibleBundle(NS_DATA_BUNDLE_CATEGORY, &sDataBundle); 1.104 + if (NS_FAILED(rv)) 1.105 + return rv; 1.106 + } 1.107 + 1.108 + return GetBundleValue(sDataBundle, aCharset, nsDependentString(aProp), aResult); 1.109 +} 1.110 + 1.111 +//static 1.112 +bool nsCharsetConverterManager::IsInternal(const nsACString& aCharset) 1.113 +{ 1.114 + nsAutoString str; 1.115 + // fully qualify to possibly avoid vtable call 1.116 + nsresult rv = GetCharsetDataImpl(PromiseFlatCString(aCharset).get(), 1.117 + MOZ_UTF16(".isInternal"), 1.118 + str); 1.119 + 1.120 + return NS_SUCCEEDED(rv); 1.121 +} 1.122 + 1.123 + 1.124 +//----------------------------------------------------------------------------//---------------------------------------------------------------------------- 1.125 +// Interface nsICharsetConverterManager [implementation] 1.126 + 1.127 +NS_IMETHODIMP 1.128 +nsCharsetConverterManager::GetUnicodeEncoder(const char * aDest, 1.129 + nsIUnicodeEncoder ** aResult) 1.130 +{ 1.131 + // resolve the charset first 1.132 + nsAutoCString charset; 1.133 + 1.134 + // fully qualify to possibly avoid vtable call 1.135 + nsCharsetConverterManager::GetCharsetAlias(aDest, charset); 1.136 + 1.137 + return nsCharsetConverterManager::GetUnicodeEncoderRaw(charset.get(), 1.138 + aResult); 1.139 +} 1.140 + 1.141 + 1.142 +NS_IMETHODIMP 1.143 +nsCharsetConverterManager::GetUnicodeEncoderRaw(const char * aDest, 1.144 + nsIUnicodeEncoder ** aResult) 1.145 +{ 1.146 + *aResult= nullptr; 1.147 + nsCOMPtr<nsIUnicodeEncoder> encoder; 1.148 + 1.149 + nsresult rv = NS_OK; 1.150 + 1.151 + nsAutoCString 1.152 + contractid(NS_LITERAL_CSTRING(NS_UNICODEENCODER_CONTRACTID_BASE) + 1.153 + nsDependentCString(aDest)); 1.154 + 1.155 + // Always create an instance since encoders hold state. 1.156 + encoder = do_CreateInstance(contractid.get(), &rv); 1.157 + 1.158 + if (NS_FAILED(rv)) 1.159 + rv = NS_ERROR_UCONV_NOCONV; 1.160 + else 1.161 + { 1.162 + *aResult = encoder.get(); 1.163 + NS_ADDREF(*aResult); 1.164 + } 1.165 + return rv; 1.166 +} 1.167 + 1.168 +NS_IMETHODIMP 1.169 +nsCharsetConverterManager::GetUnicodeDecoder(const char * aSrc, 1.170 + nsIUnicodeDecoder ** aResult) 1.171 +{ 1.172 + // resolve the charset first 1.173 + nsAutoCString charset; 1.174 + 1.175 + // fully qualify to possibly avoid vtable call 1.176 + if (NS_FAILED(nsCharsetConverterManager::GetCharsetAlias(aSrc, charset))) 1.177 + return NS_ERROR_UCONV_NOCONV; 1.178 + 1.179 + return nsCharsetConverterManager::GetUnicodeDecoderRaw(charset.get(), 1.180 + aResult); 1.181 +} 1.182 + 1.183 +NS_IMETHODIMP 1.184 +nsCharsetConverterManager::GetUnicodeDecoderInternal(const char * aSrc, 1.185 + nsIUnicodeDecoder ** aResult) 1.186 +{ 1.187 + // resolve the charset first 1.188 + nsAutoCString charset; 1.189 + 1.190 + nsresult rv = nsCharsetAlias::GetPreferredInternal(nsDependentCString(aSrc), 1.191 + charset); 1.192 + NS_ENSURE_SUCCESS(rv, rv); 1.193 + 1.194 + return nsCharsetConverterManager::GetUnicodeDecoderRaw(charset.get(), 1.195 + aResult); 1.196 +} 1.197 + 1.198 +NS_IMETHODIMP 1.199 +nsCharsetConverterManager::GetUnicodeDecoderRaw(const char * aSrc, 1.200 + nsIUnicodeDecoder ** aResult) 1.201 +{ 1.202 + *aResult= nullptr; 1.203 + nsCOMPtr<nsIUnicodeDecoder> decoder; 1.204 + 1.205 + nsresult rv = NS_OK; 1.206 + 1.207 + NS_NAMED_LITERAL_CSTRING(contractbase, NS_UNICODEDECODER_CONTRACTID_BASE); 1.208 + nsDependentCString src(aSrc); 1.209 + 1.210 + decoder = do_CreateInstance(PromiseFlatCString(contractbase + src).get(), 1.211 + &rv); 1.212 + NS_ENSURE_SUCCESS(rv, NS_ERROR_UCONV_NOCONV); 1.213 + 1.214 + decoder.forget(aResult); 1.215 + return rv; 1.216 +} 1.217 + 1.218 +static 1.219 +nsresult GetList(const nsACString& aCategory, 1.220 + const nsACString& aPrefix, 1.221 + nsIUTF8StringEnumerator** aResult) 1.222 +{ 1.223 + NS_ENSURE_ARG_POINTER(aResult); 1.224 + *aResult = nullptr; 1.225 + 1.226 + nsresult rv; 1.227 + 1.228 + nsCOMPtr<nsICategoryManager> catman = do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv); 1.229 + if (NS_FAILED(rv)) 1.230 + return rv; 1.231 + 1.232 + nsTArray<nsCString>* array = new nsTArray<nsCString>; 1.233 + if (!array) 1.234 + return NS_ERROR_OUT_OF_MEMORY; 1.235 + 1.236 + nsCOMPtr<nsISimpleEnumerator> enumerator; 1.237 + catman->EnumerateCategory(PromiseFlatCString(aCategory).get(), 1.238 + getter_AddRefs(enumerator)); 1.239 + 1.240 + bool hasMore; 1.241 + while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore) { 1.242 + nsCOMPtr<nsISupports> supports; 1.243 + if (NS_FAILED(enumerator->GetNext(getter_AddRefs(supports)))) 1.244 + continue; 1.245 + 1.246 + nsCOMPtr<nsISupportsCString> supStr = do_QueryInterface(supports); 1.247 + if (!supStr) 1.248 + continue; 1.249 + 1.250 + nsAutoCString name; 1.251 + if (NS_FAILED(supStr->GetData(name))) 1.252 + continue; 1.253 + 1.254 + nsAutoCString fullName(aPrefix); 1.255 + fullName.Append(name); 1.256 + NS_ENSURE_TRUE(array->AppendElement(fullName), NS_ERROR_OUT_OF_MEMORY); 1.257 + } 1.258 + 1.259 + return NS_NewAdoptingUTF8StringEnumerator(aResult, array); 1.260 +} 1.261 + 1.262 +// we should change the interface so that we can just pass back a enumerator! 1.263 +NS_IMETHODIMP 1.264 +nsCharsetConverterManager::GetDecoderList(nsIUTF8StringEnumerator ** aResult) 1.265 +{ 1.266 + return GetList(NS_LITERAL_CSTRING(NS_UNICODEDECODER_NAME), 1.267 + EmptyCString(), aResult); 1.268 +} 1.269 + 1.270 +NS_IMETHODIMP 1.271 +nsCharsetConverterManager::GetEncoderList(nsIUTF8StringEnumerator ** aResult) 1.272 +{ 1.273 + return GetList(NS_LITERAL_CSTRING(NS_UNICODEENCODER_NAME), 1.274 + EmptyCString(), aResult); 1.275 +} 1.276 + 1.277 +NS_IMETHODIMP 1.278 +nsCharsetConverterManager::GetCharsetDetectorList(nsIUTF8StringEnumerator** aResult) 1.279 +{ 1.280 + return GetList(NS_LITERAL_CSTRING("charset-detectors"), 1.281 + NS_LITERAL_CSTRING("chardet."), aResult); 1.282 +} 1.283 + 1.284 +// XXX Improve the implementation of this method. Right now, it is build on 1.285 +// top of the nsCharsetAlias service. We can make the nsCharsetAlias 1.286 +// better, with its own hash table (not the StringBundle anymore) and 1.287 +// a nicer file format. 1.288 +NS_IMETHODIMP 1.289 +nsCharsetConverterManager::GetCharsetAlias(const char * aCharset, 1.290 + nsACString& aResult) 1.291 +{ 1.292 + NS_ENSURE_ARG_POINTER(aCharset); 1.293 + 1.294 + // We try to obtain the preferred name for this charset from the charset 1.295 + // aliases. 1.296 + nsresult rv; 1.297 + 1.298 + rv = nsCharsetAlias::GetPreferred(nsDependentCString(aCharset), aResult); 1.299 + NS_ENSURE_SUCCESS(rv, rv); 1.300 + 1.301 + return NS_OK; 1.302 +} 1.303 + 1.304 + 1.305 +NS_IMETHODIMP 1.306 +nsCharsetConverterManager::GetCharsetTitle(const char * aCharset, 1.307 + nsAString& aResult) 1.308 +{ 1.309 + NS_ENSURE_ARG_POINTER(aCharset); 1.310 + 1.311 + if (!sTitleBundle) { 1.312 + nsresult rv = LoadExtensibleBundle(NS_TITLE_BUNDLE_CATEGORY, &sTitleBundle); 1.313 + NS_ENSURE_SUCCESS(rv, rv); 1.314 + } 1.315 + 1.316 + return GetBundleValue(sTitleBundle, aCharset, NS_LITERAL_STRING(".title"), aResult); 1.317 +} 1.318 + 1.319 +NS_IMETHODIMP 1.320 +nsCharsetConverterManager::GetCharsetData(const char * aCharset, 1.321 + const char16_t * aProp, 1.322 + nsAString& aResult) 1.323 +{ 1.324 + return GetCharsetDataImpl(aCharset, aProp, aResult); 1.325 +} 1.326 + 1.327 +NS_IMETHODIMP 1.328 +nsCharsetConverterManager::GetCharsetLangGroup(const char * aCharset, 1.329 + nsIAtom** aResult) 1.330 +{ 1.331 + // resolve the charset first 1.332 + nsAutoCString charset; 1.333 + 1.334 + nsresult rv = GetCharsetAlias(aCharset, charset); 1.335 + NS_ENSURE_SUCCESS(rv, rv); 1.336 + 1.337 + // fully qualify to possibly avoid vtable call 1.338 + return nsCharsetConverterManager::GetCharsetLangGroupRaw(charset.get(), 1.339 + aResult); 1.340 +} 1.341 + 1.342 +NS_IMETHODIMP 1.343 +nsCharsetConverterManager::GetCharsetLangGroupRaw(const char * aCharset, 1.344 + nsIAtom** aResult) 1.345 +{ 1.346 + 1.347 + *aResult = nullptr; 1.348 + nsAutoString langGroup; 1.349 + // fully qualify to possibly avoid vtable call 1.350 + nsresult rv = nsCharsetConverterManager::GetCharsetData( 1.351 + aCharset, MOZ_UTF16(".LangGroup"), langGroup); 1.352 + 1.353 + if (NS_SUCCEEDED(rv)) { 1.354 + ToLowerCase(langGroup); // use lowercase for all language atoms 1.355 + *aResult = NS_NewAtom(langGroup).take(); 1.356 + } 1.357 + 1.358 + return rv; 1.359 +}