534 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			534 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
| // © 2016 and later: Unicode, Inc. and others.
 | |
| // License & terms of use: http://www.unicode.org/copyright.html
 | |
| /*
 | |
|  *******************************************************************************
 | |
|  *   Copyright (C) 1997-2009,2014 International Business Machines
 | |
|  *   Corporation and others.  All Rights Reserved.
 | |
|  *******************************************************************************
 | |
|  *   Date        Name        Description
 | |
|  *   06/21/00    aliu        Creation.
 | |
|  *******************************************************************************
 | |
|  */
 | |
| 
 | |
| #include "unicode/utypes.h"
 | |
| 
 | |
| #if !UCONFIG_NO_TRANSLITERATION
 | |
| 
 | |
| #include "unicode/utrans.h"
 | |
| #include "unicode/putil.h"
 | |
| #include "unicode/rep.h"
 | |
| #include "unicode/translit.h"
 | |
| #include "unicode/unifilt.h"
 | |
| #include "unicode/uniset.h"
 | |
| #include "unicode/ustring.h"
 | |
| #include "unicode/uenum.h"
 | |
| #include "unicode/uset.h"
 | |
| #include "uenumimp.h"
 | |
| #include "cpputils.h"
 | |
| #include "rbt.h"
 | |
| 
 | |
| // Following macro is to be followed by <return value>';' or just ';'
 | |
| #define utrans_ENTRY(s) if ((s)==NULL || U_FAILURE(*(s))) return
 | |
| 
 | |
| /********************************************************************
 | |
|  * Replaceable-UReplaceableCallbacks glue
 | |
|  ********************************************************************/
 | |
| 
 | |
| /**
 | |
|  * Make a UReplaceable + UReplaceableCallbacks into a Replaceable object.
 | |
|  */
 | |
| U_NAMESPACE_BEGIN
 | |
| class ReplaceableGlue : public Replaceable {
 | |
| 
 | |
|     UReplaceable *rep;
 | |
|     const UReplaceableCallbacks *func;
 | |
| 
 | |
| public:
 | |
| 
 | |
|     ReplaceableGlue(UReplaceable *replaceable,
 | |
|                     const UReplaceableCallbacks *funcCallback);
 | |
| 
 | |
|     virtual ~ReplaceableGlue();
 | |
| 
 | |
|     virtual void handleReplaceBetween(int32_t start,
 | |
|                                       int32_t limit,
 | |
|                                       const UnicodeString& text) override;
 | |
| 
 | |
|     virtual void extractBetween(int32_t start,
 | |
|                                 int32_t limit,
 | |
|                                 UnicodeString& target) const override;
 | |
| 
 | |
|     virtual void copy(int32_t start, int32_t limit, int32_t dest) override;
 | |
| 
 | |
|     // virtual Replaceable *clone() const { return NULL; } same as default
 | |
| 
 | |
|     /**
 | |
|      * ICU "poor man's RTTI", returns a UClassID for the actual class.
 | |
|      *
 | |
|      * @draft ICU 2.2
 | |
|      */
 | |
|     virtual UClassID getDynamicClassID() const override;
 | |
| 
 | |
|     /**
 | |
|      * ICU "poor man's RTTI", returns a UClassID for this class.
 | |
|      *
 | |
|      * @draft ICU 2.2
 | |
|      */
 | |
|     static UClassID U_EXPORT2 getStaticClassID();
 | |
| 
 | |
| protected:
 | |
| 
 | |
|     virtual int32_t getLength() const override;
 | |
| 
 | |
|     virtual UChar getCharAt(int32_t offset) const override;
 | |
| 
 | |
|     virtual UChar32 getChar32At(int32_t offset) const override;
 | |
| };
 | |
| 
 | |
| UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ReplaceableGlue)
 | |
| 
 | |
| ReplaceableGlue::ReplaceableGlue(UReplaceable *replaceable,
 | |
|                                  const UReplaceableCallbacks *funcCallback)
 | |
|   : Replaceable()
 | |
| {
 | |
|     this->rep = replaceable;
 | |
|     this->func = funcCallback;
 | |
| }
 | |
| 
 | |
| ReplaceableGlue::~ReplaceableGlue() {}
 | |
| 
 | |
| int32_t ReplaceableGlue::getLength() const {
 | |
|     return (*func->length)(rep);
 | |
| }
 | |
| 
 | |
| UChar ReplaceableGlue::getCharAt(int32_t offset) const {
 | |
|     return (*func->charAt)(rep, offset);
 | |
| }
 | |
| 
 | |
| UChar32 ReplaceableGlue::getChar32At(int32_t offset) const {
 | |
|     return (*func->char32At)(rep, offset);
 | |
| }
 | |
| 
 | |
| void ReplaceableGlue::handleReplaceBetween(int32_t start,
 | |
|                           int32_t limit,
 | |
|                           const UnicodeString& text) {
 | |
|     (*func->replace)(rep, start, limit, text.getBuffer(), text.length());
 | |
| }
 | |
| 
 | |
| void ReplaceableGlue::extractBetween(int32_t start,
 | |
|                                      int32_t limit,
 | |
|                                      UnicodeString& target) const {
 | |
|     (*func->extract)(rep, start, limit, target.getBuffer(limit-start));
 | |
|     target.releaseBuffer(limit-start);
 | |
| }
 | |
| 
 | |
| void ReplaceableGlue::copy(int32_t start, int32_t limit, int32_t dest) {
 | |
|     (*func->copy)(rep, start, limit, dest);
 | |
| }
 | |
| U_NAMESPACE_END
 | |
| /********************************************************************
 | |
|  * General API
 | |
|  ********************************************************************/
 | |
| U_NAMESPACE_USE
 | |
| 
 | |
| 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) {
 | |
|     if(status==NULL || U_FAILURE(*status)) {
 | |
|         return NULL;
 | |
|     }
 | |
|     if (id == NULL) {
 | |
|         *status = U_ILLEGAL_ARGUMENT_ERROR;
 | |
|         return NULL;
 | |
|     }
 | |
|     UParseError temp;
 | |
|     
 | |
|     if(parseError == NULL){
 | |
|         parseError = &temp;
 | |
|     }
 | |
|     
 | |
|     UnicodeString ID(idLength<0, id, idLength); // r-o alias
 | |
| 
 | |
|     if(rules==NULL){
 | |
| 
 | |
|         Transliterator *trans = NULL;
 | |
| 
 | |
|         trans = Transliterator::createInstance(ID, dir, *parseError, *status);
 | |
|         
 | |
|         if(U_FAILURE(*status)){
 | |
|             return NULL;
 | |
|         }
 | |
|         return (UTransliterator*) trans;
 | |
|     }else{
 | |
|         UnicodeString ruleStr(rulesLength < 0,
 | |
|                               rules,
 | |
|                               rulesLength); // r-o alias
 | |
| 
 | |
|         Transliterator *trans = NULL;
 | |
|         trans = Transliterator::createFromRules(ID, ruleStr, dir, *parseError, *status); 
 | |
|         if(U_FAILURE(*status)) { 
 | |
|             return NULL;
 | |
|         }
 | |
| 
 | |
|         return (UTransliterator*) trans;
 | |
|     }
 | |
| }
 | |
| 
 | |
| U_CAPI UTransliterator* U_EXPORT2
 | |
| utrans_open(const char* id,
 | |
|             UTransDirection dir,
 | |
|             const UChar* rules,         /* may be Null */
 | |
|             int32_t rulesLength,        /* -1 if null-terminated */ 
 | |
|             UParseError* parseError,    /* may be Null */
 | |
|             UErrorCode* status) {
 | |
|     UnicodeString ID(id, -1, US_INV); // use invariant converter
 | |
|     return utrans_openU(ID.getBuffer(), ID.length(), dir,
 | |
|                         rules, rulesLength,
 | |
|                         parseError, status);
 | |
| }
 | |
| 
 | |
| U_CAPI UTransliterator* U_EXPORT2
 | |
| utrans_openInverse(const UTransliterator* trans,
 | |
|                    UErrorCode* status) {
 | |
| 
 | |
|     utrans_ENTRY(status) NULL;
 | |
| 
 | |
|     UTransliterator* result =
 | |
|         (UTransliterator*) ((Transliterator*) trans)->createInverse(*status);
 | |
| 
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| U_CAPI UTransliterator* U_EXPORT2
 | |
| utrans_clone(const UTransliterator* trans,
 | |
|              UErrorCode* status) {
 | |
| 
 | |
|     utrans_ENTRY(status) NULL;
 | |
| 
 | |
|     if (trans == NULL) {
 | |
|         *status = U_ILLEGAL_ARGUMENT_ERROR;
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     Transliterator *t = ((Transliterator*) trans)->clone();
 | |
|     if (t == NULL) {
 | |
|         *status = U_MEMORY_ALLOCATION_ERROR;
 | |
|     }
 | |
|     return (UTransliterator*) t;
 | |
| }
 | |
| 
 | |
| U_CAPI void U_EXPORT2
 | |
| utrans_close(UTransliterator* trans) {
 | |
|     delete (Transliterator*) trans;
 | |
| }
 | |
| 
 | |
| U_CAPI const UChar * U_EXPORT2
 | |
| utrans_getUnicodeID(const UTransliterator *trans,
 | |
|                     int32_t *resultLength) {
 | |
|     // Transliterator keeps its ID NUL-terminated
 | |
|     const UnicodeString &ID=((Transliterator*) trans)->getID();
 | |
|     if(resultLength!=NULL) {
 | |
|         *resultLength=ID.length();
 | |
|     }
 | |
|     return ID.getBuffer();
 | |
| }
 | |
| 
 | |
| U_CAPI int32_t U_EXPORT2
 | |
| utrans_getID(const UTransliterator* trans,
 | |
|              char* buf,
 | |
|              int32_t bufCapacity) {
 | |
|     return ((Transliterator*) trans)->getID().extract(0, 0x7fffffff, buf, bufCapacity, US_INV);
 | |
| }
 | |
| 
 | |
| U_CAPI void U_EXPORT2
 | |
| utrans_register(UTransliterator* adoptedTrans,
 | |
|                 UErrorCode* status) {
 | |
|     utrans_ENTRY(status);
 | |
|     // status currently ignored; may remove later
 | |
|     Transliterator::registerInstance((Transliterator*) adoptedTrans);
 | |
| }
 | |
| 
 | |
| U_CAPI void U_EXPORT2
 | |
| utrans_unregisterID(const UChar* id, int32_t idLength) {
 | |
|     UnicodeString ID(idLength<0, id, idLength); // r-o alias
 | |
|     Transliterator::unregister(ID);
 | |
| }
 | |
| 
 | |
| U_CAPI void U_EXPORT2
 | |
| utrans_unregister(const char* id) {
 | |
|     UnicodeString ID(id, -1, US_INV); // use invariant converter
 | |
|     Transliterator::unregister(ID);
 | |
| }
 | |
| 
 | |
| U_CAPI void U_EXPORT2
 | |
| utrans_setFilter(UTransliterator* trans,
 | |
|                  const UChar* filterPattern,
 | |
|                  int32_t filterPatternLen,
 | |
|                  UErrorCode* status) {
 | |
| 
 | |
|     utrans_ENTRY(status);
 | |
|     UnicodeFilter* filter = NULL;
 | |
|     if (filterPattern != NULL && *filterPattern != 0) {
 | |
|         // Create read only alias of filterPattern:
 | |
|         UnicodeString pat(filterPatternLen < 0, filterPattern, filterPatternLen);
 | |
|         filter = new UnicodeSet(pat, *status);
 | |
|         /* test for NULL */
 | |
|         if (filter == NULL) {
 | |
|             *status = U_MEMORY_ALLOCATION_ERROR;
 | |
|             return;
 | |
|         }
 | |
|         if (U_FAILURE(*status)) {
 | |
|             delete filter;
 | |
|             filter = NULL;
 | |
|         }
 | |
|     }
 | |
|     ((Transliterator*) trans)->adoptFilter(filter);
 | |
| }
 | |
| 
 | |
| U_CAPI int32_t U_EXPORT2
 | |
| utrans_countAvailableIDs(void) {
 | |
|     return Transliterator::countAvailableIDs();
 | |
| }
 | |
| 
 | |
| U_CAPI int32_t U_EXPORT2
 | |
| utrans_getAvailableID(int32_t index,
 | |
|                       char* buf, // may be NULL
 | |
|                       int32_t bufCapacity) {
 | |
|     return Transliterator::getAvailableID(index).extract(0, 0x7fffffff, buf, bufCapacity, US_INV);
 | |
| }
 | |
| 
 | |
| /* Transliterator UEnumeration ---------------------------------------------- */
 | |
| 
 | |
| typedef struct UTransEnumeration {
 | |
|     UEnumeration uenum;
 | |
|     int32_t index, count;
 | |
| } UTransEnumeration;
 | |
| 
 | |
| U_CDECL_BEGIN
 | |
| static int32_t U_CALLCONV
 | |
| utrans_enum_count(UEnumeration *uenum, UErrorCode *pErrorCode) {
 | |
|     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
 | |
|         return 0;
 | |
|     }
 | |
|     return ((UTransEnumeration *)uenum)->count;
 | |
| }
 | |
| 
 | |
| static const UChar* U_CALLCONV
 | |
| utrans_enum_unext(UEnumeration *uenum,
 | |
|                   int32_t* resultLength,
 | |
|                   UErrorCode *pErrorCode) {
 | |
|     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     UTransEnumeration *ute=(UTransEnumeration *)uenum;
 | |
|     int32_t index=ute->index;
 | |
|     if(index<ute->count) {
 | |
|         const UnicodeString &ID=Transliterator::getAvailableID(index);
 | |
|         ute->index=index+1;
 | |
|         if(resultLength!=NULL) {
 | |
|             *resultLength=ID.length();
 | |
|         }
 | |
|         // Transliterator keeps its ID NUL-terminated
 | |
|         return ID.getBuffer();
 | |
|     }
 | |
| 
 | |
|     if(resultLength!=NULL) {
 | |
|         *resultLength=0;
 | |
|     }
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| static void U_CALLCONV
 | |
| utrans_enum_reset(UEnumeration *uenum, UErrorCode *pErrorCode) {
 | |
|     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     UTransEnumeration *ute=(UTransEnumeration *)uenum;
 | |
|     ute->index=0;
 | |
|     ute->count=Transliterator::countAvailableIDs();
 | |
| }
 | |
| 
 | |
| static void U_CALLCONV
 | |
| utrans_enum_close(UEnumeration *uenum) {
 | |
|     uprv_free(uenum);
 | |
| }
 | |
| U_CDECL_END
 | |
| 
 | |
| static const UEnumeration utransEnumeration={
 | |
|     NULL,
 | |
|     NULL,
 | |
|     utrans_enum_close,
 | |
|     utrans_enum_count,
 | |
|     utrans_enum_unext,
 | |
|     uenum_nextDefault,
 | |
|     utrans_enum_reset
 | |
| };
 | |
| 
 | |
| U_CAPI UEnumeration * U_EXPORT2
 | |
| utrans_openIDs(UErrorCode *pErrorCode) {
 | |
|     UTransEnumeration *ute;
 | |
| 
 | |
|     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     ute=(UTransEnumeration *)uprv_malloc(sizeof(UTransEnumeration));
 | |
|     if(ute==NULL) {
 | |
|         *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     ute->uenum=utransEnumeration;
 | |
|     ute->index=0;
 | |
|     ute->count=Transliterator::countAvailableIDs();
 | |
|     return (UEnumeration *)ute;
 | |
| }
 | |
| 
 | |
| /********************************************************************
 | |
|  * Transliteration API
 | |
|  ********************************************************************/
 | |
| 
 | |
| U_CAPI void U_EXPORT2
 | |
| utrans_trans(const UTransliterator* trans,
 | |
|              UReplaceable* rep,
 | |
|              const UReplaceableCallbacks* repFunc,
 | |
|              int32_t start,
 | |
|              int32_t* limit,
 | |
|              UErrorCode* status) {
 | |
| 
 | |
|     utrans_ENTRY(status);
 | |
| 
 | |
|     if (trans == 0 || rep == 0 || repFunc == 0 || limit == 0) {
 | |
|         *status = U_ILLEGAL_ARGUMENT_ERROR;
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     ReplaceableGlue r(rep, repFunc);
 | |
| 
 | |
|     *limit = ((Transliterator*) trans)->transliterate(r, start, *limit);
 | |
| }
 | |
| 
 | |
| U_CAPI void U_EXPORT2
 | |
| utrans_transIncremental(const UTransliterator* trans,
 | |
|                         UReplaceable* rep,
 | |
|                         const UReplaceableCallbacks* repFunc,
 | |
|                         UTransPosition* pos,
 | |
|                         UErrorCode* status) {
 | |
| 
 | |
|     utrans_ENTRY(status);
 | |
| 
 | |
|     if (trans == 0 || rep == 0 || repFunc == 0 || pos == 0) {
 | |
|         *status = U_ILLEGAL_ARGUMENT_ERROR;
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     ReplaceableGlue r(rep, repFunc);
 | |
| 
 | |
|     ((Transliterator*) trans)->transliterate(r, *pos, *status);
 | |
| }
 | |
| 
 | |
| 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) {
 | |
| 
 | |
|     utrans_ENTRY(status);
 | |
| 
 | |
|     if (trans == 0 || text == 0 || limit == 0) {
 | |
|         *status = U_ILLEGAL_ARGUMENT_ERROR;
 | |
|         return;
 | |
|     }
 | |
|  
 | |
|     int32_t textLen = (textLength == NULL || *textLength < 0)
 | |
|         ? u_strlen(text) : *textLength;
 | |
|     // writeable alias: for this ct, len CANNOT be -1 (why?)
 | |
|     UnicodeString str(text, textLen, textCapacity);
 | |
| 
 | |
|     *limit = ((Transliterator*) trans)->transliterate(str, start, *limit);
 | |
| 
 | |
|     // Copy the string buffer back to text (only if necessary)
 | |
|     // and fill in *neededCapacity (if neededCapacity != NULL).
 | |
|     textLen = str.extract(text, textCapacity, *status);
 | |
|     if(textLength != NULL) {
 | |
|         *textLength = textLen;
 | |
|     }
 | |
| }
 | |
| 
 | |
| U_CAPI void U_EXPORT2
 | |
| utrans_transIncrementalUChars(const UTransliterator* trans,
 | |
|                               UChar* text,
 | |
|                               int32_t* textLength,
 | |
|                               int32_t textCapacity,
 | |
|                               UTransPosition* pos,
 | |
|                               UErrorCode* status) {
 | |
| 
 | |
|     utrans_ENTRY(status);
 | |
| 
 | |
|     if (trans == 0 || text == 0 || pos == 0) {
 | |
|         *status = U_ILLEGAL_ARGUMENT_ERROR;
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     int32_t textLen = (textLength == NULL || *textLength < 0)
 | |
|         ? u_strlen(text) : *textLength;
 | |
|     // writeable alias: for this ct, len CANNOT be -1 (why?)
 | |
|     UnicodeString str(text, textLen, textCapacity);
 | |
| 
 | |
|     ((Transliterator*) trans)->transliterate(str, *pos, *status);
 | |
| 
 | |
|     // Copy the string buffer back to text (only if necessary)
 | |
|     // and fill in *neededCapacity (if neededCapacity != NULL).
 | |
|     textLen = str.extract(text, textCapacity, *status);
 | |
|     if(textLength != NULL) {
 | |
|         *textLength = textLen;
 | |
|     }
 | |
| }
 | |
| 
 | |
| U_CAPI int32_t U_EXPORT2
 | |
| utrans_toRules(     const UTransliterator* trans,
 | |
|                     UBool escapeUnprintable,
 | |
|                     UChar* result, int32_t resultLength,
 | |
|                     UErrorCode* status) {
 | |
|     utrans_ENTRY(status) 0;
 | |
|     if ( (result==NULL)? resultLength!=0: resultLength<0 ) {
 | |
|         *status = U_ILLEGAL_ARGUMENT_ERROR;
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     UnicodeString res;
 | |
|     res.setTo(result, 0, resultLength);
 | |
|     ((Transliterator*) trans)->toRules(res, escapeUnprintable);
 | |
|     return res.extract(result, resultLength, *status);
 | |
| }
 | |
| 
 | |
| U_CAPI USet* U_EXPORT2
 | |
| utrans_getSourceSet(const UTransliterator* trans,
 | |
|                     UBool ignoreFilter,
 | |
|                     USet* fillIn,
 | |
|                     UErrorCode* status) {
 | |
|     utrans_ENTRY(status) fillIn;
 | |
| 
 | |
|     if (fillIn == NULL) {
 | |
|         fillIn = uset_openEmpty();
 | |
|     }
 | |
|     if (ignoreFilter) {
 | |
|         ((Transliterator*) trans)->handleGetSourceSet(*((UnicodeSet*)fillIn));
 | |
|     } else {
 | |
|         ((Transliterator*) trans)->getSourceSet(*((UnicodeSet*)fillIn));
 | |
|     }
 | |
|     return fillIn;
 | |
| }
 | |
| 
 | |
| #endif /* #if !UCONFIG_NO_TRANSLITERATION */
 |