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