| |
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 */ |