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