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