1/* 2 ******************************************************************************* 3 * Copyright (C) 1997-2009,2014 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 "unicode/uset.h" 24#include "uenumimp.h" 25#include "cpputils.h" 26#include "rbt.h" 27 28// Following macro is to be followed by <return value>';' or just ';' 29#define utrans_ENTRY(s) if ((s)==NULL || U_FAILURE(*(s))) return 30 31/******************************************************************** 32 * Replaceable-UReplaceableCallbacks glue 33 ********************************************************************/ 34 35/** 36 * Make a UReplaceable + UReplaceableCallbacks into a Replaceable object. 37 */ 38U_NAMESPACE_BEGIN 39class ReplaceableGlue : public Replaceable { 40 41 UReplaceable *rep; 42 UReplaceableCallbacks *func; 43 44public: 45 46 ReplaceableGlue(UReplaceable *replaceable, 47 UReplaceableCallbacks *funcCallback); 48 49 virtual ~ReplaceableGlue(); 50 51 virtual void handleReplaceBetween(int32_t start, 52 int32_t limit, 53 const UnicodeString& text); 54 55 virtual void extractBetween(int32_t start, 56 int32_t limit, 57 UnicodeString& target) const; 58 59 virtual void copy(int32_t start, int32_t limit, int32_t dest); 60 61 // virtual Replaceable *clone() const { return NULL; } same as default 62 63 /** 64 * ICU "poor man's RTTI", returns a UClassID for the actual class. 65 * 66 * @draft ICU 2.2 67 */ 68 virtual UClassID getDynamicClassID() const; 69 70 /** 71 * ICU "poor man's RTTI", returns a UClassID for this class. 72 * 73 * @draft ICU 2.2 74 */ 75 static UClassID U_EXPORT2 getStaticClassID(); 76 77protected: 78 79 virtual int32_t getLength() const; 80 81 virtual UChar getCharAt(int32_t offset) const; 82 83 virtual UChar32 getChar32At(int32_t offset) const; 84}; 85 86UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ReplaceableGlue) 87 88ReplaceableGlue::ReplaceableGlue(UReplaceable *replaceable, 89 UReplaceableCallbacks *funcCallback) 90 : Replaceable() 91{ 92 this->rep = replaceable; 93 this->func = funcCallback; 94} 95 96ReplaceableGlue::~ReplaceableGlue() {} 97 98int32_t ReplaceableGlue::getLength() const { 99 return (*func->length)(rep); 100} 101 102UChar ReplaceableGlue::getCharAt(int32_t offset) const { 103 return (*func->charAt)(rep, offset); 104} 105 106UChar32 ReplaceableGlue::getChar32At(int32_t offset) const { 107 return (*func->char32At)(rep, offset); 108} 109 110void ReplaceableGlue::handleReplaceBetween(int32_t start, 111 int32_t limit, 112 const UnicodeString& text) { 113 (*func->replace)(rep, start, limit, text.getBuffer(), text.length()); 114} 115 116void ReplaceableGlue::extractBetween(int32_t start, 117 int32_t limit, 118 UnicodeString& target) const { 119 (*func->extract)(rep, start, limit, target.getBuffer(limit-start)); 120 target.releaseBuffer(limit-start); 121} 122 123void ReplaceableGlue::copy(int32_t start, int32_t limit, int32_t dest) { 124 (*func->copy)(rep, start, limit, dest); 125} 126U_NAMESPACE_END 127/******************************************************************** 128 * General API 129 ********************************************************************/ 130U_NAMESPACE_USE 131 132U_CAPI UTransliterator* U_EXPORT2 133utrans_openU(const UChar *id, 134 int32_t idLength, 135 UTransDirection dir, 136 const UChar *rules, 137 int32_t rulesLength, 138 UParseError *parseError, 139 UErrorCode *status) { 140 if(status==NULL || U_FAILURE(*status)) { 141 return NULL; 142 } 143 if (id == NULL) { 144 *status = U_ILLEGAL_ARGUMENT_ERROR; 145 return NULL; 146 } 147 UParseError temp; 148 149 if(parseError == NULL){ 150 parseError = &temp; 151 } 152 153 UnicodeString ID(idLength<0, id, idLength); // r-o alias 154 155 if(rules==NULL){ 156 157 Transliterator *trans = NULL; 158 159 trans = Transliterator::createInstance(ID, dir, *parseError, *status); 160 161 if(U_FAILURE(*status)){ 162 return NULL; 163 } 164 return (UTransliterator*) trans; 165 }else{ 166 UnicodeString ruleStr(rulesLength < 0, 167 rules, 168 rulesLength); // r-o alias 169 170 Transliterator *trans = NULL; 171 trans = Transliterator::createFromRules(ID, ruleStr, dir, *parseError, *status); 172 if(U_FAILURE(*status)) { 173 return NULL; 174 } 175 176 return (UTransliterator*) trans; 177 } 178} 179 180U_CAPI UTransliterator* U_EXPORT2 181utrans_open(const char* id, 182 UTransDirection dir, 183 const UChar* rules, /* may be Null */ 184 int32_t rulesLength, /* -1 if null-terminated */ 185 UParseError* parseError, /* may be Null */ 186 UErrorCode* status) { 187 UnicodeString ID(id, -1, US_INV); // use invariant converter 188 return utrans_openU(ID.getBuffer(), ID.length(), dir, 189 rules, rulesLength, 190 parseError, status); 191} 192 193U_CAPI UTransliterator* U_EXPORT2 194utrans_openInverse(const UTransliterator* trans, 195 UErrorCode* status) { 196 197 utrans_ENTRY(status) NULL; 198 199 UTransliterator* result = 200 (UTransliterator*) ((Transliterator*) trans)->createInverse(*status); 201 202 return result; 203} 204 205U_CAPI UTransliterator* U_EXPORT2 206utrans_clone(const UTransliterator* trans, 207 UErrorCode* status) { 208 209 utrans_ENTRY(status) NULL; 210 211 if (trans == NULL) { 212 *status = U_ILLEGAL_ARGUMENT_ERROR; 213 return NULL; 214 } 215 216 Transliterator *t = ((Transliterator*) trans)->clone(); 217 if (t == NULL) { 218 *status = U_MEMORY_ALLOCATION_ERROR; 219 } 220 return (UTransliterator*) t; 221} 222 223U_CAPI void U_EXPORT2 224utrans_close(UTransliterator* trans) { 225 delete (Transliterator*) trans; 226} 227 228U_CAPI const UChar * U_EXPORT2 229utrans_getUnicodeID(const UTransliterator *trans, 230 int32_t *resultLength) { 231 // Transliterator keeps its ID NUL-terminated 232 const UnicodeString &ID=((Transliterator*) trans)->getID(); 233 if(resultLength!=NULL) { 234 *resultLength=ID.length(); 235 } 236 return ID.getBuffer(); 237} 238 239U_CAPI int32_t U_EXPORT2 240utrans_getID(const UTransliterator* trans, 241 char* buf, 242 int32_t bufCapacity) { 243 return ((Transliterator*) trans)->getID().extract(0, 0x7fffffff, buf, bufCapacity, US_INV); 244} 245 246U_CAPI void U_EXPORT2 247utrans_register(UTransliterator* adoptedTrans, 248 UErrorCode* status) { 249 utrans_ENTRY(status); 250 // status currently ignored; may remove later 251 Transliterator::registerInstance((Transliterator*) adoptedTrans); 252} 253 254U_CAPI void U_EXPORT2 255utrans_unregisterID(const UChar* id, int32_t idLength) { 256 UnicodeString ID(idLength<0, id, idLength); // r-o alias 257 Transliterator::unregister(ID); 258} 259 260U_CAPI void U_EXPORT2 261utrans_unregister(const char* id) { 262 UnicodeString ID(id, -1, US_INV); // use invariant converter 263 Transliterator::unregister(ID); 264} 265 266U_CAPI void U_EXPORT2 267utrans_setFilter(UTransliterator* trans, 268 const UChar* filterPattern, 269 int32_t filterPatternLen, 270 UErrorCode* status) { 271 272 utrans_ENTRY(status); 273 UnicodeFilter* filter = NULL; 274 if (filterPattern != NULL && *filterPattern != 0) { 275 // Create read only alias of filterPattern: 276 UnicodeString pat(filterPatternLen < 0, filterPattern, filterPatternLen); 277 filter = new UnicodeSet(pat, *status); 278 /* test for NULL */ 279 if (filter == NULL) { 280 *status = U_MEMORY_ALLOCATION_ERROR; 281 return; 282 } 283 if (U_FAILURE(*status)) { 284 delete filter; 285 filter = NULL; 286 } 287 } 288 ((Transliterator*) trans)->adoptFilter(filter); 289} 290 291U_CAPI int32_t U_EXPORT2 292utrans_countAvailableIDs(void) { 293 return Transliterator::countAvailableIDs(); 294} 295 296U_CAPI int32_t U_EXPORT2 297utrans_getAvailableID(int32_t index, 298 char* buf, // may be NULL 299 int32_t bufCapacity) { 300 return Transliterator::getAvailableID(index).extract(0, 0x7fffffff, buf, bufCapacity, US_INV); 301} 302 303/* Transliterator UEnumeration ---------------------------------------------- */ 304 305typedef struct UTransEnumeration { 306 UEnumeration uenum; 307 int32_t index, count; 308} UTransEnumeration; 309 310U_CDECL_BEGIN 311static int32_t U_CALLCONV 312utrans_enum_count(UEnumeration *uenum, UErrorCode *pErrorCode) { 313 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 314 return 0; 315 } 316 return ((UTransEnumeration *)uenum)->count; 317} 318 319static const UChar* U_CALLCONV 320utrans_enum_unext(UEnumeration *uenum, 321 int32_t* resultLength, 322 UErrorCode *pErrorCode) { 323 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 324 return 0; 325 } 326 327 UTransEnumeration *ute=(UTransEnumeration *)uenum; 328 int32_t index=ute->index; 329 if(index<ute->count) { 330 const UnicodeString &ID=Transliterator::getAvailableID(index); 331 ute->index=index+1; 332 if(resultLength!=NULL) { 333 *resultLength=ID.length(); 334 } 335 // Transliterator keeps its ID NUL-terminated 336 return ID.getBuffer(); 337 } 338 339 if(resultLength!=NULL) { 340 *resultLength=0; 341 } 342 return NULL; 343} 344 345static void U_CALLCONV 346utrans_enum_reset(UEnumeration *uenum, UErrorCode *pErrorCode) { 347 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 348 return; 349 } 350 351 UTransEnumeration *ute=(UTransEnumeration *)uenum; 352 ute->index=0; 353 ute->count=Transliterator::countAvailableIDs(); 354} 355 356static void U_CALLCONV 357utrans_enum_close(UEnumeration *uenum) { 358 uprv_free(uenum); 359} 360U_CDECL_END 361 362static const UEnumeration utransEnumeration={ 363 NULL, 364 NULL, 365 utrans_enum_close, 366 utrans_enum_count, 367 utrans_enum_unext, 368 uenum_nextDefault, 369 utrans_enum_reset 370}; 371 372U_CAPI UEnumeration * U_EXPORT2 373utrans_openIDs(UErrorCode *pErrorCode) { 374 UTransEnumeration *ute; 375 376 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { 377 return NULL; 378 } 379 380 ute=(UTransEnumeration *)uprv_malloc(sizeof(UTransEnumeration)); 381 if(ute==NULL) { 382 *pErrorCode=U_MEMORY_ALLOCATION_ERROR; 383 return NULL; 384 } 385 386 ute->uenum=utransEnumeration; 387 ute->index=0; 388 ute->count=Transliterator::countAvailableIDs(); 389 return (UEnumeration *)ute; 390} 391 392/******************************************************************** 393 * Transliteration API 394 ********************************************************************/ 395 396U_CAPI void U_EXPORT2 397utrans_trans(const UTransliterator* trans, 398 UReplaceable* rep, 399 UReplaceableCallbacks* repFunc, 400 int32_t start, 401 int32_t* limit, 402 UErrorCode* status) { 403 404 utrans_ENTRY(status); 405 406 if (trans == 0 || rep == 0 || repFunc == 0 || limit == 0) { 407 *status = U_ILLEGAL_ARGUMENT_ERROR; 408 return; 409 } 410 411 ReplaceableGlue r(rep, repFunc); 412 413 *limit = ((Transliterator*) trans)->transliterate(r, start, *limit); 414} 415 416U_CAPI void U_EXPORT2 417utrans_transIncremental(const UTransliterator* trans, 418 UReplaceable* rep, 419 UReplaceableCallbacks* repFunc, 420 UTransPosition* pos, 421 UErrorCode* status) { 422 423 utrans_ENTRY(status); 424 425 if (trans == 0 || rep == 0 || repFunc == 0 || pos == 0) { 426 *status = U_ILLEGAL_ARGUMENT_ERROR; 427 return; 428 } 429 430 ReplaceableGlue r(rep, repFunc); 431 432 ((Transliterator*) trans)->transliterate(r, *pos, *status); 433} 434 435U_CAPI void U_EXPORT2 436utrans_transUChars(const UTransliterator* trans, 437 UChar* text, 438 int32_t* textLength, 439 int32_t textCapacity, 440 int32_t start, 441 int32_t* limit, 442 UErrorCode* status) { 443 444 utrans_ENTRY(status); 445 446 if (trans == 0 || text == 0 || limit == 0) { 447 *status = U_ILLEGAL_ARGUMENT_ERROR; 448 return; 449 } 450 451 int32_t textLen = (textLength == NULL || *textLength < 0) 452 ? u_strlen(text) : *textLength; 453 // writeable alias: for this ct, len CANNOT be -1 (why?) 454 UnicodeString str(text, textLen, textCapacity); 455 456 *limit = ((Transliterator*) trans)->transliterate(str, start, *limit); 457 458 // Copy the string buffer back to text (only if necessary) 459 // and fill in *neededCapacity (if neededCapacity != NULL). 460 textLen = str.extract(text, textCapacity, *status); 461 if(textLength != NULL) { 462 *textLength = textLen; 463 } 464} 465 466U_CAPI void U_EXPORT2 467utrans_transIncrementalUChars(const UTransliterator* trans, 468 UChar* text, 469 int32_t* textLength, 470 int32_t textCapacity, 471 UTransPosition* pos, 472 UErrorCode* status) { 473 474 utrans_ENTRY(status); 475 476 if (trans == 0 || text == 0 || pos == 0) { 477 *status = U_ILLEGAL_ARGUMENT_ERROR; 478 return; 479 } 480 481 int32_t textLen = (textLength == NULL || *textLength < 0) 482 ? u_strlen(text) : *textLength; 483 // writeable alias: for this ct, len CANNOT be -1 (why?) 484 UnicodeString str(text, textLen, textCapacity); 485 486 ((Transliterator*) trans)->transliterate(str, *pos, *status); 487 488 // Copy the string buffer back to text (only if necessary) 489 // and fill in *neededCapacity (if neededCapacity != NULL). 490 textLen = str.extract(text, textCapacity, *status); 491 if(textLength != NULL) { 492 *textLength = textLen; 493 } 494} 495 496U_CAPI int32_t U_EXPORT2 497utrans_toRules( const UTransliterator* trans, 498 UBool escapeUnprintable, 499 UChar* result, int32_t resultLength, 500 UErrorCode* status) { 501 utrans_ENTRY(status) 0; 502 if ( (result==NULL)? resultLength!=0: resultLength<0 ) { 503 *status = U_ILLEGAL_ARGUMENT_ERROR; 504 return 0; 505 } 506 507 UnicodeString res; 508 res.setTo(result, 0, resultLength); 509 ((Transliterator*) trans)->toRules(res, escapeUnprintable); 510 return res.extract(result, resultLength, *status); 511} 512 513U_CAPI USet* U_EXPORT2 514utrans_getSourceSet(const UTransliterator* trans, 515 UBool ignoreFilter, 516 USet* fillIn, 517 UErrorCode* status) { 518 utrans_ENTRY(status) fillIn; 519 520 if (fillIn == NULL) { 521 fillIn = uset_openEmpty(); 522 } 523 if (ignoreFilter) { 524 ((Transliterator*) trans)->handleGetSourceSet(*((UnicodeSet*)fillIn)); 525 } else { 526 ((Transliterator*) trans)->getSourceSet(*((UnicodeSet*)fillIn)); 527 } 528 return fillIn; 529} 530 531#endif /* #if !UCONFIG_NO_TRANSLITERATION */ 532