intl/uconv/src/nsScriptableUConv.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial