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 */ 37U_NAMESPACE_BEGIN 38class ReplaceableGlue : public Replaceable { 39 40 UReplaceable *rep; 41 UReplaceableCallbacks *func; 42 43public: 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 76protected: 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 85UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ReplaceableGlue) 86 87ReplaceableGlue::ReplaceableGlue(UReplaceable *replaceable, 88 UReplaceableCallbacks *funcCallback) 89 : Replaceable() 90{ 91 this->rep = replaceable; 92 this->func = funcCallback; 93} 94 95ReplaceableGlue::~ReplaceableGlue() {} 96 97int32_t ReplaceableGlue::getLength() const { 98 return (*func->length)(rep); 99} 100 101UChar ReplaceableGlue::getCharAt(int32_t offset) const { 102 return (*func->charAt)(rep, offset); 103} 104 105UChar32 ReplaceableGlue::getChar32At(int32_t offset) const { 106 return (*func->char32At)(rep, offset); 107} 108 109void 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 115void 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 122void ReplaceableGlue::copy(int32_t start, int32_t limit, int32_t dest) { 123 (*func->copy)(rep, start, limit, dest); 124} 125U_NAMESPACE_END 126/******************************************************************** 127 * General API 128 ********************************************************************/ 129U_NAMESPACE_USE 130 131U_CAPI UTransliterator* U_EXPORT2 132utrans_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 179U_CAPI UTransliterator* U_EXPORT2 180utrans_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 192U_CAPI UTransliterator* U_EXPORT2 193utrans_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 204U_CAPI UTransliterator* U_EXPORT2 205utrans_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 222U_CAPI void U_EXPORT2 223utrans_close(UTransliterator* trans) { 224 delete (Transliterator*) trans; 225} 226 227U_CAPI const UChar * U_EXPORT2 228utrans_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 238U_CAPI int32_t U_EXPORT2 239utrans_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 245U_CAPI void U_EXPORT2 246utrans_register(UTransliterator* adoptedTrans, 247 UErrorCode* status) { 248 utrans_ENTRY(status); 249 // status currently ignored; may remove later 250 Transliterator::registerInstance((Transliterator*) adoptedTrans); 251} 252 253U_CAPI void U_EXPORT2 254utrans_unregisterID(const UChar* id, int32_t idLength) { 255 UnicodeString ID(idLength<0, id, idLength); // r-o alias 256 Transliterator::unregister(ID); 257} 258 259U_CAPI void U_EXPORT2 260utrans_unregister(const char* id) { 261 UnicodeString ID(id, -1, US_INV); // use invariant converter 262 Transliterator::unregister(ID); 263} 264 265U_CAPI void U_EXPORT2 266utrans_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 290U_CAPI int32_t U_EXPORT2 291utrans_countAvailableIDs(void) { 292 return Transliterator::countAvailableIDs(); 293} 294 295U_CAPI int32_t U_EXPORT2 296utrans_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 304typedef struct UTransEnumeration { 305 UEnumeration uenum; 306 int32_t index, count; 307} UTransEnumeration; 308 309U_CDECL_BEGIN 310static int32_t U_CALLCONV 311utrans_enum_count(UEnumeration *uenum, UErrorCode *pErrorCode) { 312 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 313 return 0; 314 } 315 return ((UTransEnumeration *)uenum)->count; 316} 317 318static const UChar* U_CALLCONV 319utrans_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 344static void U_CALLCONV 345utrans_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 355static void U_CALLCONV 356utrans_enum_close(UEnumeration *uenum) { 357 uprv_free(uenum); 358} 359U_CDECL_END 360 361static 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 371U_CAPI UEnumeration * U_EXPORT2 372utrans_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 395U_CAPI void U_EXPORT2 396utrans_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 415U_CAPI void U_EXPORT2 416utrans_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 434U_CAPI void U_EXPORT2 435utrans_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 465U_CAPI void U_EXPORT2 466utrans_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