nsCollationUnix.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  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/. */
  5. #include <locale.h>
  6. #include "prmem.h"
  7. #include "nsCollationUnix.h"
  8. #include "nsIServiceManager.h"
  9. #include "nsIComponentManager.h"
  10. #include "nsILocaleService.h"
  11. #include "nsIPlatformCharset.h"
  12. #include "nsPosixLocale.h"
  13. #include "nsCOMPtr.h"
  14. #include "nsUnicharUtils.h"
  15. #include "nsCRT.h"
  16. //#define DEBUG_UNIX_COLLATION
  17. inline void nsCollationUnix::DoSetLocale()
  18. {
  19. char *locale = setlocale(LC_COLLATE, nullptr);
  20. mSavedLocale.Assign(locale ? locale : "");
  21. if (!mSavedLocale.EqualsIgnoreCase(mLocale.get())) {
  22. (void) setlocale(LC_COLLATE, PromiseFlatCString(Substring(mLocale,0,MAX_LOCALE_LEN)).get());
  23. }
  24. }
  25. inline void nsCollationUnix::DoRestoreLocale()
  26. {
  27. if (!mSavedLocale.EqualsIgnoreCase(mLocale.get())) {
  28. (void) setlocale(LC_COLLATE, PromiseFlatCString(Substring(mSavedLocale,0,MAX_LOCALE_LEN)).get());
  29. }
  30. }
  31. nsCollationUnix::nsCollationUnix() : mCollation(nullptr)
  32. {
  33. }
  34. nsCollationUnix::~nsCollationUnix()
  35. {
  36. if (mCollation)
  37. delete mCollation;
  38. }
  39. NS_IMPL_ISUPPORTS(nsCollationUnix, nsICollation)
  40. nsresult nsCollationUnix::Initialize(nsILocale* locale)
  41. {
  42. #define kPlatformLocaleLength 64
  43. NS_ASSERTION(!mCollation, "Should only be initialized once");
  44. nsresult res;
  45. mCollation = new nsCollation;
  46. // default platform locale
  47. mLocale.Assign('C');
  48. nsAutoString localeStr;
  49. NS_NAMED_LITERAL_STRING(aCategory, "NSILOCALE_COLLATE##PLATFORM");
  50. // get locale string, use app default if no locale specified
  51. if (locale == nullptr) {
  52. nsCOMPtr<nsILocaleService> localeService =
  53. do_GetService(NS_LOCALESERVICE_CONTRACTID, &res);
  54. if (NS_SUCCEEDED(res)) {
  55. nsCOMPtr<nsILocale> appLocale;
  56. res = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
  57. if (NS_SUCCEEDED(res)) {
  58. res = appLocale->GetCategory(aCategory, localeStr);
  59. NS_ASSERTION(NS_SUCCEEDED(res), "failed to get app locale info");
  60. }
  61. }
  62. }
  63. else {
  64. res = locale->GetCategory(aCategory, localeStr);
  65. NS_ASSERTION(NS_SUCCEEDED(res), "failed to get locale info");
  66. }
  67. // Get platform locale and charset name from locale, if available
  68. if (NS_SUCCEEDED(res)) {
  69. // keep the same behavior as 4.x as well as avoiding Linux collation key problem
  70. if (localeStr.LowerCaseEqualsLiteral("en_us")) { // note: locale is in platform format
  71. localeStr.Assign('C');
  72. }
  73. nsPosixLocale::GetPlatformLocale(localeStr, mLocale);
  74. nsCOMPtr <nsIPlatformCharset> platformCharset = do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &res);
  75. if (NS_SUCCEEDED(res)) {
  76. nsAutoCString mappedCharset;
  77. res = platformCharset->GetDefaultCharsetForLocale(localeStr, mappedCharset);
  78. if (NS_SUCCEEDED(res)) {
  79. mCollation->SetCharset(mappedCharset.get());
  80. }
  81. }
  82. }
  83. return NS_OK;
  84. }
  85. nsresult nsCollationUnix::CompareString(int32_t strength,
  86. const nsAString& string1,
  87. const nsAString& string2,
  88. int32_t* result)
  89. {
  90. nsresult res = NS_OK;
  91. nsAutoString stringNormalized1, stringNormalized2;
  92. if (strength != kCollationCaseSensitive) {
  93. res = mCollation->NormalizeString(string1, stringNormalized1);
  94. if (NS_FAILED(res)) {
  95. return res;
  96. }
  97. res = mCollation->NormalizeString(string2, stringNormalized2);
  98. if (NS_FAILED(res)) {
  99. return res;
  100. }
  101. } else {
  102. stringNormalized1 = string1;
  103. stringNormalized2 = string2;
  104. }
  105. // convert unicode to charset
  106. char *str1, *str2;
  107. res = mCollation->UnicodeToChar(stringNormalized1, &str1);
  108. if (NS_SUCCEEDED(res) && str1) {
  109. res = mCollation->UnicodeToChar(stringNormalized2, &str2);
  110. if (NS_SUCCEEDED(res) && str2) {
  111. DoSetLocale();
  112. *result = strcoll(str1, str2);
  113. DoRestoreLocale();
  114. PR_Free(str2);
  115. }
  116. PR_Free(str1);
  117. }
  118. return res;
  119. }
  120. nsresult nsCollationUnix::AllocateRawSortKey(int32_t strength,
  121. const nsAString& stringIn,
  122. uint8_t** key, uint32_t* outLen)
  123. {
  124. nsresult res = NS_OK;
  125. nsAutoString stringNormalized;
  126. if (strength != kCollationCaseSensitive) {
  127. res = mCollation->NormalizeString(stringIn, stringNormalized);
  128. if (NS_FAILED(res))
  129. return res;
  130. } else {
  131. stringNormalized = stringIn;
  132. }
  133. // convert unicode to charset
  134. char *str;
  135. res = mCollation->UnicodeToChar(stringNormalized, &str);
  136. if (NS_SUCCEEDED(res) && str) {
  137. DoSetLocale();
  138. // call strxfrm to generate a key
  139. size_t len = strxfrm(nullptr, str, 0) + 1;
  140. void *buffer = PR_Malloc(len);
  141. if (!buffer) {
  142. res = NS_ERROR_OUT_OF_MEMORY;
  143. } else if (strxfrm((char *)buffer, str, len) >= len) {
  144. PR_Free(buffer);
  145. res = NS_ERROR_FAILURE;
  146. } else {
  147. *key = (uint8_t *)buffer;
  148. *outLen = len;
  149. }
  150. DoRestoreLocale();
  151. PR_Free(str);
  152. }
  153. return res;
  154. }
  155. nsresult nsCollationUnix::CompareRawSortKey(const uint8_t* key1, uint32_t len1,
  156. const uint8_t* key2, uint32_t len2,
  157. int32_t* result)
  158. {
  159. *result = PL_strcmp((const char *)key1, (const char *)key2);
  160. return NS_OK;
  161. }