// © 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; UReplaceableCallbacks *func; public: ReplaceableGlue(UReplaceable *replaceable, UReplaceableCallbacks *funcCallback); virtual ~ReplaceableGlue(); virtual void handleReplaceBetween(int32_t start, int32_t limit, const UnicodeString& text); virtual void extractBetween(int32_t start, int32_t limit, UnicodeString& target) const; virtual void copy(int32_t start, int32_t limit, int32_t dest); // 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; /** * 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; virtual UChar getCharAt(int32_t offset) const; virtual UChar32 getChar32At(int32_t offset) const; }; UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ReplaceableGlue) ReplaceableGlue::ReplaceableGlue(UReplaceable *replaceable, 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, 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, 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 */