1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/uconv/src/nsScriptableUConv.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,296 @@ 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 "nsString.h" 1.10 +#include "nsICharsetConverterManager.h" 1.11 +#include "nsIScriptableUConv.h" 1.12 +#include "nsScriptableUConv.h" 1.13 +#include "nsIStringStream.h" 1.14 +#include "nsComponentManagerUtils.h" 1.15 +#include "nsCharsetAlias.h" 1.16 +#include "nsServiceManagerUtils.h" 1.17 + 1.18 +/* Implementation file */ 1.19 +NS_IMPL_ISUPPORTS(nsScriptableUnicodeConverter, nsIScriptableUnicodeConverter) 1.20 + 1.21 +nsScriptableUnicodeConverter::nsScriptableUnicodeConverter() 1.22 +: mIsInternal(false) 1.23 +{ 1.24 +} 1.25 + 1.26 +nsScriptableUnicodeConverter::~nsScriptableUnicodeConverter() 1.27 +{ 1.28 +} 1.29 + 1.30 +nsresult 1.31 +nsScriptableUnicodeConverter::ConvertFromUnicodeWithLength(const nsAString& aSrc, 1.32 + int32_t* aOutLen, 1.33 + char **_retval) 1.34 +{ 1.35 + if (!mEncoder) 1.36 + return NS_ERROR_FAILURE; 1.37 + 1.38 + nsresult rv = NS_OK; 1.39 + int32_t inLength = aSrc.Length(); 1.40 + const nsAFlatString& flatSrc = PromiseFlatString(aSrc); 1.41 + rv = mEncoder->GetMaxLength(flatSrc.get(), inLength, aOutLen); 1.42 + if (NS_SUCCEEDED(rv)) { 1.43 + *_retval = (char*)moz_malloc(*aOutLen+1); 1.44 + if (!*_retval) 1.45 + return NS_ERROR_OUT_OF_MEMORY; 1.46 + 1.47 + rv = mEncoder->Convert(flatSrc.get(), &inLength, *_retval, aOutLen); 1.48 + if (NS_SUCCEEDED(rv)) 1.49 + { 1.50 + (*_retval)[*aOutLen] = '\0'; 1.51 + return NS_OK; 1.52 + } 1.53 + moz_free(*_retval); 1.54 + } 1.55 + *_retval = nullptr; 1.56 + return NS_ERROR_FAILURE; 1.57 +} 1.58 + 1.59 +/* ACString ConvertFromUnicode (in AString src); */ 1.60 +NS_IMETHODIMP 1.61 +nsScriptableUnicodeConverter::ConvertFromUnicode(const nsAString& aSrc, 1.62 + nsACString& _retval) 1.63 +{ 1.64 + int32_t len; 1.65 + char* str; 1.66 + nsresult rv = ConvertFromUnicodeWithLength(aSrc, &len, &str); 1.67 + if (NS_SUCCEEDED(rv)) { 1.68 + // No Adopt on nsACString :( 1.69 + if (!_retval.Assign(str, len, mozilla::fallible_t())) { 1.70 + rv = NS_ERROR_OUT_OF_MEMORY; 1.71 + } 1.72 + moz_free(str); 1.73 + } 1.74 + return rv; 1.75 +} 1.76 + 1.77 +nsresult 1.78 +nsScriptableUnicodeConverter::FinishWithLength(char **_retval, int32_t* aLength) 1.79 +{ 1.80 + if (!mEncoder) 1.81 + return NS_ERROR_FAILURE; 1.82 + 1.83 + int32_t finLength = 32; 1.84 + 1.85 + *_retval = (char *)moz_malloc(finLength); 1.86 + if (!*_retval) 1.87 + return NS_ERROR_OUT_OF_MEMORY; 1.88 + 1.89 + nsresult rv = mEncoder->Finish(*_retval, &finLength); 1.90 + if (NS_SUCCEEDED(rv)) 1.91 + *aLength = finLength; 1.92 + else 1.93 + moz_free(*_retval); 1.94 + 1.95 + return rv; 1.96 + 1.97 +} 1.98 + 1.99 +/* ACString Finish(); */ 1.100 +NS_IMETHODIMP 1.101 +nsScriptableUnicodeConverter::Finish(nsACString& _retval) 1.102 +{ 1.103 + int32_t len; 1.104 + char* str; 1.105 + nsresult rv = FinishWithLength(&str, &len); 1.106 + if (NS_SUCCEEDED(rv)) { 1.107 + // No Adopt on nsACString :( 1.108 + if (!_retval.Assign(str, len, mozilla::fallible_t())) { 1.109 + rv = NS_ERROR_OUT_OF_MEMORY; 1.110 + } 1.111 + moz_free(str); 1.112 + } 1.113 + return rv; 1.114 +} 1.115 + 1.116 +/* AString ConvertToUnicode (in ACString src); */ 1.117 +NS_IMETHODIMP 1.118 +nsScriptableUnicodeConverter::ConvertToUnicode(const nsACString& aSrc, nsAString& _retval) 1.119 +{ 1.120 + nsACString::const_iterator i; 1.121 + aSrc.BeginReading(i); 1.122 + return ConvertFromByteArray(reinterpret_cast<const uint8_t*>(i.get()), 1.123 + aSrc.Length(), 1.124 + _retval); 1.125 +} 1.126 + 1.127 +/* AString convertFromByteArray([const,array,size_is(aCount)] in octet aData, 1.128 + in unsigned long aCount); 1.129 + */ 1.130 +NS_IMETHODIMP 1.131 +nsScriptableUnicodeConverter::ConvertFromByteArray(const uint8_t* aData, 1.132 + uint32_t aCount, 1.133 + nsAString& _retval) 1.134 +{ 1.135 + if (!mDecoder) 1.136 + return NS_ERROR_FAILURE; 1.137 + 1.138 + nsresult rv = NS_OK; 1.139 + int32_t inLength = aCount; 1.140 + int32_t outLength; 1.141 + rv = mDecoder->GetMaxLength(reinterpret_cast<const char*>(aData), 1.142 + inLength, &outLength); 1.143 + if (NS_SUCCEEDED(rv)) 1.144 + { 1.145 + char16_t* buf = (char16_t*)moz_malloc((outLength+1)*sizeof(char16_t)); 1.146 + if (!buf) 1.147 + return NS_ERROR_OUT_OF_MEMORY; 1.148 + 1.149 + rv = mDecoder->Convert(reinterpret_cast<const char*>(aData), 1.150 + &inLength, buf, &outLength); 1.151 + if (NS_SUCCEEDED(rv)) 1.152 + { 1.153 + buf[outLength] = 0; 1.154 + if (!_retval.Assign(buf, outLength, mozilla::fallible_t())) { 1.155 + rv = NS_ERROR_OUT_OF_MEMORY; 1.156 + } 1.157 + } 1.158 + moz_free(buf); 1.159 + return rv; 1.160 + } 1.161 + return NS_ERROR_FAILURE; 1.162 + 1.163 +} 1.164 + 1.165 +/* void convertToByteArray(in AString aString, 1.166 + [optional] out unsigned long aLen, 1.167 + [array, size_is(aLen),retval] out octet aData); 1.168 + */ 1.169 +NS_IMETHODIMP 1.170 +nsScriptableUnicodeConverter::ConvertToByteArray(const nsAString& aString, 1.171 + uint32_t* aLen, 1.172 + uint8_t** _aData) 1.173 +{ 1.174 + char* data; 1.175 + int32_t len; 1.176 + nsresult rv = ConvertFromUnicodeWithLength(aString, &len, &data); 1.177 + if (NS_FAILED(rv)) 1.178 + return rv; 1.179 + nsXPIDLCString str; 1.180 + str.Adopt(data, len); // NOTE: This uses the XPIDLCString as a byte array 1.181 + 1.182 + rv = FinishWithLength(&data, &len); 1.183 + if (NS_FAILED(rv)) 1.184 + return rv; 1.185 + 1.186 + str.Append(data, len); 1.187 + moz_free(data); 1.188 + // NOTE: this being a byte array, it needs no null termination 1.189 + *_aData = reinterpret_cast<uint8_t*>(moz_malloc(str.Length())); 1.190 + if (!*_aData) 1.191 + return NS_ERROR_OUT_OF_MEMORY; 1.192 + memcpy(*_aData, str.get(), str.Length()); 1.193 + *aLen = str.Length(); 1.194 + return NS_OK; 1.195 +} 1.196 + 1.197 +/* nsIInputStream convertToInputStream(in AString aString); */ 1.198 +NS_IMETHODIMP 1.199 +nsScriptableUnicodeConverter::ConvertToInputStream(const nsAString& aString, 1.200 + nsIInputStream** _retval) 1.201 +{ 1.202 + nsresult rv; 1.203 + nsCOMPtr<nsIStringInputStream> inputStream = 1.204 + do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv); 1.205 + if (NS_FAILED(rv)) 1.206 + return rv; 1.207 + 1.208 + uint8_t* data; 1.209 + uint32_t dataLen; 1.210 + rv = ConvertToByteArray(aString, &dataLen, &data); 1.211 + if (NS_FAILED(rv)) 1.212 + return rv; 1.213 + 1.214 + rv = inputStream->AdoptData(reinterpret_cast<char*>(data), dataLen); 1.215 + if (NS_FAILED(rv)) { 1.216 + moz_free(data); 1.217 + return rv; 1.218 + } 1.219 + 1.220 + NS_ADDREF(*_retval = inputStream); 1.221 + return rv; 1.222 +} 1.223 + 1.224 +/* attribute string charset; */ 1.225 +NS_IMETHODIMP 1.226 +nsScriptableUnicodeConverter::GetCharset(char * *aCharset) 1.227 +{ 1.228 + *aCharset = ToNewCString(mCharset); 1.229 + if (!*aCharset) 1.230 + return NS_ERROR_OUT_OF_MEMORY; 1.231 + 1.232 + return NS_OK; 1.233 +} 1.234 + 1.235 +NS_IMETHODIMP 1.236 +nsScriptableUnicodeConverter::SetCharset(const char * aCharset) 1.237 +{ 1.238 + mCharset.Assign(aCharset); 1.239 + return InitConverter(); 1.240 +} 1.241 + 1.242 +NS_IMETHODIMP 1.243 +nsScriptableUnicodeConverter::GetIsInternal(bool *aIsInternal) 1.244 +{ 1.245 + *aIsInternal = mIsInternal; 1.246 + return NS_OK; 1.247 +} 1.248 + 1.249 +NS_IMETHODIMP 1.250 +nsScriptableUnicodeConverter::SetIsInternal(const bool aIsInternal) 1.251 +{ 1.252 + mIsInternal = aIsInternal; 1.253 + return NS_OK; 1.254 +} 1.255 + 1.256 +nsresult 1.257 +nsScriptableUnicodeConverter::InitConverter() 1.258 +{ 1.259 + nsresult rv = NS_OK; 1.260 + mEncoder = nullptr; 1.261 + 1.262 + nsCOMPtr<nsICharsetConverterManager> ccm = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv); 1.263 + if (NS_FAILED(rv) || !ccm) { 1.264 + return rv; 1.265 + } 1.266 + 1.267 + // get an unicode converter 1.268 + rv = ccm->GetUnicodeEncoder(mCharset.get(), getter_AddRefs(mEncoder)); 1.269 + if (NS_FAILED(rv)) { 1.270 + return rv; 1.271 + } 1.272 + 1.273 + rv = mEncoder->SetOutputErrorBehavior(nsIUnicodeEncoder::kOnError_Replace, nullptr, (char16_t)'?'); 1.274 + if (NS_FAILED(rv)) { 1.275 + return rv; 1.276 + } 1.277 + 1.278 + nsAutoCString charset; 1.279 + rv = mIsInternal ? nsCharsetAlias::GetPreferredInternal(mCharset, charset) 1.280 + : nsCharsetAlias::GetPreferred(mCharset, charset); 1.281 + if (NS_FAILED(rv)) { 1.282 + return rv; 1.283 + } 1.284 + 1.285 + rv = ccm->GetUnicodeDecoderRaw(charset.get(), getter_AddRefs(mDecoder)); 1.286 + if (NS_FAILED(rv)) { 1.287 + return rv; 1.288 + } 1.289 + 1.290 + // The UTF-8 decoder used to throw regardless of the error behavior. 1.291 + // Simulating the old behavior for compatibility with legacy callers 1.292 + // (including addons). If callers want a control over the behavior, 1.293 + // they should switch to TextDecoder. 1.294 + if (charset.EqualsLiteral("UTF-8")) { 1.295 + mDecoder->SetInputErrorBehavior(nsIUnicodeDecoder::kOnError_Signal); 1.296 + } 1.297 + 1.298 + return rv ; 1.299 +}