• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  ************************************************************************************
3  * Copyright (C) 2006-2007, International Business Machines Corporation and others. *
4  * All Rights Reserved.                                                             *
5  ************************************************************************************
6  */
7 
8 #include "unicode/utypes.h"
9 
10 #if !UCONFIG_NO_BREAK_ITERATION
11 
12 #include "brkeng.h"
13 #include "dictbe.h"
14 #include "triedict.h"
15 #include "unicode/uchar.h"
16 #include "unicode/uniset.h"
17 #include "unicode/chariter.h"
18 #include "unicode/ures.h"
19 #include "unicode/udata.h"
20 #include "unicode/putil.h"
21 #include "unicode/ustring.h"
22 #include "unicode/uscript.h"
23 #include "uvector.h"
24 #include "umutex.h"
25 #include "uresimp.h"
26 #include "ubrkimpl.h"
27 
28 U_NAMESPACE_BEGIN
29 
30 /*
31  ******************************************************************
32  */
33 
LanguageBreakEngine()34 LanguageBreakEngine::LanguageBreakEngine() {
35 }
36 
~LanguageBreakEngine()37 LanguageBreakEngine::~LanguageBreakEngine() {
38 }
39 
40 /*
41  ******************************************************************
42  */
43 
LanguageBreakFactory()44 LanguageBreakFactory::LanguageBreakFactory() {
45 }
46 
~LanguageBreakFactory()47 LanguageBreakFactory::~LanguageBreakFactory() {
48 }
49 
50 /*
51  ******************************************************************
52  */
53 
UnhandledEngine(UErrorCode &)54 UnhandledEngine::UnhandledEngine(UErrorCode &/*status*/) {
55     for (int32_t i = 0; i < (int32_t)(sizeof(fHandled)/sizeof(fHandled[0])); ++i) {
56         fHandled[i] = 0;
57     }
58 }
59 
~UnhandledEngine()60 UnhandledEngine::~UnhandledEngine() {
61     for (int32_t i = 0; i < (int32_t)(sizeof(fHandled)/sizeof(fHandled[0])); ++i) {
62         if (fHandled[i] != 0) {
63             delete fHandled[i];
64         }
65     }
66 }
67 
68 UBool
handles(UChar32 c,int32_t breakType) const69 UnhandledEngine::handles(UChar32 c, int32_t breakType) const {
70     return (breakType >= 0 && breakType < (int32_t)(sizeof(fHandled)/sizeof(fHandled[0]))
71         && fHandled[breakType] != 0 && fHandled[breakType]->contains(c));
72 }
73 
74 int32_t
findBreaks(UText * text,int32_t startPos,int32_t endPos,UBool reverse,int32_t breakType,UStack &) const75 UnhandledEngine::findBreaks( UText *text,
76                                  int32_t startPos,
77                                  int32_t endPos,
78                                  UBool reverse,
79                                  int32_t breakType,
80                                  UStack &/*foundBreaks*/ ) const {
81     if (breakType >= 0 && breakType < (int32_t)(sizeof(fHandled)/sizeof(fHandled[0]))) {
82         UChar32 c = utext_current32(text);
83         if (reverse) {
84             while((int32_t)utext_getNativeIndex(text) > startPos && fHandled[breakType]->contains(c)) {
85                 c = utext_previous32(text);
86             }
87         }
88         else {
89             while((int32_t)utext_getNativeIndex(text) < endPos && fHandled[breakType]->contains(c)) {
90                 utext_next32(text);            // TODO:  recast loop to work with post-increment operations.
91                 c = utext_current32(text);
92             }
93         }
94     }
95     return 0;
96 }
97 
98 void
handleCharacter(UChar32 c,int32_t breakType)99 UnhandledEngine::handleCharacter(UChar32 c, int32_t breakType) {
100     if (breakType >= 0 && breakType < (int32_t)(sizeof(fHandled)/sizeof(fHandled[0]))) {
101         if (fHandled[breakType] == 0) {
102             fHandled[breakType] = new UnicodeSet();
103             if (fHandled[breakType] == 0) {
104                 return;
105             }
106         }
107         if (!fHandled[breakType]->contains(c)) {
108             UErrorCode status = U_ZERO_ERROR;
109             // Apply the entire script of the character.
110             int32_t script = u_getIntPropertyValue(c, UCHAR_SCRIPT);
111             fHandled[breakType]->applyIntPropertyValue(UCHAR_SCRIPT, script, status);
112         }
113     }
114 }
115 
116 /*
117  ******************************************************************
118  */
119 
ICULanguageBreakFactory(UErrorCode &)120 ICULanguageBreakFactory::ICULanguageBreakFactory(UErrorCode &/*status*/) {
121     fEngines = 0;
122 }
123 
~ICULanguageBreakFactory()124 ICULanguageBreakFactory::~ICULanguageBreakFactory() {
125     if (fEngines != 0) {
126         delete fEngines;
127     }
128 }
129 
130 U_NAMESPACE_END
131 U_CDECL_BEGIN
_deleteEngine(void * obj)132 static void U_CALLCONV _deleteEngine(void *obj) {
133     delete (const U_NAMESPACE_QUALIFIER LanguageBreakEngine *) obj;
134 }
135 U_CDECL_END
136 U_NAMESPACE_BEGIN
137 
138 const LanguageBreakEngine *
getEngineFor(UChar32 c,int32_t breakType)139 ICULanguageBreakFactory::getEngineFor(UChar32 c, int32_t breakType) {
140     UBool       needsInit;
141     int32_t     i;
142     const LanguageBreakEngine *lbe = NULL;
143     UErrorCode  status = U_ZERO_ERROR;
144 
145     // TODO: The global mutex should not be used.
146     // The global mutex should only be used for short periods.
147     // A ICULanguageBreakFactory specific mutex should be used.
148     umtx_lock(NULL);
149     needsInit = (UBool)(fEngines == NULL);
150     if (!needsInit) {
151         i = fEngines->size();
152         while (--i >= 0) {
153             lbe = (const LanguageBreakEngine *)(fEngines->elementAt(i));
154             if (lbe != NULL && lbe->handles(c, breakType)) {
155                 break;
156             }
157             lbe = NULL;
158         }
159     }
160     umtx_unlock(NULL);
161 
162     if (lbe != NULL) {
163         return lbe;
164     }
165 
166     if (needsInit) {
167         UStack  *engines = new UStack(_deleteEngine, NULL, status);
168         if (U_SUCCESS(status) && engines == NULL) {
169             status = U_MEMORY_ALLOCATION_ERROR;
170         }
171         else if (U_FAILURE(status)) {
172             delete engines;
173             engines = NULL;
174         }
175         else {
176             umtx_lock(NULL);
177             if (fEngines == NULL) {
178                 fEngines = engines;
179                 engines = NULL;
180             }
181             umtx_unlock(NULL);
182             delete engines;
183         }
184     }
185 
186     if (fEngines == NULL) {
187         return NULL;
188     }
189 
190     // We didn't find an engine the first time through, or there was no
191     // stack. Create an engine.
192     const LanguageBreakEngine *newlbe = loadEngineFor(c, breakType);
193 
194     // Now get the lock, and see if someone else has created it in the
195     // meantime
196     umtx_lock(NULL);
197     i = fEngines->size();
198     while (--i >= 0) {
199         lbe = (const LanguageBreakEngine *)(fEngines->elementAt(i));
200         if (lbe != NULL && lbe->handles(c, breakType)) {
201             break;
202         }
203         lbe = NULL;
204     }
205     if (lbe == NULL && newlbe != NULL) {
206         fEngines->push((void *)newlbe, status);
207         lbe = newlbe;
208         newlbe = NULL;
209     }
210     umtx_unlock(NULL);
211 
212     delete newlbe;
213 
214     return lbe;
215 }
216 
217 const LanguageBreakEngine *
loadEngineFor(UChar32 c,int32_t breakType)218 ICULanguageBreakFactory::loadEngineFor(UChar32 c, int32_t breakType) {
219     UErrorCode status = U_ZERO_ERROR;
220     UScriptCode code = uscript_getScript(c, &status);
221     if (U_SUCCESS(status)) {
222         const CompactTrieDictionary *dict = loadDictionaryFor(code, breakType);
223         if (dict != NULL) {
224             const LanguageBreakEngine *engine = NULL;
225             switch(code) {
226             case USCRIPT_THAI:
227                 engine = new ThaiBreakEngine(dict, status);
228                 break;
229             default:
230                 break;
231             }
232             if (engine == NULL) {
233                 delete dict;
234             }
235             else if (U_FAILURE(status)) {
236                 delete engine;
237                 engine = NULL;
238             }
239             return engine;
240         }
241     }
242     return NULL;
243 }
244 
245 const CompactTrieDictionary *
loadDictionaryFor(UScriptCode script,int32_t)246 ICULanguageBreakFactory::loadDictionaryFor(UScriptCode script, int32_t /*breakType*/) {
247     UErrorCode status = U_ZERO_ERROR;
248     // Open root from brkitr tree.
249     char dictnbuff[256];
250     char ext[4]={'\0'};
251 
252     UResourceBundle *b = ures_open(U_ICUDATA_BRKITR, "", &status);
253     b = ures_getByKeyWithFallback(b, "dictionaries", b, &status);
254     b = ures_getByKeyWithFallback(b, uscript_getShortName(script), b, &status);
255     int32_t dictnlength = 0;
256     const UChar *dictfname = ures_getString(b, &dictnlength, &status);
257     if (U_SUCCESS(status) && (size_t)dictnlength >= sizeof(dictnbuff)) {
258         dictnlength = 0;
259         status = U_BUFFER_OVERFLOW_ERROR;
260     }
261     if (U_SUCCESS(status) && dictfname) {
262         UChar* extStart=u_strchr(dictfname, 0x002e);
263         int len = 0;
264         if(extStart!=NULL){
265             len = extStart-dictfname;
266             u_UCharsToChars(extStart+1, ext, sizeof(ext)); // nul terminates the buff
267             u_UCharsToChars(dictfname, dictnbuff, len);
268         }
269         dictnbuff[len]=0; // nul terminate
270     }
271     ures_close(b);
272     UDataMemory *file = udata_open(U_ICUDATA_BRKITR, ext, dictnbuff, &status);
273     if (U_SUCCESS(status)) {
274         const CompactTrieDictionary *dict = new CompactTrieDictionary(
275             file, status);
276         if (U_SUCCESS(status) && dict == NULL) {
277             status = U_MEMORY_ALLOCATION_ERROR;
278         }
279         if (U_FAILURE(status)) {
280             delete dict;
281             dict = NULL;
282         }
283         return dict;
284     }
285     return NULL;
286 }
287 
288 U_NAMESPACE_END
289 
290 #endif /* #if !UCONFIG_NO_BREAK_ITERATION */
291