1 : /* ***** BEGIN LICENSE BLOCK *****
2 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 : *
4 : * The contents of this file are subject to the Mozilla Public License Version
5 : * 1.1 (the "License"); you may not use this file except in compliance with
6 : * the License. You may obtain a copy of the License at
7 : * http://www.mozilla.org/MPL/
8 : *
9 : * Software distributed under the License is distributed on an "AS IS" basis,
10 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 : * for the specific language governing rights and limitations under the
12 : * License.
13 : *
14 : * The Original Code is Mozilla Hyphenation Service.
15 : *
16 : * The Initial Developer of the Original Code is
17 : * Mozilla Foundation.
18 : * Portions created by the Initial Developer are Copyright (C) 2011
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Jonathan Kew <jfkthame@gmail.com>
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "nsHyphenationManager.h"
39 : #include "nsHyphenator.h"
40 : #include "nsIAtom.h"
41 : #include "nsIFile.h"
42 : #include "nsIURI.h"
43 : #include "nsIProperties.h"
44 : #include "nsISimpleEnumerator.h"
45 : #include "nsIDirectoryEnumerator.h"
46 : #include "nsDirectoryServiceDefs.h"
47 : #include "nsNetUtil.h"
48 : #include "nsUnicharUtils.h"
49 : #include "mozilla/Preferences.h"
50 : #include "nsZipArchive.h"
51 :
52 : using namespace mozilla;
53 :
54 : #define INTL_HYPHENATIONALIAS_PREFIX "intl.hyphenation-alias."
55 :
56 : nsHyphenationManager *nsHyphenationManager::sInstance = nsnull;
57 :
58 : nsHyphenationManager*
59 0 : nsHyphenationManager::Instance()
60 : {
61 0 : if (sInstance == nsnull) {
62 0 : sInstance = new nsHyphenationManager();
63 : }
64 0 : return sInstance;
65 : }
66 :
67 : void
68 1403 : nsHyphenationManager::Shutdown()
69 : {
70 1403 : delete sInstance;
71 1403 : }
72 :
73 0 : nsHyphenationManager::nsHyphenationManager()
74 : {
75 0 : mHyphAliases.Init();
76 0 : mPatternFiles.Init();
77 0 : mHyphenators.Init();
78 0 : LoadPatternList();
79 0 : LoadAliases();
80 0 : }
81 :
82 0 : nsHyphenationManager::~nsHyphenationManager()
83 : {
84 0 : sInstance = nsnull;
85 0 : }
86 :
87 : already_AddRefed<nsHyphenator>
88 0 : nsHyphenationManager::GetHyphenator(nsIAtom *aLocale)
89 : {
90 0 : nsRefPtr<nsHyphenator> hyph;
91 0 : mHyphenators.Get(aLocale, getter_AddRefs(hyph));
92 0 : if (hyph) {
93 0 : return hyph.forget();
94 : }
95 0 : nsCOMPtr<nsIURI> uri = mPatternFiles.Get(aLocale);
96 0 : if (!uri) {
97 0 : nsCOMPtr<nsIAtom> alias = mHyphAliases.Get(aLocale);
98 0 : if (alias) {
99 0 : mHyphenators.Get(alias, getter_AddRefs(hyph));
100 0 : if (hyph) {
101 0 : return hyph.forget();
102 : }
103 0 : uri = mPatternFiles.Get(alias);
104 0 : if (uri) {
105 0 : aLocale = alias;
106 : }
107 : }
108 0 : if (!uri) {
109 : // In the case of a locale such as "de-DE-1996", we try replacing
110 : // successive trailing subtags with "-*" to find fallback patterns,
111 : // so "de-DE-1996" -> "de-DE-*" (and then recursively -> "de-*")
112 0 : nsAtomCString localeStr(aLocale);
113 0 : if (StringEndsWith(localeStr, NS_LITERAL_CSTRING("-*"))) {
114 0 : localeStr.Truncate(localeStr.Length() - 2);
115 : }
116 0 : PRInt32 i = localeStr.RFindChar('-');
117 0 : if (i > 1) {
118 0 : localeStr.Replace(i, localeStr.Length() - i, "-*");
119 0 : nsCOMPtr<nsIAtom> fuzzyLocale = do_GetAtom(localeStr);
120 0 : return GetHyphenator(fuzzyLocale);
121 : } else {
122 0 : return nsnull;
123 : }
124 : }
125 : }
126 0 : hyph = new nsHyphenator(uri);
127 0 : if (hyph->IsValid()) {
128 0 : mHyphenators.Put(aLocale, hyph);
129 0 : return hyph.forget();
130 : }
131 : #ifdef DEBUG
132 0 : nsCString msg;
133 0 : uri->GetSpec(msg);
134 0 : msg.Insert("failed to load patterns from ", 0);
135 0 : NS_WARNING(msg.get());
136 : #endif
137 0 : mPatternFiles.Remove(aLocale);
138 0 : return nsnull;
139 : }
140 :
141 : void
142 0 : nsHyphenationManager::LoadPatternList()
143 : {
144 0 : mPatternFiles.Clear();
145 0 : mHyphenators.Clear();
146 :
147 0 : LoadPatternListFromOmnijar(Omnijar::GRE);
148 0 : LoadPatternListFromOmnijar(Omnijar::APP);
149 :
150 : nsCOMPtr<nsIProperties> dirSvc =
151 0 : do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
152 0 : if (!dirSvc) {
153 : return;
154 : }
155 :
156 : nsresult rv;
157 0 : nsCOMPtr<nsIFile> greDir;
158 0 : rv = dirSvc->Get(NS_GRE_DIR,
159 0 : NS_GET_IID(nsIFile), getter_AddRefs(greDir));
160 0 : if (NS_SUCCEEDED(rv)) {
161 0 : greDir->AppendNative(NS_LITERAL_CSTRING("hyphenation"));
162 0 : LoadPatternListFromDir(greDir);
163 : }
164 :
165 0 : nsCOMPtr<nsIFile> appDir;
166 0 : rv = dirSvc->Get(NS_XPCOM_CURRENT_PROCESS_DIR,
167 0 : NS_GET_IID(nsIFile), getter_AddRefs(appDir));
168 0 : if (NS_SUCCEEDED(rv)) {
169 0 : appDir->AppendNative(NS_LITERAL_CSTRING("hyphenation"));
170 : bool equals;
171 0 : if (NS_SUCCEEDED(appDir->Equals(greDir, &equals)) && !equals) {
172 0 : LoadPatternListFromDir(appDir);
173 : }
174 : }
175 : }
176 :
177 : void
178 0 : nsHyphenationManager::LoadPatternListFromOmnijar(Omnijar::Type aType)
179 : {
180 0 : nsCString base;
181 0 : nsresult rv = Omnijar::GetURIString(aType, base);
182 0 : if (NS_FAILED(rv)) {
183 : return;
184 : }
185 :
186 0 : nsRefPtr<nsZipArchive> zip = Omnijar::GetReader(aType);
187 0 : if (!zip) {
188 : return;
189 : }
190 :
191 : nsZipFind *find;
192 0 : zip->FindInit("hyphenation/hyph_*.dic", &find);
193 0 : if (!find) {
194 : return;
195 : }
196 :
197 : const char *result;
198 : PRUint16 len;
199 0 : while (NS_SUCCEEDED(find->FindNext(&result, &len))) {
200 0 : nsCString uriString(base);
201 0 : uriString.Append(result, len);
202 0 : nsCOMPtr<nsIURI> uri;
203 0 : rv = NS_NewURI(getter_AddRefs(uri), uriString);
204 0 : if (NS_FAILED(rv)) {
205 0 : continue;
206 : }
207 0 : nsCString locale;
208 0 : rv = uri->GetPath(locale);
209 0 : if (NS_FAILED(rv)) {
210 0 : continue;
211 : }
212 0 : ToLowerCase(locale);
213 0 : locale.SetLength(locale.Length() - 4); // strip ".dic"
214 0 : locale.Cut(0, locale.RFindChar('/') + 1); // strip directory
215 0 : if (StringBeginsWith(locale, NS_LITERAL_CSTRING("hyph_"))) {
216 0 : locale.Cut(0, 5);
217 : }
218 0 : for (PRUint32 i = 0; i < locale.Length(); ++i) {
219 0 : if (locale[i] == '_') {
220 0 : locale.Replace(i, 1, '-');
221 : }
222 : }
223 0 : nsCOMPtr<nsIAtom> localeAtom = do_GetAtom(locale);
224 0 : if (NS_SUCCEEDED(rv)) {
225 0 : mPatternFiles.Put(localeAtom, uri);
226 : }
227 : }
228 :
229 0 : delete find;
230 : }
231 :
232 : void
233 0 : nsHyphenationManager::LoadPatternListFromDir(nsIFile *aDir)
234 : {
235 : nsresult rv;
236 :
237 0 : bool check = false;
238 0 : rv = aDir->Exists(&check);
239 0 : if (NS_FAILED(rv) || !check) {
240 0 : return;
241 : }
242 :
243 0 : rv = aDir->IsDirectory(&check);
244 0 : if (NS_FAILED(rv) || !check) {
245 0 : return;
246 : }
247 :
248 0 : nsCOMPtr<nsISimpleEnumerator> e;
249 0 : rv = aDir->GetDirectoryEntries(getter_AddRefs(e));
250 0 : if (NS_FAILED(rv)) {
251 : return;
252 : }
253 :
254 0 : nsCOMPtr<nsIDirectoryEnumerator> files(do_QueryInterface(e));
255 0 : if (!files) {
256 : return;
257 : }
258 :
259 0 : nsCOMPtr<nsIFile> file;
260 0 : while (NS_SUCCEEDED(files->GetNextFile(getter_AddRefs(file))) && file){
261 0 : nsAutoString dictName;
262 0 : file->GetLeafName(dictName);
263 0 : NS_ConvertUTF16toUTF8 locale(dictName);
264 0 : ToLowerCase(locale);
265 0 : if (!StringEndsWith(locale, NS_LITERAL_CSTRING(".dic"))) {
266 0 : continue;
267 : }
268 0 : if (StringBeginsWith(locale, NS_LITERAL_CSTRING("hyph_"))) {
269 0 : locale.Cut(0, 5);
270 : }
271 0 : locale.SetLength(locale.Length() - 4); // strip ".dic"
272 0 : for (PRUint32 i = 0; i < locale.Length(); ++i) {
273 0 : if (locale[i] == '_') {
274 0 : locale.Replace(i, 1, '-');
275 : }
276 : }
277 : #ifdef DEBUG_hyph
278 : printf("adding hyphenation patterns for %s: %s\n", locale.get(),
279 : NS_ConvertUTF16toUTF8(dictName).get());
280 : #endif
281 0 : nsCOMPtr<nsIAtom> localeAtom = do_GetAtom(locale);
282 0 : nsCOMPtr<nsIURI> uri;
283 0 : nsresult rv = NS_NewFileURI(getter_AddRefs(uri), file);
284 0 : if (NS_SUCCEEDED(rv)) {
285 0 : mPatternFiles.Put(localeAtom, uri);
286 : }
287 : }
288 : }
289 :
290 : void
291 0 : nsHyphenationManager::LoadAliases()
292 : {
293 0 : nsIPrefBranch* prefRootBranch = Preferences::GetRootBranch();
294 0 : if (!prefRootBranch) {
295 0 : return;
296 : }
297 : PRUint32 prefCount;
298 : char **prefNames;
299 : nsresult rv = prefRootBranch->GetChildList(INTL_HYPHENATIONALIAS_PREFIX,
300 0 : &prefCount, &prefNames);
301 0 : if (NS_SUCCEEDED(rv) && prefCount > 0) {
302 0 : for (PRUint32 i = 0; i < prefCount; ++i) {
303 0 : nsAdoptingCString value = Preferences::GetCString(prefNames[i]);
304 0 : if (value) {
305 0 : nsCAutoString alias(prefNames[i]);
306 0 : alias.Cut(0, strlen(INTL_HYPHENATIONALIAS_PREFIX));
307 0 : ToLowerCase(alias);
308 0 : ToLowerCase(value);
309 0 : nsCOMPtr<nsIAtom> aliasAtom = do_GetAtom(alias);
310 0 : nsCOMPtr<nsIAtom> valueAtom = do_GetAtom(value);
311 0 : mHyphAliases.Put(aliasAtom, valueAtom);
312 : }
313 : }
314 0 : NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, prefNames);
315 : }
316 : }
|