Coverage Report

Created: 2025-01-28 06:38

/src/icu/source/i18n/rbnf.cpp
Line
Count
Source (jump to first uncovered line)
1
// © 2016 and later: Unicode, Inc. and others.
2
// License & terms of use: http://www.unicode.org/copyright.html
3
/*
4
*******************************************************************************
5
* Copyright (C) 1997-2015, International Business Machines Corporation
6
* and others. All Rights Reserved.
7
*******************************************************************************
8
*/
9
10
#include "unicode/utypes.h"
11
#include "utypeinfo.h"  // for 'typeid' to work
12
13
#include "unicode/rbnf.h"
14
15
#if U_HAVE_RBNF
16
17
#include "unicode/normlzr.h"
18
#include "unicode/plurfmt.h"
19
#include "unicode/tblcoll.h"
20
#include "unicode/uchar.h"
21
#include "unicode/ucol.h"
22
#include "unicode/uloc.h"
23
#include "unicode/unum.h"
24
#include "unicode/ures.h"
25
#include "unicode/ustring.h"
26
#include "unicode/utf16.h"
27
#include "unicode/udata.h"
28
#include "unicode/udisplaycontext.h"
29
#include "unicode/brkiter.h"
30
#include "unicode/ucasemap.h"
31
32
#include "cmemory.h"
33
#include "cstring.h"
34
#include "patternprops.h"
35
#include "uresimp.h"
36
#include "nfrs.h"
37
#include "number_decimalquantity.h"
38
39
// debugging
40
// #define RBNF_DEBUG
41
42
#ifdef RBNF_DEBUG
43
#include <stdio.h>
44
#endif
45
46
0
#define U_ICUDATA_RBNF U_ICUDATA_NAME U_TREE_SEPARATOR_STRING "rbnf"
47
48
static const UChar gPercentPercent[] =
49
{
50
    0x25, 0x25, 0
51
}; /* "%%" */
52
53
// All urbnf objects are created through openRules, so we init all of the
54
// Unicode string constants required by rbnf, nfrs, or nfr here.
55
static const UChar gLenientParse[] =
56
{
57
    0x25, 0x25, 0x6C, 0x65, 0x6E, 0x69, 0x65, 0x6E, 0x74, 0x2D, 0x70, 0x61, 0x72, 0x73, 0x65, 0x3A, 0
58
}; /* "%%lenient-parse:" */
59
static const UChar gSemiColon = 0x003B;
60
static const UChar gSemiPercent[] =
61
{
62
    0x3B, 0x25, 0
63
}; /* ";%" */
64
65
0
#define kSomeNumberOfBitsDiv2 22
66
0
#define kHalfMaxDouble (double)(1 << kSomeNumberOfBitsDiv2)
67
0
#define kMaxDouble (kHalfMaxDouble * kHalfMaxDouble)
68
69
U_NAMESPACE_BEGIN
70
71
using number::impl::DecimalQuantity;
72
73
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedNumberFormat)
74
75
/*
76
This is a utility class. It does not use ICU's RTTI.
77
If ICU's RTTI is needed again, you can uncomment the RTTI code and derive from UObject.
78
Please make sure that intltest passes on Windows in Release mode,
79
since the string pooling per compilation unit will mess up how RTTI works.
80
The RTTI code was also removed due to lack of code coverage.
81
*/
82
class LocalizationInfo : public UMemory {
83
protected:
84
    virtual ~LocalizationInfo();
85
    uint32_t refcount;
86
    
87
public:
88
0
    LocalizationInfo() : refcount(0) {}
89
    
90
0
    LocalizationInfo* ref(void) {
91
0
        ++refcount;
92
0
        return this;
93
0
    }
94
    
95
0
    LocalizationInfo* unref(void) {
96
0
        if (refcount && --refcount == 0) {
97
0
            delete this;
98
0
        }
99
0
        return NULL;
100
0
    }
101
    
102
    virtual bool operator==(const LocalizationInfo* rhs) const;
103
0
    inline  bool operator!=(const LocalizationInfo* rhs) const { return !operator==(rhs); }
104
    
105
    virtual int32_t getNumberOfRuleSets(void) const = 0;
106
    virtual const UChar* getRuleSetName(int32_t index) const = 0;
107
    virtual int32_t getNumberOfDisplayLocales(void) const = 0;
108
    virtual const UChar* getLocaleName(int32_t index) const = 0;
109
    virtual const UChar* getDisplayName(int32_t localeIndex, int32_t ruleIndex) const = 0;
110
    
111
    virtual int32_t indexForLocale(const UChar* locale) const;
112
    virtual int32_t indexForRuleSet(const UChar* ruleset) const;
113
    
114
//    virtual UClassID getDynamicClassID() const = 0;
115
//    static UClassID getStaticClassID(void);
116
};
117
118
0
LocalizationInfo::~LocalizationInfo() {}
119
120
//UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(LocalizationInfo)
121
122
// if both strings are NULL, this returns TRUE
123
static UBool 
124
0
streq(const UChar* lhs, const UChar* rhs) {
125
0
    if (rhs == lhs) {
126
0
        return TRUE;
127
0
    }
128
0
    if (lhs && rhs) {
129
0
        return u_strcmp(lhs, rhs) == 0;
130
0
    }
131
0
    return FALSE;
132
0
}
133
134
bool
135
0
LocalizationInfo::operator==(const LocalizationInfo* rhs) const {
136
0
    if (rhs) {
137
0
        if (this == rhs) {
138
0
            return TRUE;
139
0
        }
140
        
141
0
        int32_t rsc = getNumberOfRuleSets();
142
0
        if (rsc == rhs->getNumberOfRuleSets()) {
143
0
            for (int i = 0; i < rsc; ++i) {
144
0
                if (!streq(getRuleSetName(i), rhs->getRuleSetName(i))) {
145
0
                    return FALSE;
146
0
                }
147
0
            }
148
0
            int32_t dlc = getNumberOfDisplayLocales();
149
0
            if (dlc == rhs->getNumberOfDisplayLocales()) {
150
0
                for (int i = 0; i < dlc; ++i) {
151
0
                    const UChar* locale = getLocaleName(i);
152
0
                    int32_t ix = rhs->indexForLocale(locale);
153
                    // if no locale, ix is -1, getLocaleName returns null, so streq returns false
154
0
                    if (!streq(locale, rhs->getLocaleName(ix))) {
155
0
                        return FALSE;
156
0
                    }
157
0
                    for (int j = 0; j < rsc; ++j) {
158
0
                        if (!streq(getDisplayName(i, j), rhs->getDisplayName(ix, j))) {
159
0
                            return FALSE;
160
0
                        }
161
0
                    }
162
0
                }
163
0
                return TRUE;
164
0
            }
165
0
        }
166
0
    }
167
0
    return FALSE;
168
0
}
169
170
int32_t
171
0
LocalizationInfo::indexForLocale(const UChar* locale) const {
172
0
    for (int i = 0; i < getNumberOfDisplayLocales(); ++i) {
173
0
        if (streq(locale, getLocaleName(i))) {
174
0
            return i;
175
0
        }
176
0
    }
177
0
    return -1;
178
0
}
179
180
int32_t
181
0
LocalizationInfo::indexForRuleSet(const UChar* ruleset) const {
182
0
    if (ruleset) {
183
0
        for (int i = 0; i < getNumberOfRuleSets(); ++i) {
184
0
            if (streq(ruleset, getRuleSetName(i))) {
185
0
                return i;
186
0
            }
187
0
        }
188
0
    }
189
0
    return -1;
190
0
}
191
192
193
typedef void (*Fn_Deleter)(void*);
194
195
class VArray {
196
    void** buf;
197
    int32_t cap;
198
    int32_t size;
199
    Fn_Deleter deleter;
200
public:
201
0
    VArray() : buf(NULL), cap(0), size(0), deleter(NULL) {}
202
    
203
0
    VArray(Fn_Deleter del) : buf(NULL), cap(0), size(0), deleter(del) {}
204
    
205
0
    ~VArray() {
206
0
        if (deleter) {
207
0
            for (int i = 0; i < size; ++i) {
208
0
                (*deleter)(buf[i]);
209
0
            }
210
0
        }
211
0
        uprv_free(buf); 
212
0
    }
213
    
214
0
    int32_t length() {
215
0
        return size;
216
0
    }
217
    
218
0
    void add(void* elem, UErrorCode& status) {
219
0
        if (U_SUCCESS(status)) {
220
0
            if (size == cap) {
221
0
                if (cap == 0) {
222
0
                    cap = 1;
223
0
                } else if (cap < 256) {
224
0
                    cap *= 2;
225
0
                } else {
226
0
                    cap += 256;
227
0
                }
228
0
                if (buf == NULL) {
229
0
                    buf = (void**)uprv_malloc(cap * sizeof(void*));
230
0
                } else {
231
0
                    buf = (void**)uprv_realloc(buf, cap * sizeof(void*));
232
0
                }
233
0
                if (buf == NULL) {
234
                    // if we couldn't realloc, we leak the memory we've already allocated, but we're in deep trouble anyway
235
0
                    status = U_MEMORY_ALLOCATION_ERROR;
236
0
                    return;
237
0
                }
238
0
                void* start = &buf[size];
239
0
                size_t count = (cap - size) * sizeof(void*);
240
0
                uprv_memset(start, 0, count); // fill with nulls, just because
241
0
            }
242
0
            buf[size++] = elem;
243
0
        }
244
0
    }
245
    
246
0
    void** release(void) {
247
0
        void** result = buf;
248
0
        buf = NULL;
249
0
        cap = 0;
250
0
        size = 0;
251
0
        return result;
252
0
    }
253
};
254
255
class LocDataParser;
256
257
class StringLocalizationInfo : public LocalizationInfo {
258
    UChar* info;
259
    UChar*** data;
260
    int32_t numRuleSets;
261
    int32_t numLocales;
262
263
friend class LocDataParser;
264
265
    StringLocalizationInfo(UChar* i, UChar*** d, int32_t numRS, int32_t numLocs)
266
0
        : info(i), data(d), numRuleSets(numRS), numLocales(numLocs)
267
0
    {
268
0
    }
269
    
270
public:
271
    static StringLocalizationInfo* create(const UnicodeString& info, UParseError& perror, UErrorCode& status);
272
    
273
    virtual ~StringLocalizationInfo();
274
0
    virtual int32_t getNumberOfRuleSets(void) const { return numRuleSets; }
275
    virtual const UChar* getRuleSetName(int32_t index) const;
276
0
    virtual int32_t getNumberOfDisplayLocales(void) const { return numLocales; }
277
    virtual const UChar* getLocaleName(int32_t index) const;
278
    virtual const UChar* getDisplayName(int32_t localeIndex, int32_t ruleIndex) const;
279
    
280
//    virtual UClassID getDynamicClassID() const;
281
//    static UClassID getStaticClassID(void);
282
    
283
private:
284
    void init(UErrorCode& status) const;
285
};
286
287
288
enum {
289
    OPEN_ANGLE = 0x003c, /* '<' */
290
    CLOSE_ANGLE = 0x003e, /* '>' */
291
    COMMA = 0x002c,
292
    TICK = 0x0027,
293
    QUOTE = 0x0022,
294
    SPACE = 0x0020
295
};
296
297
/**
298
 * Utility for parsing a localization string and returning a StringLocalizationInfo*.
299
 */
300
class LocDataParser {
301
    UChar* data;
302
    const UChar* e;
303
    UChar* p;
304
    UChar ch;
305
    UParseError& pe;
306
    UErrorCode& ec;
307
    
308
public:
309
    LocDataParser(UParseError& parseError, UErrorCode& status) 
310
0
        : data(NULL), e(NULL), p(NULL), ch(0xffff), pe(parseError), ec(status) {}
311
0
    ~LocDataParser() {}
312
    
313
    /*
314
    * On a successful parse, return a StringLocalizationInfo*, otherwise delete locData, set perror and status,
315
    * and return NULL.  The StringLocalizationInfo will adopt locData if it is created.
316
    */
317
    StringLocalizationInfo* parse(UChar* data, int32_t len);
318
    
319
private:
320
    
321
0
    inline void inc(void) {
322
0
        ++p;
323
0
        ch = 0xffff;
324
0
    }
325
0
    inline UBool checkInc(UChar c) {
326
0
        if (p < e && (ch == c || *p == c)) {
327
0
            inc();
328
0
            return TRUE;
329
0
        }
330
0
        return FALSE;
331
0
    }
332
0
    inline UBool check(UChar c) {
333
0
        return p < e && (ch == c || *p == c);
334
0
    }
335
0
    inline void skipWhitespace(void) {
336
0
        while (p < e && PatternProps::isWhiteSpace(ch != 0xffff ? ch : *p)) {
337
0
            inc();
338
0
        }
339
0
    }
340
0
    inline UBool inList(UChar c, const UChar* list) const {
341
0
        if (*list == SPACE && PatternProps::isWhiteSpace(c)) {
342
0
            return TRUE;
343
0
        }
344
0
        while (*list && *list != c) {
345
0
            ++list;
346
0
        }
347
0
        return *list == c;
348
0
    }
349
    void parseError(const char* msg);
350
    
351
    StringLocalizationInfo* doParse(void);
352
        
353
    UChar** nextArray(int32_t& requiredLength);
354
    UChar*  nextString(void);
355
};
356
357
#ifdef RBNF_DEBUG
358
#define ERROR(msg) UPRV_BLOCK_MACRO_BEGIN { \
359
    parseError(msg); \
360
    return NULL; \
361
} UPRV_BLOCK_MACRO_END
362
#define EXPLANATION_ARG explanationArg
363
#else
364
0
#define ERROR(msg) UPRV_BLOCK_MACRO_BEGIN { \
365
0
    parseError(NULL); \
366
0
    return NULL; \
367
0
} UPRV_BLOCK_MACRO_END
368
#define EXPLANATION_ARG
369
#endif
370
        
371
372
static const UChar DQUOTE_STOPLIST[] = { 
373
    QUOTE, 0
374
};
375
376
static const UChar SQUOTE_STOPLIST[] = { 
377
    TICK, 0
378
};
379
380
static const UChar NOQUOTE_STOPLIST[] = { 
381
    SPACE, COMMA, CLOSE_ANGLE, OPEN_ANGLE, TICK, QUOTE, 0
382
};
383
384
static void
385
0
DeleteFn(void* p) {
386
0
  uprv_free(p);
387
0
}
388
389
StringLocalizationInfo*
390
0
LocDataParser::parse(UChar* _data, int32_t len) {
391
0
    if (U_FAILURE(ec)) {
392
0
        if (_data) uprv_free(_data);
393
0
        return NULL;
394
0
    }
395
396
0
    pe.line = 0;
397
0
    pe.offset = -1;
398
0
    pe.postContext[0] = 0;
399
0
    pe.preContext[0] = 0;
400
401
0
    if (_data == NULL) {
402
0
        ec = U_ILLEGAL_ARGUMENT_ERROR;
403
0
        return NULL;
404
0
    }
405
406
0
    if (len <= 0) {
407
0
        ec = U_ILLEGAL_ARGUMENT_ERROR;
408
0
        uprv_free(_data);
409
0
        return NULL;
410
0
    }
411
412
0
    data = _data;
413
0
    e = data + len;
414
0
    p = _data;
415
0
    ch = 0xffff;
416
417
0
    return doParse();
418
0
}
419
420
421
StringLocalizationInfo*
422
0
LocDataParser::doParse(void) {
423
0
    skipWhitespace();
424
0
    if (!checkInc(OPEN_ANGLE)) {
425
0
        ERROR("Missing open angle");
426
0
    } else {
427
0
        VArray array(DeleteFn);
428
0
        UBool mightHaveNext = TRUE;
429
0
        int32_t requiredLength = -1;
430
0
        while (mightHaveNext) {
431
0
            mightHaveNext = FALSE;
432
0
            UChar** elem = nextArray(requiredLength);
433
0
            skipWhitespace();
434
0
            UBool haveComma = check(COMMA);
435
0
            if (elem) {
436
0
                array.add(elem, ec);
437
0
                if (haveComma) {
438
0
                    inc();
439
0
                    mightHaveNext = TRUE;
440
0
                }
441
0
            } else if (haveComma) {
442
0
                ERROR("Unexpected character");
443
0
            }
444
0
        }
445
446
0
        skipWhitespace();
447
0
        if (!checkInc(CLOSE_ANGLE)) {
448
0
            if (check(OPEN_ANGLE)) {
449
0
                ERROR("Missing comma in outer array");
450
0
            } else {
451
0
                ERROR("Missing close angle bracket in outer array");
452
0
            }
453
0
        }
454
455
0
        skipWhitespace();
456
0
        if (p != e) {
457
0
            ERROR("Extra text after close of localization data");
458
0
        }
459
460
0
        array.add(NULL, ec);
461
0
        if (U_SUCCESS(ec)) {
462
0
            int32_t numLocs = array.length() - 2; // subtract first, NULL
463
0
            UChar*** result = (UChar***)array.release();
464
            
465
0
            return new StringLocalizationInfo(data, result, requiredLength-2, numLocs); // subtract first, NULL
466
0
        }
467
0
    }
468
  
469
0
    ERROR("Unknown error");
470
0
}
471
472
UChar**
473
0
LocDataParser::nextArray(int32_t& requiredLength) {
474
0
    if (U_FAILURE(ec)) {
475
0
        return NULL;
476
0
    }
477
    
478
0
    skipWhitespace();
479
0
    if (!checkInc(OPEN_ANGLE)) {
480
0
        ERROR("Missing open angle");
481
0
    }
482
483
0
    VArray array;
484
0
    UBool mightHaveNext = TRUE;
485
0
    while (mightHaveNext) {
486
0
        mightHaveNext = FALSE;
487
0
        UChar* elem = nextString();
488
0
        skipWhitespace();
489
0
        UBool haveComma = check(COMMA);
490
0
        if (elem) {
491
0
            array.add(elem, ec);
492
0
            if (haveComma) {
493
0
                inc();
494
0
                mightHaveNext = TRUE;
495
0
            }
496
0
        } else if (haveComma) {
497
0
            ERROR("Unexpected comma");
498
0
        }
499
0
    }
500
0
    skipWhitespace();
501
0
    if (!checkInc(CLOSE_ANGLE)) {
502
0
        if (check(OPEN_ANGLE)) {
503
0
            ERROR("Missing close angle bracket in inner array");
504
0
        } else {
505
0
            ERROR("Missing comma in inner array");
506
0
        }
507
0
    }
508
509
0
    array.add(NULL, ec);
510
0
    if (U_SUCCESS(ec)) {
511
0
        if (requiredLength == -1) {
512
0
            requiredLength = array.length() + 1;
513
0
        } else if (array.length() != requiredLength) {
514
0
            ec = U_ILLEGAL_ARGUMENT_ERROR;
515
0
            ERROR("Array not of required length");
516
0
        }
517
        
518
0
        return (UChar**)array.release();
519
0
    }
520
0
    ERROR("Unknown Error");
521
0
}
522
523
UChar*
524
0
LocDataParser::nextString() {
525
0
    UChar* result = NULL;
526
    
527
0
    skipWhitespace();
528
0
    if (p < e) {
529
0
        const UChar* terminators;
530
0
        UChar c = *p;
531
0
        UBool haveQuote = c == QUOTE || c == TICK;
532
0
        if (haveQuote) {
533
0
            inc();
534
0
            terminators = c == QUOTE ? DQUOTE_STOPLIST : SQUOTE_STOPLIST;
535
0
        } else {
536
0
            terminators = NOQUOTE_STOPLIST;
537
0
        }
538
0
        UChar* start = p;
539
0
        while (p < e && !inList(*p, terminators)) ++p;
540
0
        if (p == e) {
541
0
            ERROR("Unexpected end of data");
542
0
        }
543
        
544
0
        UChar x = *p;
545
0
        if (p > start) {
546
0
            ch = x;
547
0
            *p = 0x0; // terminate by writing to data
548
0
            result = start; // just point into data
549
0
        }
550
0
        if (haveQuote) {
551
0
            if (x != c) {
552
0
                ERROR("Missing matching quote");
553
0
            } else if (p == start) {
554
0
                ERROR("Empty string");
555
0
            }
556
0
            inc();
557
0
        } else if (x == OPEN_ANGLE || x == TICK || x == QUOTE) {
558
0
            ERROR("Unexpected character in string");
559
0
        }
560
0
    }
561
562
    // ok for there to be no next string
563
0
    return result;
564
0
}
565
566
void LocDataParser::parseError(const char* EXPLANATION_ARG)
567
0
{
568
0
    if (!data) {
569
0
        return;
570
0
    }
571
572
0
    const UChar* start = p - U_PARSE_CONTEXT_LEN - 1;
573
0
    if (start < data) {
574
0
        start = data;
575
0
    }
576
0
    for (UChar* x = p; --x >= start;) {
577
0
        if (!*x) {
578
0
            start = x+1;
579
0
            break;
580
0
        }
581
0
    }
582
0
    const UChar* limit = p + U_PARSE_CONTEXT_LEN - 1;
583
0
    if (limit > e) {
584
0
        limit = e;
585
0
    }
586
0
    u_strncpy(pe.preContext, start, (int32_t)(p-start));
587
0
    pe.preContext[p-start] = 0;
588
0
    u_strncpy(pe.postContext, p, (int32_t)(limit-p));
589
0
    pe.postContext[limit-p] = 0;
590
0
    pe.offset = (int32_t)(p - data);
591
    
592
#ifdef RBNF_DEBUG
593
    fprintf(stderr, "%s at or near character %ld: ", EXPLANATION_ARG, p-data);
594
595
    UnicodeString msg;
596
    msg.append(start, p - start);
597
    msg.append((UChar)0x002f); /* SOLIDUS/SLASH */
598
    msg.append(p, limit-p);
599
    msg.append(UNICODE_STRING_SIMPLE("'"));
600
    
601
    char buf[128];
602
    int32_t len = msg.extract(0, msg.length(), buf, 128);
603
    if (len >= 128) {
604
        buf[127] = 0;
605
    } else {
606
        buf[len] = 0;
607
    }
608
    fprintf(stderr, "%s\n", buf);
609
    fflush(stderr);
610
#endif
611
    
612
0
    uprv_free(data);
613
0
    data = NULL;
614
0
    p = NULL;
615
0
    e = NULL;
616
    
617
0
    if (U_SUCCESS(ec)) {
618
0
        ec = U_PARSE_ERROR;
619
0
    }
620
0
}
621
622
//UOBJECT_DEFINE_RTTI_IMPLEMENTATION(StringLocalizationInfo)
623
624
StringLocalizationInfo* 
625
0
StringLocalizationInfo::create(const UnicodeString& info, UParseError& perror, UErrorCode& status) {
626
0
    if (U_FAILURE(status)) {
627
0
        return NULL;
628
0
    }
629
    
630
0
    int32_t len = info.length();
631
0
    if (len == 0) {
632
0
        return NULL; // no error;
633
0
    }
634
    
635
0
    UChar* p = (UChar*)uprv_malloc(len * sizeof(UChar));
636
0
    if (!p) {
637
0
        status = U_MEMORY_ALLOCATION_ERROR;
638
0
        return NULL;
639
0
    }
640
0
    info.extract(p, len, status);
641
0
    if (!U_FAILURE(status)) {
642
0
        status = U_ZERO_ERROR; // clear warning about non-termination
643
0
    }
644
    
645
0
    LocDataParser parser(perror, status);
646
0
    return parser.parse(p, len);
647
0
}
648
649
0
StringLocalizationInfo::~StringLocalizationInfo() {
650
0
    for (UChar*** p = (UChar***)data; *p; ++p) {
651
        // remaining data is simply pointer into our unicode string data.
652
0
        if (*p) uprv_free(*p);
653
0
    }
654
0
    if (data) uprv_free(data);
655
0
    if (info) uprv_free(info);
656
0
}
657
658
659
const UChar*
660
0
StringLocalizationInfo::getRuleSetName(int32_t index) const {
661
0
    if (index >= 0 && index < getNumberOfRuleSets()) {
662
0
        return data[0][index];
663
0
    }
664
0
    return NULL;
665
0
}
666
667
const UChar*
668
0
StringLocalizationInfo::getLocaleName(int32_t index) const {
669
0
    if (index >= 0 && index < getNumberOfDisplayLocales()) {
670
0
        return data[index+1][0];
671
0
    }
672
0
    return NULL;
673
0
}
674
675
const UChar*
676
0
StringLocalizationInfo::getDisplayName(int32_t localeIndex, int32_t ruleIndex) const {
677
0
    if (localeIndex >= 0 && localeIndex < getNumberOfDisplayLocales() &&
678
0
        ruleIndex >= 0 && ruleIndex < getNumberOfRuleSets()) {
679
0
        return data[localeIndex+1][ruleIndex+1];
680
0
    }
681
0
    return NULL;
682
0
}
683
684
// ----------
685
686
RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, 
687
                                             const UnicodeString& locs,
688
                                             const Locale& alocale, UParseError& perror, UErrorCode& status)
689
  : fRuleSets(NULL)
690
  , ruleSetDescriptions(NULL)
691
0
  , numRuleSets(0)
692
  , defaultRuleSet(NULL)
693
0
  , locale(alocale)
694
  , collator(NULL)
695
  , decimalFormatSymbols(NULL)
696
  , defaultInfinityRule(NULL)
697
  , defaultNaNRule(NULL)
698
0
  , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
699
0
  , lenient(FALSE)
700
  , lenientParseRules(NULL)
701
  , localizations(NULL)
702
0
  , capitalizationInfoSet(FALSE)
703
0
  , capitalizationForUIListMenu(FALSE)
704
0
  , capitalizationForStandAlone(FALSE)
705
  , capitalizationBrkIter(NULL)
706
0
{
707
0
  LocalizationInfo* locinfo = StringLocalizationInfo::create(locs, perror, status);
708
0
  init(description, locinfo, perror, status);
709
0
}
710
711
RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, 
712
                                             const UnicodeString& locs,
713
                                             UParseError& perror, UErrorCode& status)
714
  : fRuleSets(NULL)
715
  , ruleSetDescriptions(NULL)
716
0
  , numRuleSets(0)
717
  , defaultRuleSet(NULL)
718
0
  , locale(Locale::getDefault())
719
  , collator(NULL)
720
  , decimalFormatSymbols(NULL)
721
  , defaultInfinityRule(NULL)
722
  , defaultNaNRule(NULL)
723
0
  , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
724
0
  , lenient(FALSE)
725
  , lenientParseRules(NULL)
726
  , localizations(NULL)
727
0
  , capitalizationInfoSet(FALSE)
728
0
  , capitalizationForUIListMenu(FALSE)
729
0
  , capitalizationForStandAlone(FALSE)
730
  , capitalizationBrkIter(NULL)
731
0
{
732
0
  LocalizationInfo* locinfo = StringLocalizationInfo::create(locs, perror, status);
733
0
  init(description, locinfo, perror, status);
734
0
}
735
736
RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, 
737
                                             LocalizationInfo* info,
738
                                             const Locale& alocale, UParseError& perror, UErrorCode& status)
739
  : fRuleSets(NULL)
740
  , ruleSetDescriptions(NULL)
741
0
  , numRuleSets(0)
742
  , defaultRuleSet(NULL)
743
0
  , locale(alocale)
744
  , collator(NULL)
745
  , decimalFormatSymbols(NULL)
746
  , defaultInfinityRule(NULL)
747
  , defaultNaNRule(NULL)
748
0
  , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
749
0
  , lenient(FALSE)
750
  , lenientParseRules(NULL)
751
  , localizations(NULL)
752
0
  , capitalizationInfoSet(FALSE)
753
0
  , capitalizationForUIListMenu(FALSE)
754
0
  , capitalizationForStandAlone(FALSE)
755
  , capitalizationBrkIter(NULL)
756
0
{
757
0
  init(description, info, perror, status);
758
0
}
759
760
RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, 
761
                         UParseError& perror, 
762
                         UErrorCode& status) 
763
  : fRuleSets(NULL)
764
  , ruleSetDescriptions(NULL)
765
0
  , numRuleSets(0)
766
  , defaultRuleSet(NULL)
767
0
  , locale(Locale::getDefault())
768
  , collator(NULL)
769
  , decimalFormatSymbols(NULL)
770
  , defaultInfinityRule(NULL)
771
  , defaultNaNRule(NULL)
772
0
  , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
773
0
  , lenient(FALSE)
774
  , lenientParseRules(NULL)
775
  , localizations(NULL)
776
0
  , capitalizationInfoSet(FALSE)
777
0
  , capitalizationForUIListMenu(FALSE)
778
0
  , capitalizationForStandAlone(FALSE)
779
  , capitalizationBrkIter(NULL)
780
0
{
781
0
    init(description, NULL, perror, status);
782
0
}
783
784
RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, 
785
                         const Locale& aLocale,
786
                         UParseError& perror, 
787
                         UErrorCode& status) 
788
  : fRuleSets(NULL)
789
  , ruleSetDescriptions(NULL)
790
0
  , numRuleSets(0)
791
  , defaultRuleSet(NULL)
792
0
  , locale(aLocale)
793
  , collator(NULL)
794
  , decimalFormatSymbols(NULL)
795
  , defaultInfinityRule(NULL)
796
  , defaultNaNRule(NULL)
797
0
  , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
798
0
  , lenient(FALSE)
799
  , lenientParseRules(NULL)
800
  , localizations(NULL)
801
0
  , capitalizationInfoSet(FALSE)
802
0
  , capitalizationForUIListMenu(FALSE)
803
0
  , capitalizationForStandAlone(FALSE)
804
  , capitalizationBrkIter(NULL)
805
0
{
806
0
    init(description, NULL, perror, status);
807
0
}
808
809
RuleBasedNumberFormat::RuleBasedNumberFormat(URBNFRuleSetTag tag, const Locale& alocale, UErrorCode& status)
810
  : fRuleSets(NULL)
811
  , ruleSetDescriptions(NULL)
812
0
  , numRuleSets(0)
813
  , defaultRuleSet(NULL)
814
0
  , locale(alocale)
815
  , collator(NULL)
816
  , decimalFormatSymbols(NULL)
817
  , defaultInfinityRule(NULL)
818
  , defaultNaNRule(NULL)
819
0
  , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
820
0
  , lenient(FALSE)
821
  , lenientParseRules(NULL)
822
  , localizations(NULL)
823
0
  , capitalizationInfoSet(FALSE)
824
0
  , capitalizationForUIListMenu(FALSE)
825
0
  , capitalizationForStandAlone(FALSE)
826
  , capitalizationBrkIter(NULL)
827
0
{
828
0
    if (U_FAILURE(status)) {
829
0
        return;
830
0
    }
831
832
0
    const char* rules_tag = "RBNFRules";
833
0
    const char* fmt_tag = "";
834
0
    switch (tag) {
835
0
    case URBNF_SPELLOUT: fmt_tag = "SpelloutRules"; break;
836
0
    case URBNF_ORDINAL: fmt_tag = "OrdinalRules"; break;
837
0
    case URBNF_DURATION: fmt_tag = "DurationRules"; break;
838
0
    case URBNF_NUMBERING_SYSTEM: fmt_tag = "NumberingSystemRules"; break;
839
0
    default: status = U_ILLEGAL_ARGUMENT_ERROR; return;
840
0
    }
841
842
    // TODO: read localization info from resource
843
0
    LocalizationInfo* locinfo = NULL;
844
845
0
    UResourceBundle* nfrb = ures_open(U_ICUDATA_RBNF, locale.getName(), &status);
846
0
    if (U_SUCCESS(status)) {
847
0
        setLocaleIDs(ures_getLocaleByType(nfrb, ULOC_VALID_LOCALE, &status),
848
0
                     ures_getLocaleByType(nfrb, ULOC_ACTUAL_LOCALE, &status));
849
850
0
        UResourceBundle* rbnfRules = ures_getByKeyWithFallback(nfrb, rules_tag, NULL, &status);
851
0
        if (U_FAILURE(status)) {
852
0
            ures_close(nfrb);
853
0
        }
854
0
        UResourceBundle* ruleSets = ures_getByKeyWithFallback(rbnfRules, fmt_tag, NULL, &status);
855
0
        if (U_FAILURE(status)) {
856
0
            ures_close(rbnfRules);
857
0
            ures_close(nfrb);
858
0
            return;
859
0
        }
860
861
0
        UnicodeString desc;
862
0
        while (ures_hasNext(ruleSets)) {
863
0
           desc.append(ures_getNextUnicodeString(ruleSets,NULL,&status));
864
0
        }
865
0
        UParseError perror;
866
867
0
        init(desc, locinfo, perror, status);
868
869
0
        ures_close(ruleSets);
870
0
        ures_close(rbnfRules);
871
0
    }
872
0
    ures_close(nfrb);
873
0
}
874
875
RuleBasedNumberFormat::RuleBasedNumberFormat(const RuleBasedNumberFormat& rhs)
876
0
  : NumberFormat(rhs)
877
  , fRuleSets(NULL)
878
  , ruleSetDescriptions(NULL)
879
0
  , numRuleSets(0)
880
  , defaultRuleSet(NULL)
881
0
  , locale(rhs.locale)
882
  , collator(NULL)
883
  , decimalFormatSymbols(NULL)
884
  , defaultInfinityRule(NULL)
885
  , defaultNaNRule(NULL)
886
0
  , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
887
0
  , lenient(FALSE)
888
  , lenientParseRules(NULL)
889
  , localizations(NULL)
890
0
  , capitalizationInfoSet(FALSE)
891
0
  , capitalizationForUIListMenu(FALSE)
892
0
  , capitalizationForStandAlone(FALSE)
893
  , capitalizationBrkIter(NULL)
894
0
{
895
0
    this->operator=(rhs);
896
0
}
897
898
// --------
899
900
RuleBasedNumberFormat&
901
RuleBasedNumberFormat::operator=(const RuleBasedNumberFormat& rhs)
902
0
{
903
0
    if (this == &rhs) {
904
0
        return *this;
905
0
    }
906
0
    NumberFormat::operator=(rhs);
907
0
    UErrorCode status = U_ZERO_ERROR;
908
0
    dispose();
909
0
    locale = rhs.locale;
910
0
    lenient = rhs.lenient;
911
912
0
    UParseError perror;
913
0
    setDecimalFormatSymbols(*rhs.getDecimalFormatSymbols());
914
0
    init(rhs.originalDescription, rhs.localizations ? rhs.localizations->ref() : NULL, perror, status);
915
0
    setDefaultRuleSet(rhs.getDefaultRuleSetName(), status);
916
0
    setRoundingMode(rhs.getRoundingMode());
917
918
0
    capitalizationInfoSet = rhs.capitalizationInfoSet;
919
0
    capitalizationForUIListMenu = rhs.capitalizationForUIListMenu;
920
0
    capitalizationForStandAlone = rhs.capitalizationForStandAlone;
921
0
#if !UCONFIG_NO_BREAK_ITERATION
922
0
    capitalizationBrkIter = (rhs.capitalizationBrkIter!=NULL)? rhs.capitalizationBrkIter->clone(): NULL;
923
0
#endif
924
925
0
    return *this;
926
0
}
927
928
RuleBasedNumberFormat::~RuleBasedNumberFormat()
929
0
{
930
0
    dispose();
931
0
}
932
933
RuleBasedNumberFormat*
934
RuleBasedNumberFormat::clone() const
935
0
{
936
0
    return new RuleBasedNumberFormat(*this);
937
0
}
938
939
bool
940
RuleBasedNumberFormat::operator==(const Format& other) const
941
0
{
942
0
    if (this == &other) {
943
0
        return TRUE;
944
0
    }
945
946
0
    if (typeid(*this) == typeid(other)) {
947
0
        const RuleBasedNumberFormat& rhs = (const RuleBasedNumberFormat&)other;
948
        // test for capitalization info equality is adequately handled
949
        // by the NumberFormat test for fCapitalizationContext equality;
950
        // the info here is just derived from that.
951
0
        if (locale == rhs.locale &&
952
0
            lenient == rhs.lenient &&
953
0
            (localizations == NULL 
954
0
                ? rhs.localizations == NULL 
955
0
                : (rhs.localizations == NULL 
956
0
                    ? FALSE
957
0
                    : *localizations == rhs.localizations))) {
958
959
0
            NFRuleSet** p = fRuleSets;
960
0
            NFRuleSet** q = rhs.fRuleSets;
961
0
            if (p == NULL) {
962
0
                return q == NULL;
963
0
            } else if (q == NULL) {
964
0
                return FALSE;
965
0
            }
966
0
            while (*p && *q && (**p == **q)) {
967
0
                ++p;
968
0
                ++q;
969
0
            }
970
0
            return *q == NULL && *p == NULL;
971
0
        }
972
0
    }
973
974
0
    return FALSE;
975
0
}
976
977
UnicodeString
978
RuleBasedNumberFormat::getRules() const
979
0
{
980
0
    UnicodeString result;
981
0
    if (fRuleSets != NULL) {
982
0
        for (NFRuleSet** p = fRuleSets; *p; ++p) {
983
0
            (*p)->appendRules(result);
984
0
        }
985
0
    }
986
0
    return result;
987
0
}
988
989
UnicodeString
990
RuleBasedNumberFormat::getRuleSetName(int32_t index) const
991
0
{
992
0
    if (localizations) {
993
0
        UnicodeString string(TRUE, localizations->getRuleSetName(index), (int32_t)-1);
994
0
        return string;
995
0
    }
996
0
    else if (fRuleSets) {
997
0
        UnicodeString result;
998
0
        for (NFRuleSet** p = fRuleSets; *p; ++p) {
999
0
            NFRuleSet* rs = *p;
1000
0
            if (rs->isPublic()) {
1001
0
                if (--index == -1) {
1002
0
                    rs->getName(result);
1003
0
                    return result;
1004
0
                }
1005
0
            }
1006
0
        }
1007
0
    }
1008
0
    UnicodeString empty;
1009
0
    return empty;
1010
0
}
1011
1012
int32_t
1013
RuleBasedNumberFormat::getNumberOfRuleSetNames() const
1014
0
{
1015
0
    int32_t result = 0;
1016
0
    if (localizations) {
1017
0
        result = localizations->getNumberOfRuleSets();
1018
0
    }
1019
0
    else if (fRuleSets) {
1020
0
        for (NFRuleSet** p = fRuleSets; *p; ++p) {
1021
0
            if ((**p).isPublic()) {
1022
0
                ++result;
1023
0
            }
1024
0
        }
1025
0
    }
1026
0
    return result;
1027
0
}
1028
1029
int32_t 
1030
0
RuleBasedNumberFormat::getNumberOfRuleSetDisplayNameLocales(void) const {
1031
0
    if (localizations) {
1032
0
        return localizations->getNumberOfDisplayLocales();
1033
0
    }
1034
0
    return 0;
1035
0
}
1036
1037
Locale 
1038
0
RuleBasedNumberFormat::getRuleSetDisplayNameLocale(int32_t index, UErrorCode& status) const {
1039
0
    if (U_FAILURE(status)) {
1040
0
        return Locale("");
1041
0
    }
1042
0
    if (localizations && index >= 0 && index < localizations->getNumberOfDisplayLocales()) {
1043
0
        UnicodeString name(TRUE, localizations->getLocaleName(index), -1);
1044
0
        char buffer[64];
1045
0
        int32_t cap = name.length() + 1;
1046
0
        char* bp = buffer;
1047
0
        if (cap > 64) {
1048
0
            bp = (char *)uprv_malloc(cap);
1049
0
            if (bp == NULL) {
1050
0
                status = U_MEMORY_ALLOCATION_ERROR;
1051
0
                return Locale("");
1052
0
            }
1053
0
        }
1054
0
        name.extract(0, name.length(), bp, cap, UnicodeString::kInvariant);
1055
0
        Locale retLocale(bp);
1056
0
        if (bp != buffer) {
1057
0
            uprv_free(bp);
1058
0
        }
1059
0
        return retLocale;
1060
0
    }
1061
0
    status = U_ILLEGAL_ARGUMENT_ERROR;
1062
0
    Locale retLocale;
1063
0
    return retLocale;
1064
0
}
1065
1066
UnicodeString 
1067
0
RuleBasedNumberFormat::getRuleSetDisplayName(int32_t index, const Locale& localeParam) {
1068
0
    if (localizations && index >= 0 && index < localizations->getNumberOfRuleSets()) {
1069
0
        UnicodeString localeName(localeParam.getBaseName(), -1, UnicodeString::kInvariant); 
1070
0
        int32_t len = localeName.length();
1071
0
        UChar* localeStr = localeName.getBuffer(len + 1);
1072
0
        while (len >= 0) {
1073
0
            localeStr[len] = 0;
1074
0
            int32_t ix = localizations->indexForLocale(localeStr);
1075
0
            if (ix >= 0) {
1076
0
                UnicodeString name(TRUE, localizations->getDisplayName(ix, index), -1);
1077
0
                return name;
1078
0
            }
1079
            
1080
            // trim trailing portion, skipping over omitted sections
1081
0
            do { --len;} while (len > 0 && localeStr[len] != 0x005f); // underscore
1082
0
            while (len > 0 && localeStr[len-1] == 0x005F) --len;
1083
0
        }
1084
0
        UnicodeString name(TRUE, localizations->getRuleSetName(index), -1);
1085
0
        return name;
1086
0
    }
1087
0
    UnicodeString bogus;
1088
0
    bogus.setToBogus();
1089
0
    return bogus;
1090
0
}
1091
1092
UnicodeString 
1093
0
RuleBasedNumberFormat::getRuleSetDisplayName(const UnicodeString& ruleSetName, const Locale& localeParam) {
1094
0
    if (localizations) {
1095
0
        UnicodeString rsn(ruleSetName);
1096
0
        int32_t ix = localizations->indexForRuleSet(rsn.getTerminatedBuffer());
1097
0
        return getRuleSetDisplayName(ix, localeParam);
1098
0
    }
1099
0
    UnicodeString bogus;
1100
0
    bogus.setToBogus();
1101
0
    return bogus;
1102
0
}
1103
1104
NFRuleSet*
1105
RuleBasedNumberFormat::findRuleSet(const UnicodeString& name, UErrorCode& status) const
1106
0
{
1107
0
    if (U_SUCCESS(status) && fRuleSets) {
1108
0
        for (NFRuleSet** p = fRuleSets; *p; ++p) {
1109
0
            NFRuleSet* rs = *p;
1110
0
            if (rs->isNamed(name)) {
1111
0
                return rs;
1112
0
            }
1113
0
        }
1114
0
        status = U_ILLEGAL_ARGUMENT_ERROR;
1115
0
    }
1116
0
    return NULL;
1117
0
}
1118
1119
UnicodeString&
1120
RuleBasedNumberFormat::format(const DecimalQuantity &number,
1121
                     UnicodeString& appendTo,
1122
                     FieldPosition& pos,
1123
0
                     UErrorCode &status) const {
1124
0
    if (U_FAILURE(status)) {
1125
0
        return appendTo;
1126
0
    }
1127
0
    DecimalQuantity copy(number);
1128
0
    if (copy.fitsInLong()) {
1129
0
        format(number.toLong(), appendTo, pos, status);
1130
0
    }
1131
0
    else {
1132
0
        copy.roundToMagnitude(0, number::impl::RoundingMode::UNUM_ROUND_HALFEVEN, status);
1133
0
        if (copy.fitsInLong()) {
1134
0
            format(number.toDouble(), appendTo, pos, status);
1135
0
        }
1136
0
        else {
1137
            // We're outside of our normal range that this framework can handle.
1138
            // The DecimalFormat will provide more accurate results.
1139
1140
            // TODO this section should probably be optimized. The DecimalFormat is shared in ICU4J.
1141
0
            LocalPointer<NumberFormat> decimalFormat(NumberFormat::createInstance(locale, UNUM_DECIMAL, status), status);
1142
0
            if (decimalFormat.isNull()) {
1143
0
                return appendTo;
1144
0
            }
1145
0
            Formattable f;
1146
0
            LocalPointer<DecimalQuantity> decimalQuantity(new DecimalQuantity(number), status);
1147
0
            if (decimalQuantity.isNull()) {
1148
0
                return appendTo;
1149
0
            }
1150
0
            f.adoptDecimalQuantity(decimalQuantity.orphan()); // f now owns decimalQuantity.
1151
0
            decimalFormat->format(f, appendTo, pos, status);
1152
0
        }
1153
0
    }
1154
0
    return appendTo;
1155
0
}
1156
1157
UnicodeString&
1158
RuleBasedNumberFormat::format(int32_t number,
1159
                              UnicodeString& toAppendTo,
1160
                              FieldPosition& pos) const
1161
0
{
1162
0
    return format((int64_t)number, toAppendTo, pos);
1163
0
}
1164
1165
1166
UnicodeString&
1167
RuleBasedNumberFormat::format(int64_t number,
1168
                              UnicodeString& toAppendTo,
1169
                              FieldPosition& /* pos */) const
1170
0
{
1171
0
    if (defaultRuleSet) {
1172
0
        UErrorCode status = U_ZERO_ERROR;
1173
0
        format(number, defaultRuleSet, toAppendTo, status);
1174
0
    }
1175
0
    return toAppendTo;
1176
0
}
1177
1178
1179
UnicodeString&
1180
RuleBasedNumberFormat::format(double number,
1181
                              UnicodeString& toAppendTo,
1182
                              FieldPosition& /* pos */) const
1183
0
{
1184
0
    UErrorCode status = U_ZERO_ERROR;
1185
0
    if (defaultRuleSet) {
1186
0
        format(number, *defaultRuleSet, toAppendTo, status);
1187
0
    }
1188
0
    return toAppendTo;
1189
0
}
1190
1191
1192
UnicodeString&
1193
RuleBasedNumberFormat::format(int32_t number,
1194
                              const UnicodeString& ruleSetName,
1195
                              UnicodeString& toAppendTo,
1196
                              FieldPosition& pos,
1197
                              UErrorCode& status) const
1198
0
{
1199
0
    return format((int64_t)number, ruleSetName, toAppendTo, pos, status);
1200
0
}
1201
1202
1203
UnicodeString&
1204
RuleBasedNumberFormat::format(int64_t number,
1205
                              const UnicodeString& ruleSetName,
1206
                              UnicodeString& toAppendTo,
1207
                              FieldPosition& /* pos */,
1208
                              UErrorCode& status) const
1209
0
{
1210
0
    if (U_SUCCESS(status)) {
1211
0
        if (ruleSetName.indexOf(gPercentPercent, 2, 0) == 0) {
1212
            // throw new IllegalArgumentException("Can't use internal rule set");
1213
0
            status = U_ILLEGAL_ARGUMENT_ERROR;
1214
0
        } else {
1215
0
            NFRuleSet *rs = findRuleSet(ruleSetName, status);
1216
0
            if (rs) {
1217
0
                format(number, rs, toAppendTo, status);
1218
0
            }
1219
0
        }
1220
0
    }
1221
0
    return toAppendTo;
1222
0
}
1223
1224
1225
UnicodeString&
1226
RuleBasedNumberFormat::format(double number,
1227
                              const UnicodeString& ruleSetName,
1228
                              UnicodeString& toAppendTo,
1229
                              FieldPosition& /* pos */,
1230
                              UErrorCode& status) const
1231
0
{
1232
0
    if (U_SUCCESS(status)) {
1233
0
        if (ruleSetName.indexOf(gPercentPercent, 2, 0) == 0) {
1234
            // throw new IllegalArgumentException("Can't use internal rule set");
1235
0
            status = U_ILLEGAL_ARGUMENT_ERROR;
1236
0
        } else {
1237
0
            NFRuleSet *rs = findRuleSet(ruleSetName, status);
1238
0
            if (rs) {
1239
0
                format(number, *rs, toAppendTo, status);
1240
0
            }
1241
0
        }
1242
0
    }
1243
0
    return toAppendTo;
1244
0
}
1245
1246
void
1247
RuleBasedNumberFormat::format(double number,
1248
                              NFRuleSet& rs,
1249
                              UnicodeString& toAppendTo,
1250
                              UErrorCode& status) const
1251
0
{
1252
0
    int32_t startPos = toAppendTo.length();
1253
0
    if (getRoundingMode() != DecimalFormat::ERoundingMode::kRoundUnnecessary && !uprv_isNaN(number) && !uprv_isInfinite(number)) {
1254
0
        DecimalQuantity digitList;
1255
0
        digitList.setToDouble(number);
1256
0
        digitList.roundToMagnitude(
1257
0
                -getMaximumFractionDigits(),
1258
0
                static_cast<UNumberFormatRoundingMode>(getRoundingMode()),
1259
0
                status);
1260
0
        number = digitList.toDouble();
1261
0
    }
1262
0
    rs.format(number, toAppendTo, toAppendTo.length(), 0, status);
1263
0
    adjustForCapitalizationContext(startPos, toAppendTo, status);
1264
0
}
1265
1266
/**
1267
 * Bottleneck through which all the public format() methods
1268
 * that take a long pass. By the time we get here, we know
1269
 * which rule set we're using to do the formatting.
1270
 * @param number The number to format
1271
 * @param ruleSet The rule set to use to format the number
1272
 * @return The text that resulted from formatting the number
1273
 */
1274
UnicodeString&
1275
RuleBasedNumberFormat::format(int64_t number, NFRuleSet *ruleSet, UnicodeString& toAppendTo, UErrorCode& status) const
1276
0
{
1277
    // all API format() routines that take a double vector through
1278
    // here.  We have these two identical functions-- one taking a
1279
    // double and one taking a long-- the couple digits of precision
1280
    // that long has but double doesn't (both types are 8 bytes long,
1281
    // but double has to borrow some of the mantissa bits to hold
1282
    // the exponent).
1283
    // Create an empty string buffer where the result will
1284
    // be built, and pass it to the rule set (along with an insertion
1285
    // position of 0 and the number being formatted) to the rule set
1286
    // for formatting
1287
1288
0
    if (U_SUCCESS(status)) {
1289
0
        if (number == U_INT64_MIN) {
1290
            // We can't handle this value right now. Provide an accurate default value.
1291
1292
            // TODO this section should probably be optimized. The DecimalFormat is shared in ICU4J.
1293
0
            NumberFormat *decimalFormat = NumberFormat::createInstance(locale, UNUM_DECIMAL, status);
1294
0
            if (decimalFormat == nullptr) {
1295
0
                return toAppendTo;
1296
0
            }
1297
0
            Formattable f;
1298
0
            FieldPosition pos(FieldPosition::DONT_CARE);
1299
0
            DecimalQuantity *decimalQuantity = new DecimalQuantity();
1300
0
            if (decimalQuantity == nullptr) {
1301
0
                status = U_MEMORY_ALLOCATION_ERROR;
1302
0
                delete decimalFormat;
1303
0
                return toAppendTo;
1304
0
            }
1305
0
            decimalQuantity->setToLong(number);
1306
0
            f.adoptDecimalQuantity(decimalQuantity); // f now owns decimalQuantity.
1307
0
            decimalFormat->format(f, toAppendTo, pos, status);
1308
0
            delete decimalFormat;
1309
0
        }
1310
0
        else {
1311
0
            int32_t startPos = toAppendTo.length();
1312
0
            ruleSet->format(number, toAppendTo, toAppendTo.length(), 0, status);
1313
0
            adjustForCapitalizationContext(startPos, toAppendTo, status);
1314
0
        }
1315
0
    }
1316
0
    return toAppendTo;
1317
0
}
1318
1319
UnicodeString&
1320
RuleBasedNumberFormat::adjustForCapitalizationContext(int32_t startPos,
1321
                                                      UnicodeString& currentResult,
1322
                                                      UErrorCode& status) const
1323
0
{
1324
0
#if !UCONFIG_NO_BREAK_ITERATION
1325
0
    UDisplayContext capitalizationContext = getContext(UDISPCTX_TYPE_CAPITALIZATION, status);
1326
0
    if (capitalizationContext != UDISPCTX_CAPITALIZATION_NONE && startPos == 0 && currentResult.length() > 0) {
1327
        // capitalize currentResult according to context
1328
0
        UChar32 ch = currentResult.char32At(0);
1329
0
        if (u_islower(ch) && U_SUCCESS(status) && capitalizationBrkIter != NULL &&
1330
0
              ( capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
1331
0
                (capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && capitalizationForUIListMenu) ||
1332
0
                (capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_STANDALONE && capitalizationForStandAlone)) ) {
1333
            // titlecase first word of currentResult, here use sentence iterator unlike current implementations
1334
            // in LocaleDisplayNamesImpl::adjustForUsageAndContext and RelativeDateFormat::format
1335
0
            currentResult.toTitle(capitalizationBrkIter, locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
1336
0
        }
1337
0
    }
1338
0
#endif
1339
0
    return currentResult;
1340
0
}
1341
1342
1343
void
1344
RuleBasedNumberFormat::parse(const UnicodeString& text,
1345
                             Formattable& result,
1346
                             ParsePosition& parsePosition) const
1347
0
{
1348
0
    if (!fRuleSets) {
1349
0
        parsePosition.setErrorIndex(0);
1350
0
        return;
1351
0
    }
1352
1353
0
    UnicodeString workingText(text, parsePosition.getIndex());
1354
0
    ParsePosition workingPos(0);
1355
1356
0
    ParsePosition high_pp(0);
1357
0
    Formattable high_result;
1358
1359
0
    for (NFRuleSet** p = fRuleSets; *p; ++p) {
1360
0
        NFRuleSet *rp = *p;
1361
0
        if (rp->isPublic() && rp->isParseable()) {
1362
0
            ParsePosition working_pp(0);
1363
0
            Formattable working_result;
1364
1365
0
            rp->parse(workingText, working_pp, kMaxDouble, 0, working_result);
1366
0
            if (working_pp.getIndex() > high_pp.getIndex()) {
1367
0
                high_pp = working_pp;
1368
0
                high_result = working_result;
1369
1370
0
                if (high_pp.getIndex() == workingText.length()) {
1371
0
                    break;
1372
0
                }
1373
0
            }
1374
0
        }
1375
0
    }
1376
1377
0
    int32_t startIndex = parsePosition.getIndex();
1378
0
    parsePosition.setIndex(startIndex + high_pp.getIndex());
1379
0
    if (high_pp.getIndex() > 0) {
1380
0
        parsePosition.setErrorIndex(-1);
1381
0
    } else {
1382
0
        int32_t errorIndex = (high_pp.getErrorIndex()>0)? high_pp.getErrorIndex(): 0;
1383
0
        parsePosition.setErrorIndex(startIndex + errorIndex);
1384
0
    }
1385
0
    result = high_result;
1386
0
    if (result.getType() == Formattable::kDouble) {
1387
0
        double d = result.getDouble();
1388
0
        if (!uprv_isNaN(d) && d == uprv_trunc(d) && INT32_MIN <= d && d <= INT32_MAX) {
1389
            // Note: casting a double to an int when the double is too large or small
1390
            //       to fit the destination is undefined behavior. The explicit range checks,
1391
            //       above, are required. Just casting and checking the result value is undefined.
1392
0
            result.setLong(static_cast<int32_t>(d));
1393
0
        }
1394
0
    }
1395
0
}
1396
1397
#if !UCONFIG_NO_COLLATION
1398
1399
void
1400
RuleBasedNumberFormat::setLenient(UBool enabled)
1401
0
{
1402
0
    lenient = enabled;
1403
0
    if (!enabled && collator) {
1404
0
        delete collator;
1405
0
        collator = NULL;
1406
0
    }
1407
0
}
1408
1409
#endif
1410
1411
void 
1412
0
RuleBasedNumberFormat::setDefaultRuleSet(const UnicodeString& ruleSetName, UErrorCode& status) {
1413
0
    if (U_SUCCESS(status)) {
1414
0
        if (ruleSetName.isEmpty()) {
1415
0
          if (localizations) {
1416
0
              UnicodeString name(TRUE, localizations->getRuleSetName(0), -1);
1417
0
              defaultRuleSet = findRuleSet(name, status);
1418
0
          } else {
1419
0
            initDefaultRuleSet();
1420
0
          }
1421
0
        } else if (ruleSetName.startsWith(UNICODE_STRING_SIMPLE("%%"))) {
1422
0
            status = U_ILLEGAL_ARGUMENT_ERROR;
1423
0
        } else {
1424
0
            NFRuleSet* result = findRuleSet(ruleSetName, status);
1425
0
            if (result != NULL) {
1426
0
                defaultRuleSet = result;
1427
0
            }
1428
0
        }
1429
0
    }
1430
0
}
1431
1432
UnicodeString
1433
0
RuleBasedNumberFormat::getDefaultRuleSetName() const {
1434
0
    UnicodeString result;
1435
0
    if (defaultRuleSet && defaultRuleSet->isPublic()) {
1436
0
        defaultRuleSet->getName(result);
1437
0
    } else {
1438
0
        result.setToBogus();
1439
0
    }
1440
0
    return result;
1441
0
}
1442
1443
void 
1444
RuleBasedNumberFormat::initDefaultRuleSet()
1445
0
{
1446
0
    defaultRuleSet = NULL;
1447
0
    if (!fRuleSets) {
1448
0
        return;
1449
0
    }
1450
1451
0
    const UnicodeString spellout(UNICODE_STRING_SIMPLE("%spellout-numbering"));
1452
0
    const UnicodeString ordinal(UNICODE_STRING_SIMPLE("%digits-ordinal"));
1453
0
    const UnicodeString duration(UNICODE_STRING_SIMPLE("%duration"));
1454
1455
0
    NFRuleSet**p = &fRuleSets[0];
1456
0
    while (*p) {
1457
0
        if ((*p)->isNamed(spellout) || (*p)->isNamed(ordinal) || (*p)->isNamed(duration)) {
1458
0
            defaultRuleSet = *p;
1459
0
            return;
1460
0
        } else {
1461
0
            ++p;
1462
0
        }
1463
0
    }
1464
1465
0
    defaultRuleSet = *--p;
1466
0
    if (!defaultRuleSet->isPublic()) {
1467
0
        while (p != fRuleSets) {
1468
0
            if ((*--p)->isPublic()) {
1469
0
                defaultRuleSet = *p;
1470
0
                break;
1471
0
            }
1472
0
        }
1473
0
    }
1474
0
}
1475
1476
1477
void
1478
RuleBasedNumberFormat::init(const UnicodeString& rules, LocalizationInfo* localizationInfos,
1479
                            UParseError& pErr, UErrorCode& status)
1480
0
{
1481
    // TODO: implement UParseError
1482
0
    uprv_memset(&pErr, 0, sizeof(UParseError));
1483
    // Note: this can leave ruleSets == NULL, so remaining code should check
1484
0
    if (U_FAILURE(status)) {
1485
0
        return;
1486
0
    }
1487
1488
0
    initializeDecimalFormatSymbols(status);
1489
0
    initializeDefaultInfinityRule(status);
1490
0
    initializeDefaultNaNRule(status);
1491
0
    if (U_FAILURE(status)) {
1492
0
        return;
1493
0
    }
1494
1495
0
    this->localizations = localizationInfos == NULL ? NULL : localizationInfos->ref();
1496
1497
0
    UnicodeString description(rules);
1498
0
    if (!description.length()) {
1499
0
        status = U_MEMORY_ALLOCATION_ERROR;
1500
0
        return;
1501
0
    }
1502
1503
    // start by stripping the trailing whitespace from all the rules
1504
    // (this is all the whitespace following each semicolon in the
1505
    // description).  This allows us to look for rule-set boundaries
1506
    // by searching for ";%" without having to worry about whitespace
1507
    // between the ; and the %
1508
0
    stripWhitespace(description);
1509
1510
    // check to see if there's a set of lenient-parse rules.  If there
1511
    // is, pull them out into our temporary holding place for them,
1512
    // and delete them from the description before the real desciption-
1513
    // parsing code sees them
1514
0
    int32_t lp = description.indexOf(gLenientParse, -1, 0);
1515
0
    if (lp != -1) {
1516
        // we've got to make sure we're not in the middle of a rule
1517
        // (where "%%lenient-parse" would actually get treated as
1518
        // rule text)
1519
0
        if (lp == 0 || description.charAt(lp - 1) == gSemiColon) {
1520
            // locate the beginning and end of the actual collation
1521
            // rules (there may be whitespace between the name and
1522
            // the first token in the description)
1523
0
            int lpEnd = description.indexOf(gSemiPercent, 2, lp);
1524
1525
0
            if (lpEnd == -1) {
1526
0
                lpEnd = description.length() - 1;
1527
0
            }
1528
0
            int lpStart = lp + u_strlen(gLenientParse);
1529
0
            while (PatternProps::isWhiteSpace(description.charAt(lpStart))) {
1530
0
                ++lpStart;
1531
0
            }
1532
1533
            // copy out the lenient-parse rules and delete them
1534
            // from the description
1535
0
            lenientParseRules = new UnicodeString();
1536
            /* test for NULL */
1537
0
            if (lenientParseRules == nullptr) {
1538
0
                status = U_MEMORY_ALLOCATION_ERROR;
1539
0
                return;
1540
0
            }
1541
0
            lenientParseRules->setTo(description, lpStart, lpEnd - lpStart);
1542
1543
0
            description.remove(lp, lpEnd + 1 - lp);
1544
0
        }
1545
0
    }
1546
1547
    // pre-flight parsing the description and count the number of
1548
    // rule sets (";%" marks the end of one rule set and the beginning
1549
    // of the next)
1550
0
    numRuleSets = 0;
1551
0
    for (int32_t p = description.indexOf(gSemiPercent, 2, 0); p != -1; p = description.indexOf(gSemiPercent, 2, p)) {
1552
0
        ++numRuleSets;
1553
0
        ++p;
1554
0
    }
1555
0
    ++numRuleSets;
1556
1557
    // our rule list is an array of the appropriate size
1558
0
    fRuleSets = (NFRuleSet **)uprv_malloc((numRuleSets + 1) * sizeof(NFRuleSet *));
1559
    /* test for NULL */
1560
0
    if (fRuleSets == 0) {
1561
0
        status = U_MEMORY_ALLOCATION_ERROR;
1562
0
        return;
1563
0
    }
1564
1565
0
    for (int i = 0; i <= numRuleSets; ++i) {
1566
0
        fRuleSets[i] = NULL;
1567
0
    }
1568
1569
    // divide up the descriptions into individual rule-set descriptions
1570
    // and store them in a temporary array.  At each step, we also
1571
    // new up a rule set, but all this does is initialize its name
1572
    // and remove it from its description.  We can't actually parse
1573
    // the rest of the descriptions and finish initializing everything
1574
    // because we have to know the names and locations of all the rule
1575
    // sets before we can actually set everything up
1576
0
    if(!numRuleSets) {
1577
0
        status = U_ILLEGAL_ARGUMENT_ERROR;
1578
0
        return;
1579
0
    }
1580
1581
0
    ruleSetDescriptions = new UnicodeString[numRuleSets];
1582
0
    if (ruleSetDescriptions == nullptr) {
1583
0
        status = U_MEMORY_ALLOCATION_ERROR;
1584
0
        return;
1585
0
    }
1586
1587
0
    {
1588
0
        int curRuleSet = 0;
1589
0
        int32_t start = 0;
1590
0
        for (int32_t p = description.indexOf(gSemiPercent, 2, 0); p != -1; p = description.indexOf(gSemiPercent, 2, start)) {
1591
0
            ruleSetDescriptions[curRuleSet].setTo(description, start, p + 1 - start);
1592
0
            fRuleSets[curRuleSet] = new NFRuleSet(this, ruleSetDescriptions, curRuleSet, status);
1593
0
            if (fRuleSets[curRuleSet] == nullptr) {
1594
0
                status = U_MEMORY_ALLOCATION_ERROR;
1595
0
                return;
1596
0
            }
1597
0
            ++curRuleSet;
1598
0
            start = p + 1;
1599
0
        }
1600
0
        ruleSetDescriptions[curRuleSet].setTo(description, start, description.length() - start);
1601
0
        fRuleSets[curRuleSet] = new NFRuleSet(this, ruleSetDescriptions, curRuleSet, status);
1602
0
        if (fRuleSets[curRuleSet] == nullptr) {
1603
0
            status = U_MEMORY_ALLOCATION_ERROR;
1604
0
            return;
1605
0
        }
1606
0
    }
1607
1608
    // now we can take note of the formatter's default rule set, which
1609
    // is the last public rule set in the description (it's the last
1610
    // rather than the first so that a user can create a new formatter
1611
    // from an existing formatter and change its default behavior just
1612
    // by appending more rule sets to the end)
1613
1614
    // {dlf} Initialization of a fraction rule set requires the default rule
1615
    // set to be known.  For purposes of initialization, this is always the 
1616
    // last public rule set, no matter what the localization data says.
1617
0
    initDefaultRuleSet();
1618
1619
    // finally, we can go back through the temporary descriptions
1620
    // list and finish setting up the substructure (and we throw
1621
    // away the temporary descriptions as we go)
1622
0
    {
1623
0
        for (int i = 0; i < numRuleSets; i++) {
1624
0
            fRuleSets[i]->parseRules(ruleSetDescriptions[i], status);
1625
0
        }
1626
0
    }
1627
1628
    // Now that the rules are initialized, the 'real' default rule
1629
    // set can be adjusted by the localization data.
1630
1631
    // The C code keeps the localization array as is, rather than building
1632
    // a separate array of the public rule set names, so we have less work
1633
    // to do here-- but we still need to check the names.
1634
    
1635
0
    if (localizationInfos) {
1636
        // confirm the names, if any aren't in the rules, that's an error
1637
        // it is ok if the rules contain public rule sets that are not in this list
1638
0
        for (int32_t i = 0; i < localizationInfos->getNumberOfRuleSets(); ++i) {
1639
0
            UnicodeString name(TRUE, localizationInfos->getRuleSetName(i), -1);
1640
0
            NFRuleSet* rs = findRuleSet(name, status);
1641
0
            if (rs == NULL) {
1642
0
                break; // error
1643
0
            }
1644
0
            if (i == 0) {
1645
0
                defaultRuleSet = rs;
1646
0
            }
1647
0
        }
1648
0
    } else {
1649
0
        defaultRuleSet = getDefaultRuleSet();
1650
0
    }
1651
0
    originalDescription = rules;
1652
0
}
1653
1654
// override the NumberFormat implementation in order to
1655
// lazily initialize relevant items
1656
void
1657
RuleBasedNumberFormat::setContext(UDisplayContext value, UErrorCode& status)
1658
0
{
1659
0
    NumberFormat::setContext(value, status);
1660
0
    if (U_SUCCESS(status)) {
1661
0
      if (!capitalizationInfoSet &&
1662
0
              (value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE)) {
1663
0
          initCapitalizationContextInfo(locale);
1664
0
          capitalizationInfoSet = TRUE;
1665
0
        }
1666
0
#if !UCONFIG_NO_BREAK_ITERATION
1667
0
        if ( capitalizationBrkIter == NULL && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
1668
0
                (value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && capitalizationForUIListMenu) ||
1669
0
                (value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE && capitalizationForStandAlone)) ) {
1670
0
            status = U_ZERO_ERROR;
1671
0
            capitalizationBrkIter = BreakIterator::createSentenceInstance(locale, status);
1672
0
            if (U_FAILURE(status)) {
1673
0
                delete capitalizationBrkIter;
1674
0
                capitalizationBrkIter = NULL;
1675
0
            }
1676
0
        }
1677
0
#endif
1678
0
    }
1679
0
}
1680
1681
void
1682
RuleBasedNumberFormat::initCapitalizationContextInfo(const Locale& thelocale)
1683
0
{
1684
0
#if !UCONFIG_NO_BREAK_ITERATION
1685
0
    const char * localeID = (thelocale != NULL)? thelocale.getBaseName(): NULL;
1686
0
    UErrorCode status = U_ZERO_ERROR;
1687
0
    UResourceBundle *rb = ures_open(NULL, localeID, &status);
1688
0
    rb = ures_getByKeyWithFallback(rb, "contextTransforms", rb, &status);
1689
0
    rb = ures_getByKeyWithFallback(rb, "number-spellout", rb, &status);
1690
0
    if (U_SUCCESS(status) && rb != NULL) {
1691
0
        int32_t len = 0;
1692
0
        const int32_t * intVector = ures_getIntVector(rb, &len, &status);
1693
0
        if (U_SUCCESS(status) && intVector != NULL && len >= 2) {
1694
0
            capitalizationForUIListMenu = static_cast<UBool>(intVector[0]);
1695
0
            capitalizationForStandAlone = static_cast<UBool>(intVector[1]);
1696
0
        }
1697
0
    }
1698
0
    ures_close(rb);
1699
0
#endif
1700
0
}
1701
1702
void
1703
RuleBasedNumberFormat::stripWhitespace(UnicodeString& description)
1704
0
{
1705
    // iterate through the characters...
1706
0
    UnicodeString result;
1707
1708
0
    int start = 0;
1709
0
    while (start != -1 && start < description.length()) {
1710
        // seek to the first non-whitespace character...
1711
0
        while (start < description.length()
1712
0
            && PatternProps::isWhiteSpace(description.charAt(start))) {
1713
0
            ++start;
1714
0
        }
1715
1716
        // locate the next semicolon in the text and copy the text from
1717
        // our current position up to that semicolon into the result
1718
0
        int32_t p = description.indexOf(gSemiColon, start);
1719
0
        if (p == -1) {
1720
            // or if we don't find a semicolon, just copy the rest of
1721
            // the string into the result
1722
0
            result.append(description, start, description.length() - start);
1723
0
            start = -1;
1724
0
        }
1725
0
        else if (p < description.length()) {
1726
0
            result.append(description, start, p + 1 - start);
1727
0
            start = p + 1;
1728
0
        }
1729
1730
        // when we get here, we've seeked off the end of the string, and
1731
        // we terminate the loop (we continue until *start* is -1 rather
1732
        // than until *p* is -1, because otherwise we'd miss the last
1733
        // rule in the description)
1734
0
        else {
1735
0
            start = -1;
1736
0
        }
1737
0
    }
1738
1739
0
    description.setTo(result);
1740
0
}
1741
1742
1743
void
1744
RuleBasedNumberFormat::dispose()
1745
0
{
1746
0
    if (fRuleSets) {
1747
0
        for (NFRuleSet** p = fRuleSets; *p; ++p) {
1748
0
            delete *p;
1749
0
        }
1750
0
        uprv_free(fRuleSets);
1751
0
        fRuleSets = NULL;
1752
0
    }
1753
1754
0
    if (ruleSetDescriptions) {
1755
0
        delete [] ruleSetDescriptions;
1756
0
        ruleSetDescriptions = NULL;
1757
0
    }
1758
1759
0
#if !UCONFIG_NO_COLLATION
1760
0
    delete collator;
1761
0
#endif
1762
0
    collator = NULL;
1763
1764
0
    delete decimalFormatSymbols;
1765
0
    decimalFormatSymbols = NULL;
1766
1767
0
    delete defaultInfinityRule;
1768
0
    defaultInfinityRule = NULL;
1769
1770
0
    delete defaultNaNRule;
1771
0
    defaultNaNRule = NULL;
1772
1773
0
    delete lenientParseRules;
1774
0
    lenientParseRules = NULL;
1775
1776
0
#if !UCONFIG_NO_BREAK_ITERATION
1777
0
    delete capitalizationBrkIter;
1778
0
    capitalizationBrkIter = NULL;
1779
0
#endif
1780
1781
0
    if (localizations) {
1782
0
        localizations = localizations->unref();
1783
0
    }
1784
0
}
1785
1786
1787
//-----------------------------------------------------------------------
1788
// package-internal API
1789
//-----------------------------------------------------------------------
1790
1791
/**
1792
 * Returns the collator to use for lenient parsing.  The collator is lazily created:
1793
 * this function creates it the first time it's called.
1794
 * @return The collator to use for lenient parsing, or null if lenient parsing
1795
 * is turned off.
1796
*/
1797
const RuleBasedCollator*
1798
RuleBasedNumberFormat::getCollator() const
1799
0
{
1800
0
#if !UCONFIG_NO_COLLATION
1801
0
    if (!fRuleSets) {
1802
0
        return NULL;
1803
0
    }
1804
1805
    // lazy-evaluate the collator
1806
0
    if (collator == NULL && lenient) {
1807
        // create a default collator based on the formatter's locale,
1808
        // then pull out that collator's rules, append any additional
1809
        // rules specified in the description, and create a _new_
1810
        // collator based on the combination of those rules
1811
1812
0
        UErrorCode status = U_ZERO_ERROR;
1813
1814
0
        Collator* temp = Collator::createInstance(locale, status);
1815
0
        RuleBasedCollator* newCollator;
1816
0
        if (U_SUCCESS(status) && (newCollator = dynamic_cast<RuleBasedCollator*>(temp)) != NULL) {
1817
0
            if (lenientParseRules) {
1818
0
                UnicodeString rules(newCollator->getRules());
1819
0
                rules.append(*lenientParseRules);
1820
1821
0
                newCollator = new RuleBasedCollator(rules, status);
1822
                // Exit if newCollator could not be created.
1823
0
                if (newCollator == NULL) {
1824
0
                    return NULL;
1825
0
                }
1826
0
            } else {
1827
0
                temp = NULL;
1828
0
            }
1829
0
            if (U_SUCCESS(status)) {
1830
0
                newCollator->setAttribute(UCOL_DECOMPOSITION_MODE, UCOL_ON, status);
1831
                // cast away const
1832
0
                ((RuleBasedNumberFormat*)this)->collator = newCollator;
1833
0
            } else {
1834
0
                delete newCollator;
1835
0
            }
1836
0
        }
1837
0
        delete temp;
1838
0
    }
1839
0
#endif
1840
1841
    // if lenient-parse mode is off, this will be null
1842
    // (see setLenientParseMode())
1843
0
    return collator;
1844
0
}
1845
1846
1847
DecimalFormatSymbols*
1848
RuleBasedNumberFormat::initializeDecimalFormatSymbols(UErrorCode &status)
1849
0
{
1850
    // lazy-evaluate the DecimalFormatSymbols object.  This object
1851
    // is shared by all DecimalFormat instances belonging to this
1852
    // formatter
1853
0
    if (decimalFormatSymbols == nullptr) {
1854
0
        LocalPointer<DecimalFormatSymbols> temp(new DecimalFormatSymbols(locale, status), status);
1855
0
        if (U_SUCCESS(status)) {
1856
0
            decimalFormatSymbols = temp.orphan();
1857
0
        }
1858
0
    }
1859
0
    return decimalFormatSymbols;
1860
0
}
1861
1862
/**
1863
 * Returns the DecimalFormatSymbols object that should be used by all DecimalFormat
1864
 * instances owned by this formatter.
1865
*/
1866
const DecimalFormatSymbols*
1867
RuleBasedNumberFormat::getDecimalFormatSymbols() const
1868
0
{
1869
0
    return decimalFormatSymbols;
1870
0
}
1871
1872
NFRule*
1873
RuleBasedNumberFormat::initializeDefaultInfinityRule(UErrorCode &status)
1874
0
{
1875
0
    if (U_FAILURE(status)) {
1876
0
        return nullptr;
1877
0
    }
1878
0
    if (defaultInfinityRule == NULL) {
1879
0
        UnicodeString rule(UNICODE_STRING_SIMPLE("Inf: "));
1880
0
        rule.append(getDecimalFormatSymbols()->getSymbol(DecimalFormatSymbols::kInfinitySymbol));
1881
0
        LocalPointer<NFRule> temp(new NFRule(this, rule, status), status);
1882
0
        if (U_SUCCESS(status)) {
1883
0
            defaultInfinityRule = temp.orphan();
1884
0
        }
1885
0
    }
1886
0
    return defaultInfinityRule;
1887
0
}
1888
1889
const NFRule*
1890
RuleBasedNumberFormat::getDefaultInfinityRule() const
1891
0
{
1892
0
    return defaultInfinityRule;
1893
0
}
1894
1895
NFRule*
1896
RuleBasedNumberFormat::initializeDefaultNaNRule(UErrorCode &status)
1897
0
{
1898
0
    if (U_FAILURE(status)) {
1899
0
        return nullptr;
1900
0
    }
1901
0
    if (defaultNaNRule == nullptr) {
1902
0
        UnicodeString rule(UNICODE_STRING_SIMPLE("NaN: "));
1903
0
        rule.append(getDecimalFormatSymbols()->getSymbol(DecimalFormatSymbols::kNaNSymbol));
1904
0
        LocalPointer<NFRule> temp(new NFRule(this, rule, status), status);
1905
0
        if (U_SUCCESS(status)) {
1906
0
            defaultNaNRule = temp.orphan();
1907
0
        }
1908
0
    }
1909
0
    return defaultNaNRule;
1910
0
}
1911
1912
const NFRule*
1913
RuleBasedNumberFormat::getDefaultNaNRule() const
1914
0
{
1915
0
    return defaultNaNRule;
1916
0
}
1917
1918
// De-owning the current localized symbols and adopt the new symbols.
1919
void
1920
RuleBasedNumberFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsToAdopt)
1921
0
{
1922
0
    if (symbolsToAdopt == NULL) {
1923
0
        return; // do not allow caller to set decimalFormatSymbols to NULL
1924
0
    }
1925
1926
0
    if (decimalFormatSymbols != NULL) {
1927
0
        delete decimalFormatSymbols;
1928
0
    }
1929
1930
0
    decimalFormatSymbols = symbolsToAdopt;
1931
1932
0
    {
1933
        // Apply the new decimalFormatSymbols by reparsing the rulesets
1934
0
        UErrorCode status = U_ZERO_ERROR;
1935
1936
0
        delete defaultInfinityRule;
1937
0
        defaultInfinityRule = NULL;
1938
0
        initializeDefaultInfinityRule(status); // Reset with the new DecimalFormatSymbols
1939
1940
0
        delete defaultNaNRule;
1941
0
        defaultNaNRule = NULL;
1942
0
        initializeDefaultNaNRule(status); // Reset with the new DecimalFormatSymbols
1943
1944
0
        if (fRuleSets) {
1945
0
            for (int32_t i = 0; i < numRuleSets; i++) {
1946
0
                fRuleSets[i]->setDecimalFormatSymbols(*symbolsToAdopt, status);
1947
0
            }
1948
0
        }
1949
0
    }
1950
0
}
1951
1952
// Setting the symbols is equivalent to adopting a newly created localized symbols.
1953
void
1954
RuleBasedNumberFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols)
1955
0
{
1956
0
    adoptDecimalFormatSymbols(new DecimalFormatSymbols(symbols));
1957
0
}
1958
1959
PluralFormat *
1960
RuleBasedNumberFormat::createPluralFormat(UPluralType pluralType,
1961
                                          const UnicodeString &pattern,
1962
                                          UErrorCode& status) const
1963
0
{
1964
0
    auto *pf = new PluralFormat(locale, pluralType, pattern, status);
1965
0
    if (pf == nullptr) {
1966
0
        status = U_MEMORY_ALLOCATION_ERROR;
1967
0
    }
1968
0
    return pf;
1969
0
}
1970
1971
/**
1972
 * Get the rounding mode.
1973
 * @return A rounding mode
1974
 */
1975
0
DecimalFormat::ERoundingMode RuleBasedNumberFormat::getRoundingMode() const {
1976
0
    return fRoundingMode;
1977
0
}
1978
1979
/**
1980
 * Set the rounding mode.  This has no effect unless the rounding
1981
 * increment is greater than zero.
1982
 * @param roundingMode A rounding mode
1983
 */
1984
0
void RuleBasedNumberFormat::setRoundingMode(DecimalFormat::ERoundingMode roundingMode) {
1985
0
    fRoundingMode = roundingMode;
1986
0
}
1987
1988
U_NAMESPACE_END
1989
1990
/* U_HAVE_RBNF */
1991
#endif