1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Pierre Phaneuf <pp@ludusdesign.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include <locale.h>
40 : #include "prmem.h"
41 : #include "nsCollationUnix.h"
42 : #include "nsIServiceManager.h"
43 : #include "nsIComponentManager.h"
44 : #include "nsILocaleService.h"
45 : #include "nsIPlatformCharset.h"
46 : #include "nsPosixLocale.h"
47 : #include "nsCOMPtr.h"
48 : #include "nsUnicharUtils.h"
49 : #include "nsCRT.h"
50 : //#define DEBUG_UNIX_COLLATION
51 :
52 14659 : inline void nsCollationUnix::DoSetLocale()
53 : {
54 14659 : char *locale = setlocale(LC_COLLATE, NULL);
55 14659 : mSavedLocale.Assign(locale ? locale : "");
56 14659 : if (!mSavedLocale.EqualsIgnoreCase(mLocale.get())) {
57 0 : (void) setlocale(LC_COLLATE, PromiseFlatCString(Substring(mLocale,0,MAX_LOCALE_LEN)).get());
58 : }
59 14659 : }
60 :
61 14659 : inline void nsCollationUnix::DoRestoreLocale()
62 : {
63 14659 : if (!mSavedLocale.EqualsIgnoreCase(mLocale.get())) {
64 0 : (void) setlocale(LC_COLLATE, PromiseFlatCString(Substring(mSavedLocale,0,MAX_LOCALE_LEN)).get());
65 : }
66 14659 : }
67 :
68 19 : nsCollationUnix::nsCollationUnix()
69 : {
70 19 : mCollation = NULL;
71 19 : }
72 :
73 38 : nsCollationUnix::~nsCollationUnix()
74 : {
75 19 : if (mCollation != NULL)
76 19 : delete mCollation;
77 19 : }
78 :
79 180 : NS_IMPL_ISUPPORTS1(nsCollationUnix, nsICollation)
80 :
81 19 : nsresult nsCollationUnix::Initialize(nsILocale* locale)
82 : {
83 : #define kPlatformLocaleLength 64
84 19 : NS_ASSERTION(mCollation == NULL, "Should only be initialized once");
85 :
86 : nsresult res;
87 :
88 19 : mCollation = new nsCollation;
89 19 : if (mCollation == NULL) {
90 0 : NS_ERROR("mCollation creation failed");
91 0 : return NS_ERROR_OUT_OF_MEMORY;
92 : }
93 :
94 : // default platform locale
95 19 : mLocale.Assign('C');
96 :
97 38 : nsAutoString localeStr;
98 38 : NS_NAMED_LITERAL_STRING(aCategory, "NSILOCALE_COLLATE##PLATFORM");
99 :
100 : // get locale string, use app default if no locale specified
101 19 : if (locale == nsnull) {
102 : nsCOMPtr<nsILocaleService> localeService =
103 0 : do_GetService(NS_LOCALESERVICE_CONTRACTID, &res);
104 0 : if (NS_SUCCEEDED(res)) {
105 0 : nsCOMPtr<nsILocale> appLocale;
106 0 : res = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
107 0 : if (NS_SUCCEEDED(res)) {
108 0 : res = appLocale->GetCategory(aCategory, localeStr);
109 0 : NS_ASSERTION(NS_SUCCEEDED(res), "failed to get app locale info");
110 : }
111 : }
112 : }
113 : else {
114 19 : res = locale->GetCategory(aCategory, localeStr);
115 19 : NS_ASSERTION(NS_SUCCEEDED(res), "failed to get locale info");
116 : }
117 :
118 : // Get platform locale and charset name from locale, if available
119 19 : if (NS_SUCCEEDED(res)) {
120 : // keep the same behavior as 4.x as well as avoiding Linux collation key problem
121 19 : if (localeStr.LowerCaseEqualsLiteral("en_us")) { // note: locale is in platform format
122 0 : localeStr.AssignLiteral("C");
123 : }
124 :
125 19 : nsPosixLocale::GetPlatformLocale(localeStr, mLocale);
126 :
127 38 : nsCOMPtr <nsIPlatformCharset> platformCharset = do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &res);
128 19 : if (NS_SUCCEEDED(res)) {
129 38 : nsCAutoString mappedCharset;
130 19 : res = platformCharset->GetDefaultCharsetForLocale(localeStr, mappedCharset);
131 19 : if (NS_SUCCEEDED(res)) {
132 19 : mCollation->SetCharset(mappedCharset.get());
133 : }
134 : }
135 : }
136 :
137 19 : return NS_OK;
138 : }
139 :
140 :
141 14659 : nsresult nsCollationUnix::CompareString(PRInt32 strength,
142 : const nsAString& string1,
143 : const nsAString& string2,
144 : PRInt32* result)
145 : {
146 14659 : nsresult res = NS_OK;
147 :
148 29318 : nsAutoString stringNormalized1, stringNormalized2;
149 14659 : if (strength != kCollationCaseSensitive) {
150 11036 : res = mCollation->NormalizeString(string1, stringNormalized1);
151 11036 : if (NS_FAILED(res)) {
152 0 : return res;
153 : }
154 11036 : res = mCollation->NormalizeString(string2, stringNormalized2);
155 11036 : if (NS_FAILED(res)) {
156 0 : return res;
157 : }
158 : } else {
159 3623 : stringNormalized1 = string1;
160 3623 : stringNormalized2 = string2;
161 : }
162 :
163 : // convert unicode to charset
164 : char *str1, *str2;
165 :
166 14659 : res = mCollation->UnicodeToChar(stringNormalized1, &str1);
167 14659 : if (NS_SUCCEEDED(res) && str1 != NULL) {
168 14659 : res = mCollation->UnicodeToChar(stringNormalized2, &str2);
169 14659 : if (NS_SUCCEEDED(res) && str2 != NULL) {
170 14659 : DoSetLocale();
171 14659 : *result = strcoll(str1, str2);
172 14659 : DoRestoreLocale();
173 14659 : PR_Free(str2);
174 : }
175 14659 : PR_Free(str1);
176 : }
177 :
178 14659 : return res;
179 : }
180 :
181 :
182 0 : nsresult nsCollationUnix::AllocateRawSortKey(PRInt32 strength,
183 : const nsAString& stringIn,
184 : PRUint8** key, PRUint32* outLen)
185 : {
186 0 : nsresult res = NS_OK;
187 :
188 0 : nsAutoString stringNormalized;
189 0 : if (strength != kCollationCaseSensitive) {
190 0 : res = mCollation->NormalizeString(stringIn, stringNormalized);
191 0 : if (NS_FAILED(res))
192 0 : return res;
193 : } else {
194 0 : stringNormalized = stringIn;
195 : }
196 : // convert unicode to charset
197 : char *str;
198 :
199 0 : res = mCollation->UnicodeToChar(stringNormalized, &str);
200 0 : if (NS_SUCCEEDED(res) && str != NULL) {
201 0 : DoSetLocale();
202 : // call strxfrm to generate a key
203 0 : size_t len = strxfrm(nsnull, str, 0) + 1;
204 0 : void *buffer = PR_Malloc(len);
205 0 : if (!buffer) {
206 0 : res = NS_ERROR_OUT_OF_MEMORY;
207 0 : } else if (strxfrm((char *)buffer, str, len) >= len) {
208 0 : PR_Free(buffer);
209 0 : res = NS_ERROR_FAILURE;
210 : } else {
211 0 : *key = (PRUint8 *)buffer;
212 0 : *outLen = len;
213 : }
214 0 : DoRestoreLocale();
215 0 : PR_Free(str);
216 : }
217 :
218 0 : return res;
219 : }
220 :
221 0 : nsresult nsCollationUnix::CompareRawSortKey(const PRUint8* key1, PRUint32 len1,
222 : const PRUint8* key2, PRUint32 len2,
223 : PRInt32* result)
224 : {
225 0 : *result = PL_strcmp((const char *)key1, (const char *)key2);
226 0 : return NS_OK;
227 : }
|