|
1 /* |
|
2 ******************************************************************************* |
|
3 * Copyright (C) 1997-2009, International Business Machines |
|
4 * Corporation and others. All Rights Reserved. |
|
5 ******************************************************************************* |
|
6 * Date Name Description |
|
7 * 06/21/00 aliu Creation. |
|
8 ******************************************************************************* |
|
9 */ |
|
10 |
|
11 #include "unicode/utypes.h" |
|
12 |
|
13 #if !UCONFIG_NO_TRANSLITERATION |
|
14 |
|
15 #include "unicode/utrans.h" |
|
16 #include "unicode/putil.h" |
|
17 #include "unicode/rep.h" |
|
18 #include "unicode/translit.h" |
|
19 #include "unicode/unifilt.h" |
|
20 #include "unicode/uniset.h" |
|
21 #include "unicode/ustring.h" |
|
22 #include "unicode/uenum.h" |
|
23 #include "uenumimp.h" |
|
24 #include "cpputils.h" |
|
25 #include "rbt.h" |
|
26 |
|
27 // Following macro is to be followed by <return value>';' or just ';' |
|
28 #define utrans_ENTRY(s) if ((s)==NULL || U_FAILURE(*(s))) return |
|
29 |
|
30 /******************************************************************** |
|
31 * Replaceable-UReplaceableCallbacks glue |
|
32 ********************************************************************/ |
|
33 |
|
34 /** |
|
35 * Make a UReplaceable + UReplaceableCallbacks into a Replaceable object. |
|
36 */ |
|
37 U_NAMESPACE_BEGIN |
|
38 class ReplaceableGlue : public Replaceable { |
|
39 |
|
40 UReplaceable *rep; |
|
41 UReplaceableCallbacks *func; |
|
42 |
|
43 public: |
|
44 |
|
45 ReplaceableGlue(UReplaceable *replaceable, |
|
46 UReplaceableCallbacks *funcCallback); |
|
47 |
|
48 virtual ~ReplaceableGlue(); |
|
49 |
|
50 virtual void handleReplaceBetween(int32_t start, |
|
51 int32_t limit, |
|
52 const UnicodeString& text); |
|
53 |
|
54 virtual void extractBetween(int32_t start, |
|
55 int32_t limit, |
|
56 UnicodeString& target) const; |
|
57 |
|
58 virtual void copy(int32_t start, int32_t limit, int32_t dest); |
|
59 |
|
60 // virtual Replaceable *clone() const { return NULL; } same as default |
|
61 |
|
62 /** |
|
63 * ICU "poor man's RTTI", returns a UClassID for the actual class. |
|
64 * |
|
65 * @draft ICU 2.2 |
|
66 */ |
|
67 virtual UClassID getDynamicClassID() const; |
|
68 |
|
69 /** |
|
70 * ICU "poor man's RTTI", returns a UClassID for this class. |
|
71 * |
|
72 * @draft ICU 2.2 |
|
73 */ |
|
74 static UClassID U_EXPORT2 getStaticClassID(); |
|
75 |
|
76 protected: |
|
77 |
|
78 virtual int32_t getLength() const; |
|
79 |
|
80 virtual UChar getCharAt(int32_t offset) const; |
|
81 |
|
82 virtual UChar32 getChar32At(int32_t offset) const; |
|
83 }; |
|
84 |
|
85 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ReplaceableGlue) |
|
86 |
|
87 ReplaceableGlue::ReplaceableGlue(UReplaceable *replaceable, |
|
88 UReplaceableCallbacks *funcCallback) |
|
89 : Replaceable() |
|
90 { |
|
91 this->rep = replaceable; |
|
92 this->func = funcCallback; |
|
93 } |
|
94 |
|
95 ReplaceableGlue::~ReplaceableGlue() {} |
|
96 |
|
97 int32_t ReplaceableGlue::getLength() const { |
|
98 return (*func->length)(rep); |
|
99 } |
|
100 |
|
101 UChar ReplaceableGlue::getCharAt(int32_t offset) const { |
|
102 return (*func->charAt)(rep, offset); |
|
103 } |
|
104 |
|
105 UChar32 ReplaceableGlue::getChar32At(int32_t offset) const { |
|
106 return (*func->char32At)(rep, offset); |
|
107 } |
|
108 |
|
109 void ReplaceableGlue::handleReplaceBetween(int32_t start, |
|
110 int32_t limit, |
|
111 const UnicodeString& text) { |
|
112 (*func->replace)(rep, start, limit, text.getBuffer(), text.length()); |
|
113 } |
|
114 |
|
115 void ReplaceableGlue::extractBetween(int32_t start, |
|
116 int32_t limit, |
|
117 UnicodeString& target) const { |
|
118 (*func->extract)(rep, start, limit, target.getBuffer(limit-start)); |
|
119 target.releaseBuffer(limit-start); |
|
120 } |
|
121 |
|
122 void ReplaceableGlue::copy(int32_t start, int32_t limit, int32_t dest) { |
|
123 (*func->copy)(rep, start, limit, dest); |
|
124 } |
|
125 U_NAMESPACE_END |
|
126 /******************************************************************** |
|
127 * General API |
|
128 ********************************************************************/ |
|
129 U_NAMESPACE_USE |
|
130 |
|
131 U_CAPI UTransliterator* U_EXPORT2 |
|
132 utrans_openU(const UChar *id, |
|
133 int32_t idLength, |
|
134 UTransDirection dir, |
|
135 const UChar *rules, |
|
136 int32_t rulesLength, |
|
137 UParseError *parseError, |
|
138 UErrorCode *status) { |
|
139 if(status==NULL || U_FAILURE(*status)) { |
|
140 return NULL; |
|
141 } |
|
142 if (id == NULL) { |
|
143 *status = U_ILLEGAL_ARGUMENT_ERROR; |
|
144 return NULL; |
|
145 } |
|
146 UParseError temp; |
|
147 |
|
148 if(parseError == NULL){ |
|
149 parseError = &temp; |
|
150 } |
|
151 |
|
152 UnicodeString ID(idLength<0, id, idLength); // r-o alias |
|
153 |
|
154 if(rules==NULL){ |
|
155 |
|
156 Transliterator *trans = NULL; |
|
157 |
|
158 trans = Transliterator::createInstance(ID, dir, *parseError, *status); |
|
159 |
|
160 if(U_FAILURE(*status)){ |
|
161 return NULL; |
|
162 } |
|
163 return (UTransliterator*) trans; |
|
164 }else{ |
|
165 UnicodeString ruleStr(rulesLength < 0, |
|
166 rules, |
|
167 rulesLength); // r-o alias |
|
168 |
|
169 Transliterator *trans = NULL; |
|
170 trans = Transliterator::createFromRules(ID, ruleStr, dir, *parseError, *status); |
|
171 if(U_FAILURE(*status)) { |
|
172 return NULL; |
|
173 } |
|
174 |
|
175 return (UTransliterator*) trans; |
|
176 } |
|
177 } |
|
178 |
|
179 U_CAPI UTransliterator* U_EXPORT2 |
|
180 utrans_open(const char* id, |
|
181 UTransDirection dir, |
|
182 const UChar* rules, /* may be Null */ |
|
183 int32_t rulesLength, /* -1 if null-terminated */ |
|
184 UParseError* parseError, /* may be Null */ |
|
185 UErrorCode* status) { |
|
186 UnicodeString ID(id, -1, US_INV); // use invariant converter |
|
187 return utrans_openU(ID.getBuffer(), ID.length(), dir, |
|
188 rules, rulesLength, |
|
189 parseError, status); |
|
190 } |
|
191 |
|
192 U_CAPI UTransliterator* U_EXPORT2 |
|
193 utrans_openInverse(const UTransliterator* trans, |
|
194 UErrorCode* status) { |
|
195 |
|
196 utrans_ENTRY(status) NULL; |
|
197 |
|
198 UTransliterator* result = |
|
199 (UTransliterator*) ((Transliterator*) trans)->createInverse(*status); |
|
200 |
|
201 return result; |
|
202 } |
|
203 |
|
204 U_CAPI UTransliterator* U_EXPORT2 |
|
205 utrans_clone(const UTransliterator* trans, |
|
206 UErrorCode* status) { |
|
207 |
|
208 utrans_ENTRY(status) NULL; |
|
209 |
|
210 if (trans == NULL) { |
|
211 *status = U_ILLEGAL_ARGUMENT_ERROR; |
|
212 return NULL; |
|
213 } |
|
214 |
|
215 Transliterator *t = ((Transliterator*) trans)->clone(); |
|
216 if (t == NULL) { |
|
217 *status = U_MEMORY_ALLOCATION_ERROR; |
|
218 } |
|
219 return (UTransliterator*) t; |
|
220 } |
|
221 |
|
222 U_CAPI void U_EXPORT2 |
|
223 utrans_close(UTransliterator* trans) { |
|
224 delete (Transliterator*) trans; |
|
225 } |
|
226 |
|
227 U_CAPI const UChar * U_EXPORT2 |
|
228 utrans_getUnicodeID(const UTransliterator *trans, |
|
229 int32_t *resultLength) { |
|
230 // Transliterator keeps its ID NUL-terminated |
|
231 const UnicodeString &ID=((Transliterator*) trans)->getID(); |
|
232 if(resultLength!=NULL) { |
|
233 *resultLength=ID.length(); |
|
234 } |
|
235 return ID.getBuffer(); |
|
236 } |
|
237 |
|
238 U_CAPI int32_t U_EXPORT2 |
|
239 utrans_getID(const UTransliterator* trans, |
|
240 char* buf, |
|
241 int32_t bufCapacity) { |
|
242 return ((Transliterator*) trans)->getID().extract(0, 0x7fffffff, buf, bufCapacity, US_INV); |
|
243 } |
|
244 |
|
245 U_CAPI void U_EXPORT2 |
|
246 utrans_register(UTransliterator* adoptedTrans, |
|
247 UErrorCode* status) { |
|
248 utrans_ENTRY(status); |
|
249 // status currently ignored; may remove later |
|
250 Transliterator::registerInstance((Transliterator*) adoptedTrans); |
|
251 } |
|
252 |
|
253 U_CAPI void U_EXPORT2 |
|
254 utrans_unregisterID(const UChar* id, int32_t idLength) { |
|
255 UnicodeString ID(idLength<0, id, idLength); // r-o alias |
|
256 Transliterator::unregister(ID); |
|
257 } |
|
258 |
|
259 U_CAPI void U_EXPORT2 |
|
260 utrans_unregister(const char* id) { |
|
261 UnicodeString ID(id, -1, US_INV); // use invariant converter |
|
262 Transliterator::unregister(ID); |
|
263 } |
|
264 |
|
265 U_CAPI void U_EXPORT2 |
|
266 utrans_setFilter(UTransliterator* trans, |
|
267 const UChar* filterPattern, |
|
268 int32_t filterPatternLen, |
|
269 UErrorCode* status) { |
|
270 |
|
271 utrans_ENTRY(status); |
|
272 UnicodeFilter* filter = NULL; |
|
273 if (filterPattern != NULL && *filterPattern != 0) { |
|
274 // Create read only alias of filterPattern: |
|
275 UnicodeString pat(filterPatternLen < 0, filterPattern, filterPatternLen); |
|
276 filter = new UnicodeSet(pat, *status); |
|
277 /* test for NULL */ |
|
278 if (filter == NULL) { |
|
279 *status = U_MEMORY_ALLOCATION_ERROR; |
|
280 return; |
|
281 } |
|
282 if (U_FAILURE(*status)) { |
|
283 delete filter; |
|
284 filter = NULL; |
|
285 } |
|
286 } |
|
287 ((Transliterator*) trans)->adoptFilter(filter); |
|
288 } |
|
289 |
|
290 U_CAPI int32_t U_EXPORT2 |
|
291 utrans_countAvailableIDs(void) { |
|
292 return Transliterator::countAvailableIDs(); |
|
293 } |
|
294 |
|
295 U_CAPI int32_t U_EXPORT2 |
|
296 utrans_getAvailableID(int32_t index, |
|
297 char* buf, // may be NULL |
|
298 int32_t bufCapacity) { |
|
299 return Transliterator::getAvailableID(index).extract(0, 0x7fffffff, buf, bufCapacity, US_INV); |
|
300 } |
|
301 |
|
302 /* Transliterator UEnumeration ---------------------------------------------- */ |
|
303 |
|
304 typedef struct UTransEnumeration { |
|
305 UEnumeration uenum; |
|
306 int32_t index, count; |
|
307 } UTransEnumeration; |
|
308 |
|
309 U_CDECL_BEGIN |
|
310 static int32_t U_CALLCONV |
|
311 utrans_enum_count(UEnumeration *uenum, UErrorCode *pErrorCode) { |
|
312 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { |
|
313 return 0; |
|
314 } |
|
315 return ((UTransEnumeration *)uenum)->count; |
|
316 } |
|
317 |
|
318 static const UChar* U_CALLCONV |
|
319 utrans_enum_unext(UEnumeration *uenum, |
|
320 int32_t* resultLength, |
|
321 UErrorCode *pErrorCode) { |
|
322 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { |
|
323 return 0; |
|
324 } |
|
325 |
|
326 UTransEnumeration *ute=(UTransEnumeration *)uenum; |
|
327 int32_t index=ute->index; |
|
328 if(index<ute->count) { |
|
329 const UnicodeString &ID=Transliterator::getAvailableID(index); |
|
330 ute->index=index+1; |
|
331 if(resultLength!=NULL) { |
|
332 *resultLength=ID.length(); |
|
333 } |
|
334 // Transliterator keeps its ID NUL-terminated |
|
335 return ID.getBuffer(); |
|
336 } |
|
337 |
|
338 if(resultLength!=NULL) { |
|
339 *resultLength=0; |
|
340 } |
|
341 return NULL; |
|
342 } |
|
343 |
|
344 static void U_CALLCONV |
|
345 utrans_enum_reset(UEnumeration *uenum, UErrorCode *pErrorCode) { |
|
346 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { |
|
347 return; |
|
348 } |
|
349 |
|
350 UTransEnumeration *ute=(UTransEnumeration *)uenum; |
|
351 ute->index=0; |
|
352 ute->count=Transliterator::countAvailableIDs(); |
|
353 } |
|
354 |
|
355 static void U_CALLCONV |
|
356 utrans_enum_close(UEnumeration *uenum) { |
|
357 uprv_free(uenum); |
|
358 } |
|
359 U_CDECL_END |
|
360 |
|
361 static const UEnumeration utransEnumeration={ |
|
362 NULL, |
|
363 NULL, |
|
364 utrans_enum_close, |
|
365 utrans_enum_count, |
|
366 utrans_enum_unext, |
|
367 uenum_nextDefault, |
|
368 utrans_enum_reset |
|
369 }; |
|
370 |
|
371 U_CAPI UEnumeration * U_EXPORT2 |
|
372 utrans_openIDs(UErrorCode *pErrorCode) { |
|
373 UTransEnumeration *ute; |
|
374 |
|
375 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { |
|
376 return NULL; |
|
377 } |
|
378 |
|
379 ute=(UTransEnumeration *)uprv_malloc(sizeof(UTransEnumeration)); |
|
380 if(ute==NULL) { |
|
381 *pErrorCode=U_MEMORY_ALLOCATION_ERROR; |
|
382 return NULL; |
|
383 } |
|
384 |
|
385 ute->uenum=utransEnumeration; |
|
386 ute->index=0; |
|
387 ute->count=Transliterator::countAvailableIDs(); |
|
388 return (UEnumeration *)ute; |
|
389 } |
|
390 |
|
391 /******************************************************************** |
|
392 * Transliteration API |
|
393 ********************************************************************/ |
|
394 |
|
395 U_CAPI void U_EXPORT2 |
|
396 utrans_trans(const UTransliterator* trans, |
|
397 UReplaceable* rep, |
|
398 UReplaceableCallbacks* repFunc, |
|
399 int32_t start, |
|
400 int32_t* limit, |
|
401 UErrorCode* status) { |
|
402 |
|
403 utrans_ENTRY(status); |
|
404 |
|
405 if (trans == 0 || rep == 0 || repFunc == 0 || limit == 0) { |
|
406 *status = U_ILLEGAL_ARGUMENT_ERROR; |
|
407 return; |
|
408 } |
|
409 |
|
410 ReplaceableGlue r(rep, repFunc); |
|
411 |
|
412 *limit = ((Transliterator*) trans)->transliterate(r, start, *limit); |
|
413 } |
|
414 |
|
415 U_CAPI void U_EXPORT2 |
|
416 utrans_transIncremental(const UTransliterator* trans, |
|
417 UReplaceable* rep, |
|
418 UReplaceableCallbacks* repFunc, |
|
419 UTransPosition* pos, |
|
420 UErrorCode* status) { |
|
421 |
|
422 utrans_ENTRY(status); |
|
423 |
|
424 if (trans == 0 || rep == 0 || repFunc == 0 || pos == 0) { |
|
425 *status = U_ILLEGAL_ARGUMENT_ERROR; |
|
426 return; |
|
427 } |
|
428 |
|
429 ReplaceableGlue r(rep, repFunc); |
|
430 |
|
431 ((Transliterator*) trans)->transliterate(r, *pos, *status); |
|
432 } |
|
433 |
|
434 U_CAPI void U_EXPORT2 |
|
435 utrans_transUChars(const UTransliterator* trans, |
|
436 UChar* text, |
|
437 int32_t* textLength, |
|
438 int32_t textCapacity, |
|
439 int32_t start, |
|
440 int32_t* limit, |
|
441 UErrorCode* status) { |
|
442 |
|
443 utrans_ENTRY(status); |
|
444 |
|
445 if (trans == 0 || text == 0 || limit == 0) { |
|
446 *status = U_ILLEGAL_ARGUMENT_ERROR; |
|
447 return; |
|
448 } |
|
449 |
|
450 int32_t textLen = (textLength == NULL || *textLength < 0) |
|
451 ? u_strlen(text) : *textLength; |
|
452 // writeable alias: for this ct, len CANNOT be -1 (why?) |
|
453 UnicodeString str(text, textLen, textCapacity); |
|
454 |
|
455 *limit = ((Transliterator*) trans)->transliterate(str, start, *limit); |
|
456 |
|
457 // Copy the string buffer back to text (only if necessary) |
|
458 // and fill in *neededCapacity (if neededCapacity != NULL). |
|
459 textLen = str.extract(text, textCapacity, *status); |
|
460 if(textLength != NULL) { |
|
461 *textLength = textLen; |
|
462 } |
|
463 } |
|
464 |
|
465 U_CAPI void U_EXPORT2 |
|
466 utrans_transIncrementalUChars(const UTransliterator* trans, |
|
467 UChar* text, |
|
468 int32_t* textLength, |
|
469 int32_t textCapacity, |
|
470 UTransPosition* pos, |
|
471 UErrorCode* status) { |
|
472 |
|
473 utrans_ENTRY(status); |
|
474 |
|
475 if (trans == 0 || text == 0 || pos == 0) { |
|
476 *status = U_ILLEGAL_ARGUMENT_ERROR; |
|
477 return; |
|
478 } |
|
479 |
|
480 int32_t textLen = (textLength == NULL || *textLength < 0) |
|
481 ? u_strlen(text) : *textLength; |
|
482 // writeable alias: for this ct, len CANNOT be -1 (why?) |
|
483 UnicodeString str(text, textLen, textCapacity); |
|
484 |
|
485 ((Transliterator*) trans)->transliterate(str, *pos, *status); |
|
486 |
|
487 // Copy the string buffer back to text (only if necessary) |
|
488 // and fill in *neededCapacity (if neededCapacity != NULL). |
|
489 textLen = str.extract(text, textCapacity, *status); |
|
490 if(textLength != NULL) { |
|
491 *textLength = textLen; |
|
492 } |
|
493 } |
|
494 |
|
495 #endif /* #if !UCONFIG_NO_TRANSLITERATION */ |