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