1 /*
2 *******************************************************************************
3 * Copyright (C) 1997-2009,2014 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 "unicode/uset.h"
24 #include "uenumimp.h"
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
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 */
68 virtual UClassID getDynamicClassID() const;
69
70 /**
71 * ICU "poor man's RTTI", returns a UClassID for this class.
72 *
73 * @draft ICU 2.2
74 */
75 static UClassID U_EXPORT2 getStaticClassID();
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
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ReplaceableGlue)86 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ReplaceableGlue)
87
88 ReplaceableGlue::ReplaceableGlue(UReplaceable *replaceable,
89 UReplaceableCallbacks *funcCallback)
90 : Replaceable()
91 {
92 this->rep = replaceable;
93 this->func = funcCallback;
94 }
95
~ReplaceableGlue()96 ReplaceableGlue::~ReplaceableGlue() {}
97
getLength() const98 int32_t ReplaceableGlue::getLength() const {
99 return (*func->length)(rep);
100 }
101
getCharAt(int32_t offset) const102 UChar ReplaceableGlue::getCharAt(int32_t offset) const {
103 return (*func->charAt)(rep, offset);
104 }
105
getChar32At(int32_t offset) const106 UChar32 ReplaceableGlue::getChar32At(int32_t offset) const {
107 return (*func->char32At)(rep, offset);
108 }
109
handleReplaceBetween(int32_t start,int32_t limit,const UnicodeString & text)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
extractBetween(int32_t start,int32_t limit,UnicodeString & target) const116 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
copy(int32_t start,int32_t limit,int32_t dest)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
131
132 U_CAPI UTransliterator* U_EXPORT2
utrans_openU(const UChar * id,int32_t idLength,UTransDirection dir,const UChar * rules,int32_t rulesLength,UParseError * parseError,UErrorCode * status)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)) {
141 return NULL;
142 }
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
153 UnicodeString ID(idLength<0, id, idLength); // r-o alias
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
170 Transliterator *trans = NULL;
171 trans = Transliterator::createFromRules(ID, ruleStr, dir, *parseError, *status);
172 if(U_FAILURE(*status)) {
173 return NULL;
174 }
175
176 return (UTransliterator*) trans;
177 }
178 }
179
180 U_CAPI UTransliterator* U_EXPORT2
utrans_open(const char * id,UTransDirection dir,const UChar * rules,int32_t rulesLength,UParseError * parseError,UErrorCode * status)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) {
187 UnicodeString ID(id, -1, US_INV); // use invariant converter
188 return utrans_openU(ID.getBuffer(), ID.length(), dir,
189 rules, rulesLength,
190 parseError, status);
191 }
192
193 U_CAPI UTransliterator* U_EXPORT2
utrans_openInverse(const UTransliterator * trans,UErrorCode * status)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
utrans_clone(const UTransliterator * trans,UErrorCode * status)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
utrans_close(UTransliterator * trans)224 utrans_close(UTransliterator* trans) {
225 delete (Transliterator*) trans;
226 }
227
228 U_CAPI const UChar * U_EXPORT2
utrans_getUnicodeID(const UTransliterator * trans,int32_t * resultLength)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
239 U_CAPI int32_t U_EXPORT2
utrans_getID(const UTransliterator * trans,char * buf,int32_t bufCapacity)240 utrans_getID(const UTransliterator* trans,
241 char* buf,
242 int32_t bufCapacity) {
243 return ((Transliterator*) trans)->getID().extract(0, 0x7fffffff, buf, bufCapacity, US_INV);
244 }
245
246 U_CAPI void U_EXPORT2
utrans_register(UTransliterator * adoptedTrans,UErrorCode * status)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
254 U_CAPI void U_EXPORT2
utrans_unregisterID(const UChar * id,int32_t idLength)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
260 U_CAPI void U_EXPORT2
utrans_unregister(const char * id)261 utrans_unregister(const char* id) {
262 UnicodeString ID(id, -1, US_INV); // use invariant converter
263 Transliterator::unregister(ID);
264 }
265
266 U_CAPI void U_EXPORT2
utrans_setFilter(UTransliterator * trans,const UChar * filterPattern,int32_t filterPatternLen,UErrorCode * status)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
utrans_countAvailableIDs(void)292 utrans_countAvailableIDs(void) {
293 return Transliterator::countAvailableIDs();
294 }
295
296 U_CAPI int32_t U_EXPORT2
utrans_getAvailableID(int32_t index,char * buf,int32_t bufCapacity)297 utrans_getAvailableID(int32_t index,
298 char* buf, // may be NULL
299 int32_t bufCapacity) {
300 return Transliterator::getAvailableID(index).extract(0, 0x7fffffff, buf, bufCapacity, US_INV);
301 }
302
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
utrans_enum_count(UEnumeration * uenum,UErrorCode * pErrorCode)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
utrans_enum_unext(UEnumeration * uenum,int32_t * resultLength,UErrorCode * pErrorCode)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
utrans_enum_reset(UEnumeration * uenum,UErrorCode * pErrorCode)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
utrans_enum_close(UEnumeration * uenum)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
utrans_openIDs(UErrorCode * pErrorCode)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
392 /********************************************************************
393 * Transliteration API
394 ********************************************************************/
395
396 U_CAPI void U_EXPORT2
utrans_trans(const UTransliterator * trans,UReplaceable * rep,UReplaceableCallbacks * repFunc,int32_t start,int32_t * limit,UErrorCode * status)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
utrans_transIncremental(const UTransliterator * trans,UReplaceable * rep,UReplaceableCallbacks * repFunc,UTransPosition * pos,UErrorCode * status)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
utrans_transUChars(const UTransliterator * trans,UChar * text,int32_t * textLength,int32_t textCapacity,int32_t start,int32_t * limit,UErrorCode * status)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
utrans_transIncrementalUChars(const UTransliterator * trans,UChar * text,int32_t * textLength,int32_t textCapacity,UTransPosition * pos,UErrorCode * status)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
496 U_CAPI int32_t U_EXPORT2
utrans_toRules(const UTransliterator * trans,UBool escapeUnprintable,UChar * result,int32_t resultLength,UErrorCode * status)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
utrans_getSourceSet(const UTransliterator * trans,UBool ignoreFilter,USet * fillIn,UErrorCode * status)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
531 #endif /* #if !UCONFIG_NO_TRANSLITERATION */
532