Bumping gaia.json for 2 gaia revision(s) a=gaia-bump
[gecko.git] / intl / strres / nsStringBundle.cpp
blobe9299ddaf51c308b3e7960380ba9101596998bce
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 "nsStringBundle.h"
7 #include "nsID.h"
8 #include "nsString.h"
9 #include "nsIStringBundle.h"
10 #include "nsStringBundleService.h"
11 #include "nsStringBundleTextOverride.h"
12 #include "nsISupportsPrimitives.h"
13 #include "nsIMutableArray.h"
14 #include "nsArrayEnumerator.h"
15 #include "nscore.h"
16 #include "nsMemory.h"
17 #include "nsNetUtil.h"
18 #include "nsIObserverService.h"
19 #include "nsCOMArray.h"
20 #include "nsTextFormatter.h"
21 #include "nsIErrorService.h"
22 #include "nsICategoryManager.h"
23 #include "nsContentUtils.h"
25 // for async loading
26 #ifdef ASYNC_LOADING
27 #include "nsIBinaryInputStream.h"
28 #include "nsIStringStream.h"
29 #endif
31 using namespace mozilla;
33 static NS_DEFINE_CID(kErrorServiceCID, NS_ERRORSERVICE_CID);
35 nsStringBundle::~nsStringBundle()
39 nsStringBundle::nsStringBundle(const char* aURLSpec,
40 nsIStringBundleOverride* aOverrideStrings) :
41 mPropertiesURL(aURLSpec),
42 mOverrideStrings(aOverrideStrings),
43 mReentrantMonitor("nsStringBundle.mReentrantMonitor"),
44 mAttemptedLoad(false),
45 mLoaded(false)
49 nsresult
50 nsStringBundle::LoadProperties()
52 // this is different than mLoaded, because we only want to attempt
53 // to load once
54 // we only want to load once, but if we've tried once and failed,
55 // continue to throw an error!
56 if (mAttemptedLoad) {
57 if (mLoaded)
58 return NS_OK;
60 return NS_ERROR_UNEXPECTED;
63 mAttemptedLoad = true;
65 nsresult rv;
67 // do it synchronously
68 nsCOMPtr<nsIURI> uri;
69 rv = NS_NewURI(getter_AddRefs(uri), mPropertiesURL);
70 if (NS_FAILED(rv)) return rv;
72 nsCOMPtr<nsIChannel> channel;
73 rv = NS_NewChannel(getter_AddRefs(channel),
74 uri,
75 nsContentUtils::GetSystemPrincipal(),
76 nsILoadInfo::SEC_NORMAL,
77 nsIContentPolicy::TYPE_OTHER);
79 if (NS_FAILED(rv)) return rv;
81 // It's a string bundle. We expect a text/plain type, so set that as hint
82 channel->SetContentType(NS_LITERAL_CSTRING("text/plain"));
84 nsCOMPtr<nsIInputStream> in;
85 rv = channel->Open(getter_AddRefs(in));
86 if (NS_FAILED(rv)) return rv;
88 NS_ASSERTION(NS_SUCCEEDED(rv) && in, "Error in OpenBlockingStream");
89 NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && in, NS_ERROR_FAILURE);
91 static NS_DEFINE_CID(kPersistentPropertiesCID, NS_IPERSISTENTPROPERTIES_CID);
92 mProps = do_CreateInstance(kPersistentPropertiesCID, &rv);
93 NS_ENSURE_SUCCESS(rv, rv);
95 mAttemptedLoad = mLoaded = true;
96 rv = mProps->Load(in);
98 mLoaded = NS_SUCCEEDED(rv);
100 return rv;
104 nsresult
105 nsStringBundle::GetStringFromID(int32_t aID, nsAString& aResult)
107 ReentrantMonitorAutoEnter automon(mReentrantMonitor);
108 nsAutoCString name;
109 name.AppendInt(aID, 10);
111 nsresult rv;
113 // try override first
114 if (mOverrideStrings) {
115 rv = mOverrideStrings->GetStringFromName(mPropertiesURL,
116 name,
117 aResult);
118 if (NS_SUCCEEDED(rv)) return rv;
121 rv = mProps->GetStringProperty(name, aResult);
123 return rv;
126 nsresult
127 nsStringBundle::GetStringFromName(const nsAString& aName,
128 nsAString& aResult)
130 nsresult rv;
132 // try override first
133 if (mOverrideStrings) {
134 rv = mOverrideStrings->GetStringFromName(mPropertiesURL,
135 NS_ConvertUTF16toUTF8(aName),
136 aResult);
137 if (NS_SUCCEEDED(rv)) return rv;
140 rv = mProps->GetStringProperty(NS_ConvertUTF16toUTF8(aName), aResult);
141 return rv;
144 NS_IMETHODIMP
145 nsStringBundle::FormatStringFromID(int32_t aID,
146 const char16_t **aParams,
147 uint32_t aLength,
148 char16_t ** aResult)
150 nsAutoString idStr;
151 idStr.AppendInt(aID, 10);
153 return FormatStringFromName(idStr.get(), aParams, aLength, aResult);
156 // this function supports at most 10 parameters.. see below for why
157 NS_IMETHODIMP
158 nsStringBundle::FormatStringFromName(const char16_t *aName,
159 const char16_t **aParams,
160 uint32_t aLength,
161 char16_t **aResult)
163 NS_ENSURE_ARG_POINTER(aName);
164 NS_ASSERTION(aParams && aLength, "FormatStringFromName() without format parameters: use GetStringFromName() instead");
165 NS_ENSURE_ARG_POINTER(aResult);
167 nsresult rv;
168 rv = LoadProperties();
169 if (NS_FAILED(rv)) return rv;
171 nsAutoString formatStr;
172 rv = GetStringFromName(nsDependentString(aName), formatStr);
173 if (NS_FAILED(rv)) return rv;
175 return FormatString(formatStr.get(), aParams, aLength, aResult);
179 NS_IMPL_ISUPPORTS(nsStringBundle, nsIStringBundle)
181 /* void GetStringFromID (in long aID, out wstring aResult); */
182 NS_IMETHODIMP
183 nsStringBundle::GetStringFromID(int32_t aID, char16_t **aResult)
185 nsresult rv;
186 rv = LoadProperties();
187 if (NS_FAILED(rv)) return rv;
189 *aResult = nullptr;
190 nsAutoString tmpstr;
192 rv = GetStringFromID(aID, tmpstr);
193 NS_ENSURE_SUCCESS(rv, rv);
195 *aResult = ToNewUnicode(tmpstr);
196 NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
198 return NS_OK;
201 /* void GetStringFromName (in wstring aName, out wstring aResult); */
202 NS_IMETHODIMP
203 nsStringBundle::GetStringFromName(const char16_t *aName, char16_t **aResult)
205 NS_ENSURE_ARG_POINTER(aName);
206 NS_ENSURE_ARG_POINTER(aResult);
208 nsresult rv;
209 rv = LoadProperties();
210 if (NS_FAILED(rv)) return rv;
212 ReentrantMonitorAutoEnter automon(mReentrantMonitor);
213 *aResult = nullptr;
214 nsAutoString tmpstr;
215 rv = GetStringFromName(nsDependentString(aName), tmpstr);
216 if (NS_FAILED(rv))
218 #if 0
219 // it is not uncommon for apps to request a string name which may not exist
220 // so be quiet about it.
221 NS_WARNING("String missing from string bundle");
222 printf(" '%s' missing from bundle %s\n", NS_ConvertUTF16toUTF8(aName).get(), mPropertiesURL.get());
223 #endif
224 return rv;
227 *aResult = ToNewUnicode(tmpstr);
228 NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
230 return NS_OK;
233 nsresult
234 nsStringBundle::GetCombinedEnumeration(nsIStringBundleOverride* aOverrideStrings,
235 nsISimpleEnumerator** aResult)
237 nsCOMPtr<nsISupports> supports;
238 nsCOMPtr<nsIPropertyElement> propElement;
240 nsresult rv;
242 nsCOMPtr<nsIMutableArray> resultArray =
243 do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
244 NS_ENSURE_SUCCESS(rv, rv);
246 // first, append the override elements
247 nsCOMPtr<nsISimpleEnumerator> overrideEnumerator;
248 rv = aOverrideStrings->EnumerateKeysInBundle(mPropertiesURL,
249 getter_AddRefs(overrideEnumerator));
251 bool hasMore;
252 rv = overrideEnumerator->HasMoreElements(&hasMore);
253 NS_ENSURE_SUCCESS(rv, rv);
254 while (hasMore) {
256 rv = overrideEnumerator->GetNext(getter_AddRefs(supports));
257 if (NS_SUCCEEDED(rv))
258 resultArray->AppendElement(supports, false);
260 rv = overrideEnumerator->HasMoreElements(&hasMore);
261 NS_ENSURE_SUCCESS(rv, rv);
264 // ok, now we have the override elements in resultArray
265 nsCOMPtr<nsISimpleEnumerator> propEnumerator;
266 rv = mProps->Enumerate(getter_AddRefs(propEnumerator));
267 if (NS_FAILED(rv)) {
268 // no elements in mProps anyway, just return what we have
269 return NS_NewArrayEnumerator(aResult, resultArray);
272 // second, append all the elements that are in mProps
273 do {
274 rv = propEnumerator->GetNext(getter_AddRefs(supports));
275 if (NS_SUCCEEDED(rv) &&
276 (propElement = do_QueryInterface(supports, &rv))) {
278 // now check if its in the override bundle
279 nsAutoCString key;
280 propElement->GetKey(key);
282 nsAutoString value;
283 rv = aOverrideStrings->GetStringFromName(mPropertiesURL, key, value);
285 // if it isn't there, then it is safe to append
286 if (NS_FAILED(rv))
287 resultArray->AppendElement(propElement, false);
290 rv = propEnumerator->HasMoreElements(&hasMore);
291 NS_ENSURE_SUCCESS(rv, rv);
292 } while (hasMore);
294 return resultArray->Enumerate(aResult);
298 NS_IMETHODIMP
299 nsStringBundle::GetSimpleEnumeration(nsISimpleEnumerator** elements)
301 if (!elements)
302 return NS_ERROR_INVALID_POINTER;
304 nsresult rv;
305 rv = LoadProperties();
306 if (NS_FAILED(rv)) return rv;
308 if (mOverrideStrings)
309 return GetCombinedEnumeration(mOverrideStrings, elements);
311 return mProps->Enumerate(elements);
314 nsresult
315 nsStringBundle::FormatString(const char16_t *aFormatStr,
316 const char16_t **aParams, uint32_t aLength,
317 char16_t **aResult)
319 NS_ENSURE_ARG_POINTER(aResult);
320 NS_ENSURE_ARG(aLength <= 10); // enforce 10-parameter limit
322 // implementation note: you would think you could use vsmprintf
323 // to build up an arbitrary length array.. except that there
324 // is no way to build up a va_list at runtime!
325 // Don't believe me? See:
326 // http://www.eskimo.com/~scs/C-faq/q15.13.html
327 // -alecf
328 char16_t *text =
329 nsTextFormatter::smprintf(aFormatStr,
330 aLength >= 1 ? aParams[0] : nullptr,
331 aLength >= 2 ? aParams[1] : nullptr,
332 aLength >= 3 ? aParams[2] : nullptr,
333 aLength >= 4 ? aParams[3] : nullptr,
334 aLength >= 5 ? aParams[4] : nullptr,
335 aLength >= 6 ? aParams[5] : nullptr,
336 aLength >= 7 ? aParams[6] : nullptr,
337 aLength >= 8 ? aParams[7] : nullptr,
338 aLength >= 9 ? aParams[8] : nullptr,
339 aLength >= 10 ? aParams[9] : nullptr);
341 if (!text) {
342 *aResult = nullptr;
343 return NS_ERROR_OUT_OF_MEMORY;
346 // nsTextFormatter does not use the shared nsMemory allocator.
347 // Instead it is required to free the memory it allocates using
348 // nsTextFormatter::smprintf_free. Let's instead use nsMemory based
349 // allocation for the result that we give out and free the string
350 // returned by smprintf ourselves!
351 *aResult = NS_strdup(text);
352 nsTextFormatter::smprintf_free(text);
354 return *aResult ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
357 NS_IMPL_ISUPPORTS(nsExtensibleStringBundle, nsIStringBundle)
359 nsExtensibleStringBundle::nsExtensibleStringBundle()
361 mLoaded = false;
364 nsresult
365 nsExtensibleStringBundle::Init(const char * aCategory,
366 nsIStringBundleService* aBundleService)
369 nsresult rv;
370 nsCOMPtr<nsICategoryManager> catman =
371 do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
372 if (NS_FAILED(rv)) return rv;
374 nsCOMPtr<nsISimpleEnumerator> enumerator;
375 rv = catman->EnumerateCategory(aCategory, getter_AddRefs(enumerator));
376 if (NS_FAILED(rv)) return rv;
378 bool hasMore;
379 while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore) {
380 nsCOMPtr<nsISupports> supports;
381 rv = enumerator->GetNext(getter_AddRefs(supports));
382 if (NS_FAILED(rv))
383 continue;
385 nsCOMPtr<nsISupportsCString> supStr = do_QueryInterface(supports, &rv);
386 if (NS_FAILED(rv))
387 continue;
389 nsAutoCString name;
390 rv = supStr->GetData(name);
391 if (NS_FAILED(rv))
392 continue;
394 nsCOMPtr<nsIStringBundle> bundle;
395 rv = aBundleService->CreateBundle(name.get(), getter_AddRefs(bundle));
396 if (NS_FAILED(rv))
397 continue;
399 mBundles.AppendObject(bundle);
402 return rv;
405 nsExtensibleStringBundle::~nsExtensibleStringBundle()
409 nsresult nsExtensibleStringBundle::GetStringFromID(int32_t aID, char16_t ** aResult)
411 nsresult rv;
412 const uint32_t size = mBundles.Count();
413 for (uint32_t i = 0; i < size; ++i) {
414 nsIStringBundle *bundle = mBundles[i];
415 if (bundle) {
416 rv = bundle->GetStringFromID(aID, aResult);
417 if (NS_SUCCEEDED(rv))
418 return NS_OK;
422 return NS_ERROR_FAILURE;
425 nsresult nsExtensibleStringBundle::GetStringFromName(const char16_t *aName,
426 char16_t ** aResult)
428 nsresult rv;
429 const uint32_t size = mBundles.Count();
430 for (uint32_t i = 0; i < size; ++i) {
431 nsIStringBundle* bundle = mBundles[i];
432 if (bundle) {
433 rv = bundle->GetStringFromName(aName, aResult);
434 if (NS_SUCCEEDED(rv))
435 return NS_OK;
439 return NS_ERROR_FAILURE;
442 NS_IMETHODIMP
443 nsExtensibleStringBundle::FormatStringFromID(int32_t aID,
444 const char16_t ** aParams,
445 uint32_t aLength,
446 char16_t ** aResult)
448 nsAutoString idStr;
449 idStr.AppendInt(aID, 10);
450 return FormatStringFromName(idStr.get(), aParams, aLength, aResult);
453 NS_IMETHODIMP
454 nsExtensibleStringBundle::FormatStringFromName(const char16_t *aName,
455 const char16_t ** aParams,
456 uint32_t aLength,
457 char16_t ** aResult)
459 nsXPIDLString formatStr;
460 nsresult rv;
461 rv = GetStringFromName(aName, getter_Copies(formatStr));
462 if (NS_FAILED(rv))
463 return rv;
465 return nsStringBundle::FormatString(formatStr, aParams, aLength, aResult);
468 nsresult nsExtensibleStringBundle::GetSimpleEnumeration(nsISimpleEnumerator ** aResult)
470 // XXX write me
471 *aResult = nullptr;
472 return NS_ERROR_NOT_IMPLEMENTED;
475 /////////////////////////////////////////////////////////////////////////////////////////
477 #define MAX_CACHED_BUNDLES 16
479 struct bundleCacheEntry_t MOZ_FINAL : public LinkedListElement<bundleCacheEntry_t> {
480 nsCString mHashKey;
481 nsCOMPtr<nsIStringBundle> mBundle;
483 bundleCacheEntry_t()
485 MOZ_COUNT_CTOR(bundleCacheEntry_t);
488 ~bundleCacheEntry_t()
490 MOZ_COUNT_DTOR(bundleCacheEntry_t);
495 nsStringBundleService::nsStringBundleService() :
496 mBundleMap(MAX_CACHED_BUNDLES)
498 mErrorService = do_GetService(kErrorServiceCID);
499 NS_ASSERTION(mErrorService, "Couldn't get error service");
502 NS_IMPL_ISUPPORTS(nsStringBundleService,
503 nsIStringBundleService,
504 nsIObserver,
505 nsISupportsWeakReference)
507 nsStringBundleService::~nsStringBundleService()
509 flushBundleCache();
512 nsresult
513 nsStringBundleService::Init()
515 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
516 if (os) {
517 os->AddObserver(this, "memory-pressure", true);
518 os->AddObserver(this, "profile-do-change", true);
519 os->AddObserver(this, "chrome-flush-caches", true);
520 os->AddObserver(this, "xpcom-category-entry-added", true);
523 // instantiate the override service, if there is any.
524 // at some point we probably want to make this a category, and
525 // support multiple overrides
526 mOverrideStrings = do_GetService(NS_STRINGBUNDLETEXTOVERRIDE_CONTRACTID);
528 return NS_OK;
531 NS_IMETHODIMP
532 nsStringBundleService::Observe(nsISupports* aSubject,
533 const char* aTopic,
534 const char16_t* aSomeData)
536 if (strcmp("memory-pressure", aTopic) == 0 ||
537 strcmp("profile-do-change", aTopic) == 0 ||
538 strcmp("chrome-flush-caches", aTopic) == 0)
540 flushBundleCache();
542 else if (strcmp("xpcom-category-entry-added", aTopic) == 0 &&
543 NS_LITERAL_STRING("xpcom-autoregistration").Equals(aSomeData))
545 mOverrideStrings = do_GetService(NS_STRINGBUNDLETEXTOVERRIDE_CONTRACTID);
548 return NS_OK;
551 void
552 nsStringBundleService::flushBundleCache()
554 // release all bundles in the cache
555 mBundleMap.Clear();
557 while (!mBundleCache.isEmpty()) {
558 delete mBundleCache.popFirst();
562 NS_IMETHODIMP
563 nsStringBundleService::FlushBundles()
565 flushBundleCache();
566 return NS_OK;
569 nsresult
570 nsStringBundleService::getStringBundle(const char *aURLSpec,
571 nsIStringBundle **aResult)
573 nsDependentCString key(aURLSpec);
574 bundleCacheEntry_t* cacheEntry = mBundleMap.Get(key);
576 if (cacheEntry) {
577 // cache hit!
578 // remove it from the list, it will later be reinserted
579 // at the head of the list
580 cacheEntry->remove();
582 } else {
584 // hasn't been cached, so insert it into the hash table
585 nsRefPtr<nsStringBundle> bundle = new nsStringBundle(aURLSpec, mOverrideStrings);
586 cacheEntry = insertIntoCache(bundle.forget(), key);
589 // at this point the cacheEntry should exist in the hashtable,
590 // but is not in the LRU cache.
591 // put the cache entry at the front of the list
592 mBundleCache.insertFront(cacheEntry);
594 // finally, return the value
595 *aResult = cacheEntry->mBundle;
596 NS_ADDREF(*aResult);
598 return NS_OK;
601 bundleCacheEntry_t *
602 nsStringBundleService::insertIntoCache(already_AddRefed<nsIStringBundle> aBundle,
603 nsCString &aHashKey)
605 bundleCacheEntry_t *cacheEntry;
607 if (mBundleMap.Count() < MAX_CACHED_BUNDLES) {
608 // cache not full - create a new entry
609 cacheEntry = new bundleCacheEntry_t();
610 } else {
611 // cache is full
612 // take the last entry in the list, and recycle it.
613 cacheEntry = mBundleCache.getLast();
615 // remove it from the hash table and linked list
616 NS_ASSERTION(mBundleMap.Contains(cacheEntry->mHashKey),
617 "Element will not be removed!");
618 mBundleMap.Remove(cacheEntry->mHashKey);
619 cacheEntry->remove();
622 // at this point we have a new cacheEntry that doesn't exist
623 // in the hashtable, so set up the cacheEntry
624 cacheEntry->mHashKey = aHashKey;
625 cacheEntry->mBundle = aBundle;
627 // insert the entry into the cache and map, make it the MRU
628 mBundleMap.Put(cacheEntry->mHashKey, cacheEntry);
630 return cacheEntry;
633 NS_IMETHODIMP
634 nsStringBundleService::CreateBundle(const char* aURLSpec,
635 nsIStringBundle** aResult)
637 return getStringBundle(aURLSpec,aResult);
640 NS_IMETHODIMP
641 nsStringBundleService::CreateExtensibleBundle(const char* aCategory,
642 nsIStringBundle** aResult)
644 NS_ENSURE_ARG_POINTER(aResult);
645 *aResult = nullptr;
647 nsRefPtr<nsExtensibleStringBundle> bundle = new nsExtensibleStringBundle();
649 nsresult res = bundle->Init(aCategory, this);
650 if (NS_FAILED(res)) {
651 return res;
654 res = bundle->QueryInterface(NS_GET_IID(nsIStringBundle), (void**) aResult);
656 return res;
659 #define GLOBAL_PROPERTIES "chrome://global/locale/global-strres.properties"
661 nsresult
662 nsStringBundleService::FormatWithBundle(nsIStringBundle* bundle, nsresult aStatus,
663 uint32_t argCount, char16_t** argArray,
664 char16_t* *result)
666 nsresult rv;
667 nsXPIDLCString key;
669 // try looking up the error message with the int key:
670 uint16_t code = NS_ERROR_GET_CODE(aStatus);
671 rv = bundle->FormatStringFromID(code, (const char16_t**)argArray, argCount, result);
673 // If the int key fails, try looking up the default error message. E.g. print:
674 // An unknown error has occurred (0x804B0003).
675 if (NS_FAILED(rv)) {
676 nsAutoString statusStr;
677 statusStr.AppendInt(static_cast<uint32_t>(aStatus), 16);
678 const char16_t* otherArgArray[1];
679 otherArgArray[0] = statusStr.get();
680 uint16_t code = NS_ERROR_GET_CODE(NS_ERROR_FAILURE);
681 rv = bundle->FormatStringFromID(code, otherArgArray, 1, result);
684 return rv;
687 NS_IMETHODIMP
688 nsStringBundleService::FormatStatusMessage(nsresult aStatus,
689 const char16_t* aStatusArg,
690 char16_t* *result)
692 nsresult rv;
693 uint32_t i, argCount = 0;
694 nsCOMPtr<nsIStringBundle> bundle;
695 nsXPIDLCString stringBundleURL;
697 // XXX hack for mailnews who has already formatted their messages:
698 if (aStatus == NS_OK && aStatusArg) {
699 *result = NS_strdup(aStatusArg);
700 NS_ENSURE_TRUE(*result, NS_ERROR_OUT_OF_MEMORY);
701 return NS_OK;
704 if (aStatus == NS_OK) {
705 return NS_ERROR_FAILURE; // no message to format
708 // format the arguments:
709 const nsDependentString args(aStatusArg);
710 argCount = args.CountChar(char16_t('\n')) + 1;
711 NS_ENSURE_ARG(argCount <= 10); // enforce 10-parameter limit
712 char16_t* argArray[10];
714 // convert the aStatusArg into a char16_t array
715 if (argCount == 1) {
716 // avoid construction for the simple case:
717 argArray[0] = (char16_t*)aStatusArg;
719 else if (argCount > 1) {
720 int32_t offset = 0;
721 for (i = 0; i < argCount; i++) {
722 int32_t pos = args.FindChar('\n', offset);
723 if (pos == -1)
724 pos = args.Length();
725 argArray[i] = ToNewUnicode(Substring(args, offset, pos - offset));
726 if (argArray[i] == nullptr) {
727 rv = NS_ERROR_OUT_OF_MEMORY;
728 argCount = i - 1; // don't try to free uninitialized memory
729 goto done;
731 offset = pos + 1;
735 // find the string bundle for the error's module:
736 rv = mErrorService->GetErrorStringBundle(NS_ERROR_GET_MODULE(aStatus),
737 getter_Copies(stringBundleURL));
738 if (NS_SUCCEEDED(rv)) {
739 rv = getStringBundle(stringBundleURL, getter_AddRefs(bundle));
740 if (NS_SUCCEEDED(rv)) {
741 rv = FormatWithBundle(bundle, aStatus, argCount, argArray, result);
744 if (NS_FAILED(rv)) {
745 rv = getStringBundle(GLOBAL_PROPERTIES, getter_AddRefs(bundle));
746 if (NS_SUCCEEDED(rv)) {
747 rv = FormatWithBundle(bundle, aStatus, argCount, argArray, result);
751 done:
752 if (argCount > 1) {
753 for (i = 0; i < argCount; i++) {
754 if (argArray[i])
755 nsMemory::Free(argArray[i]);
758 return rv;