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