1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
5 * Copyright (C) 1997-2009,2014 International Business Machines
6 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
8 * Date Name Description
9 * 06/21/00 aliu Creation.
10 *******************************************************************************
13 #include "unicode/utypes.h"
15 #if !UCONFIG_NO_TRANSLITERATION
17 #include "unicode/utrans.h"
18 #include "unicode/putil.h"
19 #include "unicode/rep.h"
20 #include "unicode/translit.h"
21 #include "unicode/unifilt.h"
22 #include "unicode/uniset.h"
23 #include "unicode/ustring.h"
24 #include "unicode/uenum.h"
25 #include "unicode/uset.h"
30 // Following macro is to be followed by <return value>';' or just ';'
31 #define utrans_ENTRY(s) if ((s)==NULL || U_FAILURE(*(s))) return
33 /********************************************************************
34 * Replaceable-UReplaceableCallbacks glue
35 ********************************************************************/
38 * Make a UReplaceable + UReplaceableCallbacks into a Replaceable object.
41 class ReplaceableGlue
: public Replaceable
{
44 const UReplaceableCallbacks
*func
;
48 ReplaceableGlue(UReplaceable
*replaceable
,
49 const UReplaceableCallbacks
*funcCallback
);
51 virtual ~ReplaceableGlue();
53 virtual void handleReplaceBetween(int32_t start
,
55 const UnicodeString
& text
);
57 virtual void extractBetween(int32_t start
,
59 UnicodeString
& target
) const;
61 virtual void copy(int32_t start
, int32_t limit
, int32_t dest
);
63 // virtual Replaceable *clone() const { return NULL; } same as default
66 * ICU "poor man's RTTI", returns a UClassID for the actual class.
70 virtual UClassID
getDynamicClassID() const;
73 * ICU "poor man's RTTI", returns a UClassID for this class.
77 static UClassID U_EXPORT2
getStaticClassID();
81 virtual int32_t getLength() const;
83 virtual UChar
getCharAt(int32_t offset
) const;
85 virtual UChar32
getChar32At(int32_t offset
) const;
88 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ReplaceableGlue
)
90 ReplaceableGlue::ReplaceableGlue(UReplaceable
*replaceable
,
91 const UReplaceableCallbacks
*funcCallback
)
94 this->rep
= replaceable
;
95 this->func
= funcCallback
;
98 ReplaceableGlue::~ReplaceableGlue() {}
100 int32_t ReplaceableGlue::getLength() const {
101 return (*func
->length
)(rep
);
104 UChar
ReplaceableGlue::getCharAt(int32_t offset
) const {
105 return (*func
->charAt
)(rep
, offset
);
108 UChar32
ReplaceableGlue::getChar32At(int32_t offset
) const {
109 return (*func
->char32At
)(rep
, offset
);
112 void ReplaceableGlue::handleReplaceBetween(int32_t start
,
114 const UnicodeString
& text
) {
115 (*func
->replace
)(rep
, start
, limit
, text
.getBuffer(), text
.length());
118 void ReplaceableGlue::extractBetween(int32_t start
,
120 UnicodeString
& target
) const {
121 (*func
->extract
)(rep
, start
, limit
, target
.getBuffer(limit
-start
));
122 target
.releaseBuffer(limit
-start
);
125 void ReplaceableGlue::copy(int32_t start
, int32_t limit
, int32_t dest
) {
126 (*func
->copy
)(rep
, start
, limit
, dest
);
129 /********************************************************************
131 ********************************************************************/
134 U_CAPI UTransliterator
* U_EXPORT2
135 utrans_openU(const UChar
*id
,
140 UParseError
*parseError
,
141 UErrorCode
*status
) {
142 if(status
==NULL
|| U_FAILURE(*status
)) {
146 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
151 if(parseError
== NULL
){
155 UnicodeString
ID(idLength
<0, id
, idLength
); // r-o alias
159 Transliterator
*trans
= NULL
;
161 trans
= Transliterator::createInstance(ID
, dir
, *parseError
, *status
);
163 if(U_FAILURE(*status
)){
166 return (UTransliterator
*) trans
;
168 UnicodeString
ruleStr(rulesLength
< 0,
170 rulesLength
); // r-o alias
172 Transliterator
*trans
= NULL
;
173 trans
= Transliterator::createFromRules(ID
, ruleStr
, dir
, *parseError
, *status
);
174 if(U_FAILURE(*status
)) {
178 return (UTransliterator
*) trans
;
182 U_CAPI UTransliterator
* U_EXPORT2
183 utrans_open(const char* id
,
185 const UChar
* rules
, /* may be Null */
186 int32_t rulesLength
, /* -1 if null-terminated */
187 UParseError
* parseError
, /* may be Null */
188 UErrorCode
* status
) {
189 UnicodeString
ID(id
, -1, US_INV
); // use invariant converter
190 return utrans_openU(ID
.getBuffer(), ID
.length(), dir
,
195 U_CAPI UTransliterator
* U_EXPORT2
196 utrans_openInverse(const UTransliterator
* trans
,
197 UErrorCode
* status
) {
199 utrans_ENTRY(status
) NULL
;
201 UTransliterator
* result
=
202 (UTransliterator
*) ((Transliterator
*) trans
)->createInverse(*status
);
207 U_CAPI UTransliterator
* U_EXPORT2
208 utrans_clone(const UTransliterator
* trans
,
209 UErrorCode
* status
) {
211 utrans_ENTRY(status
) NULL
;
214 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
218 Transliterator
*t
= ((Transliterator
*) trans
)->clone();
220 *status
= U_MEMORY_ALLOCATION_ERROR
;
222 return (UTransliterator
*) t
;
225 U_CAPI
void U_EXPORT2
226 utrans_close(UTransliterator
* trans
) {
227 delete (Transliterator
*) trans
;
230 U_CAPI
const UChar
* U_EXPORT2
231 utrans_getUnicodeID(const UTransliterator
*trans
,
232 int32_t *resultLength
) {
233 // Transliterator keeps its ID NUL-terminated
234 const UnicodeString
&ID
=((Transliterator
*) trans
)->getID();
235 if(resultLength
!=NULL
) {
236 *resultLength
=ID
.length();
238 return ID
.getBuffer();
241 U_CAPI
int32_t U_EXPORT2
242 utrans_getID(const UTransliterator
* trans
,
244 int32_t bufCapacity
) {
245 return ((Transliterator
*) trans
)->getID().extract(0, 0x7fffffff, buf
, bufCapacity
, US_INV
);
248 U_CAPI
void U_EXPORT2
249 utrans_register(UTransliterator
* adoptedTrans
,
250 UErrorCode
* status
) {
251 utrans_ENTRY(status
);
252 // status currently ignored; may remove later
253 Transliterator::registerInstance((Transliterator
*) adoptedTrans
);
256 U_CAPI
void U_EXPORT2
257 utrans_unregisterID(const UChar
* id
, int32_t idLength
) {
258 UnicodeString
ID(idLength
<0, id
, idLength
); // r-o alias
259 Transliterator::unregister(ID
);
262 U_CAPI
void U_EXPORT2
263 utrans_unregister(const char* id
) {
264 UnicodeString
ID(id
, -1, US_INV
); // use invariant converter
265 Transliterator::unregister(ID
);
268 U_CAPI
void U_EXPORT2
269 utrans_setFilter(UTransliterator
* trans
,
270 const UChar
* filterPattern
,
271 int32_t filterPatternLen
,
272 UErrorCode
* status
) {
274 utrans_ENTRY(status
);
275 UnicodeFilter
* filter
= NULL
;
276 if (filterPattern
!= NULL
&& *filterPattern
!= 0) {
277 // Create read only alias of filterPattern:
278 UnicodeString
pat(filterPatternLen
< 0, filterPattern
, filterPatternLen
);
279 filter
= new UnicodeSet(pat
, *status
);
281 if (filter
== NULL
) {
282 *status
= U_MEMORY_ALLOCATION_ERROR
;
285 if (U_FAILURE(*status
)) {
290 ((Transliterator
*) trans
)->adoptFilter(filter
);
293 U_CAPI
int32_t U_EXPORT2
294 utrans_countAvailableIDs(void) {
295 return Transliterator::countAvailableIDs();
298 U_CAPI
int32_t U_EXPORT2
299 utrans_getAvailableID(int32_t index
,
300 char* buf
, // may be NULL
301 int32_t bufCapacity
) {
302 return Transliterator::getAvailableID(index
).extract(0, 0x7fffffff, buf
, bufCapacity
, US_INV
);
305 /* Transliterator UEnumeration ---------------------------------------------- */
307 typedef struct UTransEnumeration
{
309 int32_t index
, count
;
313 static int32_t U_CALLCONV
314 utrans_enum_count(UEnumeration
*uenum
, UErrorCode
*pErrorCode
) {
315 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
318 return ((UTransEnumeration
*)uenum
)->count
;
321 static const UChar
* U_CALLCONV
322 utrans_enum_unext(UEnumeration
*uenum
,
323 int32_t* resultLength
,
324 UErrorCode
*pErrorCode
) {
325 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
329 UTransEnumeration
*ute
=(UTransEnumeration
*)uenum
;
330 int32_t index
=ute
->index
;
331 if(index
<ute
->count
) {
332 const UnicodeString
&ID
=Transliterator::getAvailableID(index
);
334 if(resultLength
!=NULL
) {
335 *resultLength
=ID
.length();
337 // Transliterator keeps its ID NUL-terminated
338 return ID
.getBuffer();
341 if(resultLength
!=NULL
) {
347 static void U_CALLCONV
348 utrans_enum_reset(UEnumeration
*uenum
, UErrorCode
*pErrorCode
) {
349 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
353 UTransEnumeration
*ute
=(UTransEnumeration
*)uenum
;
355 ute
->count
=Transliterator::countAvailableIDs();
358 static void U_CALLCONV
359 utrans_enum_close(UEnumeration
*uenum
) {
364 static const UEnumeration utransEnumeration
={
374 U_CAPI UEnumeration
* U_EXPORT2
375 utrans_openIDs(UErrorCode
*pErrorCode
) {
376 UTransEnumeration
*ute
;
378 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
382 ute
=(UTransEnumeration
*)uprv_malloc(sizeof(UTransEnumeration
));
384 *pErrorCode
=U_MEMORY_ALLOCATION_ERROR
;
388 ute
->uenum
=utransEnumeration
;
390 ute
->count
=Transliterator::countAvailableIDs();
391 return (UEnumeration
*)ute
;
394 /********************************************************************
395 * Transliteration API
396 ********************************************************************/
398 U_CAPI
void U_EXPORT2
399 utrans_trans(const UTransliterator
* trans
,
401 const UReplaceableCallbacks
* repFunc
,
404 UErrorCode
* status
) {
406 utrans_ENTRY(status
);
408 if (trans
== 0 || rep
== 0 || repFunc
== 0 || limit
== 0) {
409 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
413 ReplaceableGlue
r(rep
, repFunc
);
415 *limit
= ((Transliterator
*) trans
)->transliterate(r
, start
, *limit
);
418 U_CAPI
void U_EXPORT2
419 utrans_transIncremental(const UTransliterator
* trans
,
421 const UReplaceableCallbacks
* repFunc
,
423 UErrorCode
* status
) {
425 utrans_ENTRY(status
);
427 if (trans
== 0 || rep
== 0 || repFunc
== 0 || pos
== 0) {
428 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
432 ReplaceableGlue
r(rep
, repFunc
);
434 ((Transliterator
*) trans
)->transliterate(r
, *pos
, *status
);
437 U_CAPI
void U_EXPORT2
438 utrans_transUChars(const UTransliterator
* trans
,
441 int32_t textCapacity
,
444 UErrorCode
* status
) {
446 utrans_ENTRY(status
);
448 if (trans
== 0 || text
== 0 || limit
== 0) {
449 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
453 int32_t textLen
= (textLength
== NULL
|| *textLength
< 0)
454 ? u_strlen(text
) : *textLength
;
455 // writeable alias: for this ct, len CANNOT be -1 (why?)
456 UnicodeString
str(text
, textLen
, textCapacity
);
458 *limit
= ((Transliterator
*) trans
)->transliterate(str
, start
, *limit
);
460 // Copy the string buffer back to text (only if necessary)
461 // and fill in *neededCapacity (if neededCapacity != NULL).
462 textLen
= str
.extract(text
, textCapacity
, *status
);
463 if(textLength
!= NULL
) {
464 *textLength
= textLen
;
468 U_CAPI
void U_EXPORT2
469 utrans_transIncrementalUChars(const UTransliterator
* trans
,
472 int32_t textCapacity
,
474 UErrorCode
* status
) {
476 utrans_ENTRY(status
);
478 if (trans
== 0 || text
== 0 || pos
== 0) {
479 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
483 int32_t textLen
= (textLength
== NULL
|| *textLength
< 0)
484 ? u_strlen(text
) : *textLength
;
485 // writeable alias: for this ct, len CANNOT be -1 (why?)
486 UnicodeString
str(text
, textLen
, textCapacity
);
488 ((Transliterator
*) trans
)->transliterate(str
, *pos
, *status
);
490 // Copy the string buffer back to text (only if necessary)
491 // and fill in *neededCapacity (if neededCapacity != NULL).
492 textLen
= str
.extract(text
, textCapacity
, *status
);
493 if(textLength
!= NULL
) {
494 *textLength
= textLen
;
498 U_CAPI
int32_t U_EXPORT2
499 utrans_toRules( const UTransliterator
* trans
,
500 UBool escapeUnprintable
,
501 UChar
* result
, int32_t resultLength
,
502 UErrorCode
* status
) {
503 utrans_ENTRY(status
) 0;
504 if ( (result
==NULL
)? resultLength
!=0: resultLength
<0 ) {
505 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
510 res
.setTo(result
, 0, resultLength
);
511 ((Transliterator
*) trans
)->toRules(res
, escapeUnprintable
);
512 return res
.extract(result
, resultLength
, *status
);
515 U_CAPI USet
* U_EXPORT2
516 utrans_getSourceSet(const UTransliterator
* trans
,
519 UErrorCode
* status
) {
520 utrans_ENTRY(status
) fillIn
;
522 if (fillIn
== NULL
) {
523 fillIn
= uset_openEmpty();
526 ((Transliterator
*) trans
)->handleGetSourceSet(*((UnicodeSet
*)fillIn
));
528 ((Transliterator
*) trans
)->getSourceSet(*((UnicodeSet
*)fillIn
));
533 #endif /* #if !UCONFIG_NO_TRANSLITERATION */