Home | History | Annotate | Download | only in i18n
      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 */
    496