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