Coverage Report

Created: 2026-01-22 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/icu/icu4c/source/i18n/msgfmt.cpp
Line
Count
Source
1
// © 2016 and later: Unicode, Inc. and others.
2
// License & terms of use: http://www.unicode.org/copyright.html
3
/********************************************************************
4
 * COPYRIGHT:
5
 * Copyright (c) 1997-2015, International Business Machines Corporation and
6
 * others. All Rights Reserved.
7
 ********************************************************************
8
 *
9
 * File MSGFMT.CPP
10
 *
11
 * Modification History:
12
 *
13
 *   Date        Name        Description
14
 *   02/19/97    aliu        Converted from java.
15
 *   03/20/97    helena      Finished first cut of implementation.
16
 *   04/10/97    aliu        Made to work on AIX.  Added stoi to replace wtoi.
17
 *   06/11/97    helena      Fixed addPattern to take the pattern correctly.
18
 *   06/17/97    helena      Fixed the getPattern to return the correct pattern.
19
 *   07/09/97    helena      Made ParsePosition into a class.
20
 *   02/22/99    stephen     Removed character literals for EBCDIC safety
21
 *   11/01/09    kirtig      Added SelectFormat
22
 ********************************************************************/
23
24
#include "unicode/utypes.h"
25
26
#if !UCONFIG_NO_FORMATTING
27
28
#include "unicode/appendable.h"
29
#include "unicode/choicfmt.h"
30
#include "unicode/datefmt.h"
31
#include "unicode/decimfmt.h"
32
#include "unicode/localpointer.h"
33
#include "unicode/msgfmt.h"
34
#include "unicode/numberformatter.h"
35
#include "unicode/plurfmt.h"
36
#include "unicode/rbnf.h"
37
#include "unicode/selfmt.h"
38
#include "unicode/smpdtfmt.h"
39
#include "unicode/umsg.h"
40
#include "unicode/ustring.h"
41
#include "cmemory.h"
42
#include "patternprops.h"
43
#include "messageimpl.h"
44
#include "msgfmt_impl.h"
45
#include "plurrule_impl.h"
46
#include "uassert.h"
47
#include "uelement.h"
48
#include "uhash.h"
49
#include "ustrfmt.h"
50
#include "util.h"
51
#include "uvector.h"
52
#include "number_decimalquantity.h"
53
54
// *****************************************************************************
55
// class MessageFormat
56
// *****************************************************************************
57
58
0
#define SINGLE_QUOTE      ((char16_t)0x0027)
59
#define COMMA             ((char16_t)0x002C)
60
0
#define LEFT_CURLY_BRACE  ((char16_t)0x007B)
61
0
#define RIGHT_CURLY_BRACE ((char16_t)0x007D)
62
63
//---------------------------------------
64
// static data
65
66
static const char16_t ID_NUMBER[]    = {
67
    0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0  /* "number" */
68
};
69
static const char16_t ID_DATE[]      = {
70
    0x64, 0x61, 0x74, 0x65, 0              /* "date" */
71
};
72
static const char16_t ID_TIME[]      = {
73
    0x74, 0x69, 0x6D, 0x65, 0              /* "time" */
74
};
75
static const char16_t ID_SPELLOUT[]  = {
76
    0x73, 0x70, 0x65, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0 /* "spellout" */
77
};
78
static const char16_t ID_ORDINAL[]   = {
79
    0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0 /* "ordinal" */
80
};
81
static const char16_t ID_DURATION[]  = {
82
    0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0 /* "duration" */
83
};
84
85
// MessageFormat Type List  Number, Date, Time or Choice
86
static const char16_t * const TYPE_IDS[] = {
87
    ID_NUMBER,
88
    ID_DATE,
89
    ID_TIME,
90
    ID_SPELLOUT,
91
    ID_ORDINAL,
92
    ID_DURATION,
93
    nullptr,
94
};
95
96
static const char16_t ID_EMPTY[]     = {
97
    0 /* empty string, used for default so that null can mark end of list */
98
};
99
static const char16_t ID_CURRENCY[]  = {
100
    0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x63, 0x79, 0  /* "currency" */
101
};
102
static const char16_t ID_PERCENT[]   = {
103
    0x70, 0x65, 0x72, 0x63, 0x65, 0x6E, 0x74, 0        /* "percent" */
104
};
105
static const char16_t ID_INTEGER[]   = {
106
    0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0        /* "integer" */
107
};
108
109
// NumberFormat modifier list, default, currency, percent or integer
110
static const char16_t * const NUMBER_STYLE_IDS[] = {
111
    ID_EMPTY,
112
    ID_CURRENCY,
113
    ID_PERCENT,
114
    ID_INTEGER,
115
    nullptr,
116
};
117
118
static const char16_t ID_SHORT[]     = {
119
    0x73, 0x68, 0x6F, 0x72, 0x74, 0        /* "short" */
120
};
121
static const char16_t ID_MEDIUM[]    = {
122
    0x6D, 0x65, 0x64, 0x69, 0x75, 0x6D, 0  /* "medium" */
123
};
124
static const char16_t ID_LONG[]      = {
125
    0x6C, 0x6F, 0x6E, 0x67, 0              /* "long" */
126
};
127
static const char16_t ID_FULL[]      = {
128
    0x66, 0x75, 0x6C, 0x6C, 0              /* "full" */
129
};
130
131
// DateFormat modifier list, default, short, medium, long or full
132
static const char16_t * const DATE_STYLE_IDS[] = {
133
    ID_EMPTY,
134
    ID_SHORT,
135
    ID_MEDIUM,
136
    ID_LONG,
137
    ID_FULL,
138
    nullptr,
139
};
140
141
static const icu::DateFormat::EStyle DATE_STYLES[] = {
142
    icu::DateFormat::kDefault,
143
    icu::DateFormat::kShort,
144
    icu::DateFormat::kMedium,
145
    icu::DateFormat::kLong,
146
    icu::DateFormat::kFull,
147
};
148
149
static const int32_t DEFAULT_INITIAL_CAPACITY = 10;
150
151
static const char16_t NULL_STRING[] = {
152
    0x6E, 0x75, 0x6C, 0x6C, 0  // "null"
153
};
154
155
static const char16_t OTHER_STRING[] = {
156
    0x6F, 0x74, 0x68, 0x65, 0x72, 0  // "other"
157
};
158
159
U_CDECL_BEGIN
160
static UBool U_CALLCONV equalFormatsForHash(const UHashTok key1,
161
0
                                            const UHashTok key2) {
162
0
    return icu::MessageFormat::equalFormats(key1.pointer, key2.pointer);
163
0
}
164
165
U_CDECL_END
166
167
U_NAMESPACE_BEGIN
168
169
// -------------------------------------
170
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MessageFormat)
171
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(FormatNameEnumeration)
172
173
//--------------------------------------------------------------------
174
175
/**
176
 * Convert an integer value to a string and append the result to
177
 * the given UnicodeString.
178
 */
179
0
static UnicodeString& itos(int32_t i, UnicodeString& appendTo) {
180
0
    char16_t temp[16];
181
0
    uprv_itou(temp,16,i,10,0); // 10 == radix
182
0
    appendTo.append(temp, -1);
183
0
    return appendTo;
184
0
}
185
186
187
// AppendableWrapper: encapsulates the result of formatting, keeping track
188
// of the string and its length.
189
class AppendableWrapper : public UMemory {
190
public:
191
0
    AppendableWrapper(Appendable& appendable) : app(appendable), len(0) {
192
0
    }
193
0
    void append(const UnicodeString& s) {
194
0
        app.appendString(s.getBuffer(), s.length());
195
0
        len += s.length();
196
0
    }
197
0
    void append(const char16_t* s, const int32_t sLength) {
198
0
        app.appendString(s, sLength);
199
0
        len += sLength;
200
0
    }
201
0
    void append(const UnicodeString& s, int32_t start, int32_t length) {
202
0
        append(s.tempSubString(start, length));
203
0
    }
204
0
    void formatAndAppend(const Format* formatter, const Formattable& arg, UErrorCode& ec) {
205
0
        UnicodeString s;
206
0
        formatter->format(arg, s, ec);
207
0
        if (U_SUCCESS(ec)) {
208
0
            append(s);
209
0
        }
210
0
    }
211
    void formatAndAppend(const Format* formatter, const Formattable& arg,
212
0
                         const UnicodeString &argString, UErrorCode& ec) {
213
0
        if (!argString.isEmpty()) {
214
0
            if (U_SUCCESS(ec)) {
215
0
                append(argString);
216
0
            }
217
0
        } else {
218
0
            formatAndAppend(formatter, arg, ec);
219
0
        }
220
0
    }
221
0
    int32_t length() {
222
0
        return len;
223
0
    }
224
private:
225
    Appendable& app;
226
    int32_t len;
227
};
228
229
230
// -------------------------------------
231
// Creates a MessageFormat instance based on the pattern.
232
233
MessageFormat::MessageFormat(const UnicodeString& pattern,
234
                             UErrorCode& success)
235
7.21k
: fLocale(Locale::getDefault()),  // Uses the default locale
236
7.21k
  msgPattern(success),
237
7.21k
  formatAliases(nullptr),
238
7.21k
  formatAliasesCapacity(0),
239
7.21k
  argTypes(nullptr),
240
7.21k
  argTypeCount(0),
241
7.21k
  argTypeCapacity(0),
242
7.21k
  hasArgTypeConflicts(false),
243
7.21k
  defaultNumberFormat(nullptr),
244
7.21k
  defaultDateFormat(nullptr),
245
7.21k
  cachedFormatters(nullptr),
246
7.21k
  customFormatArgStarts(nullptr),
247
7.21k
  pluralProvider(*this, UPLURAL_TYPE_CARDINAL),
248
7.21k
  ordinalProvider(*this, UPLURAL_TYPE_ORDINAL)
249
7.21k
{
250
7.21k
    setLocaleIDs(fLocale.getName(), fLocale.getName());
251
7.21k
    applyPattern(pattern, success);
252
7.21k
}
253
254
MessageFormat::MessageFormat(const UnicodeString& pattern,
255
                             const Locale& newLocale,
256
                             UErrorCode& success)
257
0
: fLocale(newLocale),
258
0
  msgPattern(success),
259
0
  formatAliases(nullptr),
260
0
  formatAliasesCapacity(0),
261
0
  argTypes(nullptr),
262
0
  argTypeCount(0),
263
0
  argTypeCapacity(0),
264
0
  hasArgTypeConflicts(false),
265
0
  defaultNumberFormat(nullptr),
266
0
  defaultDateFormat(nullptr),
267
0
  cachedFormatters(nullptr),
268
0
  customFormatArgStarts(nullptr),
269
0
  pluralProvider(*this, UPLURAL_TYPE_CARDINAL),
270
0
  ordinalProvider(*this, UPLURAL_TYPE_ORDINAL)
271
0
{
272
0
    setLocaleIDs(fLocale.getName(), fLocale.getName());
273
0
    applyPattern(pattern, success);
274
0
}
275
276
MessageFormat::MessageFormat(const UnicodeString& pattern,
277
                             const Locale& newLocale,
278
                             UParseError& parseError,
279
                             UErrorCode& success)
280
0
: fLocale(newLocale),
281
0
  msgPattern(success),
282
0
  formatAliases(nullptr),
283
0
  formatAliasesCapacity(0),
284
0
  argTypes(nullptr),
285
0
  argTypeCount(0),
286
0
  argTypeCapacity(0),
287
0
  hasArgTypeConflicts(false),
288
0
  defaultNumberFormat(nullptr),
289
0
  defaultDateFormat(nullptr),
290
0
  cachedFormatters(nullptr),
291
0
  customFormatArgStarts(nullptr),
292
0
  pluralProvider(*this, UPLURAL_TYPE_CARDINAL),
293
0
  ordinalProvider(*this, UPLURAL_TYPE_ORDINAL)
294
0
{
295
0
    setLocaleIDs(fLocale.getName(), fLocale.getName());
296
0
    applyPattern(pattern, parseError, success);
297
0
}
298
299
MessageFormat::MessageFormat(const MessageFormat& that)
300
:
301
0
  Format(that),
302
0
  fLocale(that.fLocale),
303
0
  msgPattern(that.msgPattern),
304
0
  formatAliases(nullptr),
305
0
  formatAliasesCapacity(0),
306
0
  argTypes(nullptr),
307
0
  argTypeCount(0),
308
0
  argTypeCapacity(0),
309
0
  hasArgTypeConflicts(that.hasArgTypeConflicts),
310
0
  defaultNumberFormat(nullptr),
311
0
  defaultDateFormat(nullptr),
312
0
  cachedFormatters(nullptr),
313
0
  customFormatArgStarts(nullptr),
314
0
  pluralProvider(*this, UPLURAL_TYPE_CARDINAL),
315
0
  ordinalProvider(*this, UPLURAL_TYPE_ORDINAL)
316
0
{
317
    // This will take care of creating the hash tables (since they are nullptr).
318
0
    UErrorCode ec = U_ZERO_ERROR;
319
0
    copyObjects(that, ec);
320
0
    if (U_FAILURE(ec)) {
321
0
        resetPattern();
322
0
    }
323
0
}
324
325
MessageFormat::~MessageFormat()
326
7.21k
{
327
7.21k
    uhash_close(cachedFormatters);
328
7.21k
    uhash_close(customFormatArgStarts);
329
330
7.21k
    uprv_free(argTypes);
331
7.21k
    uprv_free(formatAliases);
332
7.21k
    delete defaultNumberFormat;
333
7.21k
    delete defaultDateFormat;
334
7.21k
}
335
336
//--------------------------------------------------------------------
337
// Variable-size array management
338
339
/**
340
 * Allocate argTypes[] to at least the given capacity and return
341
 * true if successful.  If not, leave argTypes[] unchanged.
342
 *
343
 * If argTypes is nullptr, allocate it.  If it is not nullptr, enlarge it
344
 * if necessary to be at least as large as specified.
345
 */
346
4.11k
UBool MessageFormat::allocateArgTypes(int32_t capacity, UErrorCode& status) {
347
4.11k
    if (U_FAILURE(status)) {
348
0
        return false;
349
0
    }
350
4.11k
    if (argTypeCapacity >= capacity) {
351
3.99k
        return true;
352
3.99k
    }
353
125
    if (capacity < DEFAULT_INITIAL_CAPACITY) {
354
71
        capacity = DEFAULT_INITIAL_CAPACITY;
355
71
    } else if (capacity < 2*argTypeCapacity) {
356
0
        capacity = 2*argTypeCapacity;
357
0
    }
358
125
    Formattable::Type* a = static_cast<Formattable::Type*>(
359
125
            uprv_realloc(argTypes, sizeof(*argTypes) * capacity));
360
125
    if (a == nullptr) {
361
0
        status = U_MEMORY_ALLOCATION_ERROR;
362
0
        return false;
363
0
    }
364
125
    argTypes = a;
365
125
    argTypeCapacity = capacity;
366
125
    return true;
367
125
}
368
369
// -------------------------------------
370
// assignment operator
371
372
const MessageFormat&
373
MessageFormat::operator=(const MessageFormat& that)
374
0
{
375
0
    if (this != &that) {
376
        // Calls the super class for assignment first.
377
0
        Format::operator=(that);
378
379
0
        setLocale(that.fLocale);
380
0
        msgPattern = that.msgPattern;
381
0
        hasArgTypeConflicts = that.hasArgTypeConflicts;
382
383
0
        UErrorCode ec = U_ZERO_ERROR;
384
0
        copyObjects(that, ec);
385
0
        if (U_FAILURE(ec)) {
386
0
            resetPattern();
387
0
        }
388
0
    }
389
0
    return *this;
390
0
}
391
392
bool
393
MessageFormat::operator==(const Format& rhs) const
394
0
{
395
0
    if (this == &rhs) return true;
396
397
    // Check class ID before checking MessageFormat members
398
0
    if (!Format::operator==(rhs)) return false;
399
400
0
    const MessageFormat& that = static_cast<const MessageFormat&>(rhs);
401
0
    if (msgPattern != that.msgPattern ||
402
0
        fLocale != that.fLocale) {
403
0
        return false;
404
0
    }
405
406
    // Compare hashtables.
407
0
    if ((customFormatArgStarts == nullptr) != (that.customFormatArgStarts == nullptr)) {
408
0
        return false;
409
0
    }
410
0
    if (customFormatArgStarts == nullptr) {
411
0
        return true;
412
0
    }
413
414
0
    UErrorCode ec = U_ZERO_ERROR;
415
0
    const int32_t count = uhash_count(customFormatArgStarts);
416
0
    const int32_t rhs_count = uhash_count(that.customFormatArgStarts);
417
0
    if (count != rhs_count) {
418
0
        return false;
419
0
    }
420
0
    int32_t idx = 0, rhs_idx = 0, pos = UHASH_FIRST, rhs_pos = UHASH_FIRST;
421
0
    for (; idx < count && rhs_idx < rhs_count && U_SUCCESS(ec); ++idx, ++rhs_idx) {
422
0
        const UHashElement* cur = uhash_nextElement(customFormatArgStarts, &pos);
423
0
        const UHashElement* rhs_cur = uhash_nextElement(that.customFormatArgStarts, &rhs_pos);
424
0
        if (cur->key.integer != rhs_cur->key.integer) {
425
0
            return false;
426
0
        }
427
0
        const Format* format = static_cast<const Format*>(uhash_iget(cachedFormatters, cur->key.integer));
428
0
        const Format* rhs_format = static_cast<const Format*>(uhash_iget(that.cachedFormatters, rhs_cur->key.integer));
429
0
        if (*format != *rhs_format) {
430
0
            return false;
431
0
        }
432
0
    }
433
0
    return true;
434
0
}
435
436
// -------------------------------------
437
// Creates a copy of this MessageFormat, the caller owns the copy.
438
439
MessageFormat*
440
MessageFormat::clone() const
441
0
{
442
0
    return new MessageFormat(*this);
443
0
}
444
445
// -------------------------------------
446
// Sets the locale of this MessageFormat object to theLocale.
447
448
void
449
MessageFormat::setLocale(const Locale& theLocale)
450
0
{
451
0
    if (fLocale != theLocale) {
452
0
        delete defaultNumberFormat;
453
0
        defaultNumberFormat = nullptr;
454
0
        delete defaultDateFormat;
455
0
        defaultDateFormat = nullptr;
456
0
        fLocale = theLocale;
457
0
        setLocaleIDs(fLocale.getName(), fLocale.getName());
458
0
        pluralProvider.reset();
459
0
        ordinalProvider.reset();
460
0
    }
461
0
}
462
463
// -------------------------------------
464
// Gets the locale of this MessageFormat object.
465
466
const Locale&
467
MessageFormat::getLocale() const
468
0
{
469
0
    return fLocale;
470
0
}
471
472
void
473
MessageFormat::applyPattern(const UnicodeString& newPattern,
474
                            UErrorCode& status)
475
7.21k
{
476
7.21k
    UParseError parseError;
477
7.21k
    applyPattern(newPattern,parseError,status);
478
7.21k
}
479
480
481
// -------------------------------------
482
// Applies the new pattern and returns an error if the pattern
483
// is not correct.
484
void
485
MessageFormat::applyPattern(const UnicodeString& pattern,
486
                            UParseError& parseError,
487
                            UErrorCode& ec)
488
7.21k
{
489
7.21k
    if(U_FAILURE(ec)) {
490
0
        return;
491
0
    }
492
7.21k
    msgPattern.parse(pattern, &parseError, ec);
493
7.21k
    cacheExplicitFormats(ec);
494
495
7.21k
    if (U_FAILURE(ec)) {
496
3.42k
        resetPattern();
497
3.42k
    }
498
7.21k
}
499
500
3.42k
void MessageFormat::resetPattern() {
501
3.42k
    msgPattern.clear();
502
3.42k
    uhash_close(cachedFormatters);
503
3.42k
    cachedFormatters = nullptr;
504
3.42k
    uhash_close(customFormatArgStarts);
505
3.42k
    customFormatArgStarts = nullptr;
506
3.42k
    argTypeCount = 0;
507
3.42k
    hasArgTypeConflicts = false;
508
3.42k
}
509
510
void
511
MessageFormat::applyPattern(const UnicodeString& pattern,
512
                            UMessagePatternApostropheMode aposMode,
513
                            UParseError* parseError,
514
0
                            UErrorCode& status) {
515
0
    if (aposMode != msgPattern.getApostropheMode()) {
516
0
        msgPattern.clearPatternAndSetApostropheMode(aposMode);
517
0
    }
518
0
    UParseError tempParseError;
519
0
    applyPattern(pattern, (parseError == nullptr) ? tempParseError : *parseError, status);
520
0
}
521
522
// -------------------------------------
523
// Converts this MessageFormat instance to a pattern.
524
525
UnicodeString&
526
0
MessageFormat::toPattern(UnicodeString& appendTo) const {
527
0
    if ((customFormatArgStarts != nullptr && 0 != uhash_count(customFormatArgStarts)) ||
528
0
        0 == msgPattern.countParts()
529
0
    ) {
530
0
        appendTo.setToBogus();
531
0
        return appendTo;
532
0
    }
533
0
    return appendTo.append(msgPattern.getPatternString());
534
0
}
535
536
0
int32_t MessageFormat::nextTopLevelArgStart(int32_t partIndex) const {
537
0
    if (partIndex != 0) {
538
0
        partIndex = msgPattern.getLimitPartIndex(partIndex);
539
0
    }
540
0
    for (;;) {
541
0
        UMessagePatternPartType type = msgPattern.getPartType(++partIndex);
542
0
        if (type == UMSGPAT_PART_TYPE_ARG_START) {
543
0
            return partIndex;
544
0
        }
545
0
        if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) {
546
0
            return -1;
547
0
        }
548
0
    }
549
0
}
550
551
void MessageFormat::setArgStartFormat(int32_t argStart,
552
                                      Format* formatter,
553
74.3k
                                      UErrorCode& status) {
554
74.3k
    if (U_FAILURE(status)) {
555
335
        delete formatter;
556
335
        return;
557
335
    }
558
74.0k
    if (cachedFormatters == nullptr) {
559
2.64k
        cachedFormatters=uhash_open(uhash_hashLong, uhash_compareLong,
560
2.64k
                                    equalFormatsForHash, &status);
561
2.64k
        if (U_FAILURE(status)) {
562
0
            delete formatter;
563
0
            return;
564
0
        }
565
2.64k
        uhash_setValueDeleter(cachedFormatters, uprv_deleteUObject);
566
2.64k
    }
567
74.0k
    if (formatter == nullptr) {
568
0
        formatter = new DummyFormat();
569
0
    }
570
74.0k
    uhash_iput(cachedFormatters, argStart, formatter, &status);
571
74.0k
}
572
573
574
0
UBool MessageFormat::argNameMatches(int32_t partIndex, const UnicodeString& argName, int32_t argNumber) {
575
0
    const MessagePattern::Part& part = msgPattern.getPart(partIndex);
576
0
    return part.getType() == UMSGPAT_PART_TYPE_ARG_NAME ?
577
0
        msgPattern.partSubstringMatches(part, argName) :
578
0
        part.getValue() == argNumber;  // ARG_NUMBER
579
0
}
580
581
// Sets a custom formatter for a MessagePattern ARG_START part index.
582
// "Custom" formatters are provided by the user via setFormat() or similar APIs.
583
void MessageFormat::setCustomArgStartFormat(int32_t argStart,
584
                                            Format* formatter,
585
0
                                            UErrorCode& status) {
586
0
    setArgStartFormat(argStart, formatter, status);
587
0
    if (customFormatArgStarts == nullptr) {
588
0
        customFormatArgStarts=uhash_open(uhash_hashLong, uhash_compareLong,
589
0
                                         nullptr, &status);
590
0
    }
591
0
    uhash_iputi(customFormatArgStarts, argStart, 1, &status);
592
0
}
593
594
0
Format* MessageFormat::getCachedFormatter(int32_t argumentNumber) const {
595
0
    if (cachedFormatters == nullptr) {
596
0
        return nullptr;
597
0
    }
598
0
    void* ptr = uhash_iget(cachedFormatters, argumentNumber);
599
0
    if (ptr != nullptr && dynamic_cast<DummyFormat*>(static_cast<Format*>(ptr)) == nullptr) {
600
0
        return static_cast<Format*>(ptr);
601
0
    } else {
602
        // Not cached, or a DummyFormat representing setFormat(nullptr).
603
0
        return nullptr;
604
0
    }
605
0
}
606
607
// -------------------------------------
608
// Adopts the new formats array and updates the array count.
609
// This MessageFormat instance owns the new formats.
610
void
611
MessageFormat::adoptFormats(Format** newFormats,
612
0
                            int32_t count) {
613
0
    if (newFormats == nullptr || count < 0) {
614
0
        return;
615
0
    }
616
    // Throw away any cached formatters.
617
0
    if (cachedFormatters != nullptr) {
618
0
        uhash_removeAll(cachedFormatters);
619
0
    }
620
0
    if (customFormatArgStarts != nullptr) {
621
0
        uhash_removeAll(customFormatArgStarts);
622
0
    }
623
624
0
    int32_t formatNumber = 0;
625
0
    UErrorCode status = U_ZERO_ERROR;
626
0
    for (int32_t partIndex = 0;
627
0
        formatNumber < count && U_SUCCESS(status) &&
628
0
            (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
629
0
        setCustomArgStartFormat(partIndex, newFormats[formatNumber], status);
630
0
        ++formatNumber;
631
0
    }
632
    // Delete those that didn't get used (if any).
633
0
    for (; formatNumber < count; ++formatNumber) {
634
0
        delete newFormats[formatNumber];
635
0
    }
636
637
0
}
638
639
// -------------------------------------
640
// Sets the new formats array and updates the array count.
641
// This MessageFormat instance makes a copy of the new formats.
642
643
void
644
MessageFormat::setFormats(const Format** newFormats,
645
0
                          int32_t count) {
646
0
    if (newFormats == nullptr || count < 0) {
647
0
        return;
648
0
    }
649
    // Throw away any cached formatters.
650
0
    if (cachedFormatters != nullptr) {
651
0
        uhash_removeAll(cachedFormatters);
652
0
    }
653
0
    if (customFormatArgStarts != nullptr) {
654
0
        uhash_removeAll(customFormatArgStarts);
655
0
    }
656
657
0
    UErrorCode status = U_ZERO_ERROR;
658
0
    int32_t formatNumber = 0;
659
0
    for (int32_t partIndex = 0;
660
0
        formatNumber < count && U_SUCCESS(status) && (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
661
0
      Format* newFormat = nullptr;
662
0
      if (newFormats[formatNumber] != nullptr) {
663
0
          newFormat = newFormats[formatNumber]->clone();
664
0
          if (newFormat == nullptr) {
665
0
              status = U_MEMORY_ALLOCATION_ERROR;
666
0
          }
667
0
      }
668
0
      setCustomArgStartFormat(partIndex, newFormat, status);
669
0
      ++formatNumber;
670
0
    }
671
0
    if (U_FAILURE(status)) {
672
0
        resetPattern();
673
0
    }
674
0
}
675
676
// -------------------------------------
677
// Adopt a single format by format number.
678
// Do nothing if the format number is not less than the array count.
679
680
void
681
0
MessageFormat::adoptFormat(int32_t n, Format *newFormat) {
682
0
    LocalPointer<Format> p(newFormat);
683
0
    if (n >= 0) {
684
0
        int32_t formatNumber = 0;
685
0
        for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
686
0
            if (n == formatNumber) {
687
0
                UErrorCode status = U_ZERO_ERROR;
688
0
                setCustomArgStartFormat(partIndex, p.orphan(), status);
689
0
                return;
690
0
            }
691
0
            ++formatNumber;
692
0
        }
693
0
    }
694
0
}
695
696
// -------------------------------------
697
// Adopt a single format by format name.
698
// Do nothing if there is no match of formatName.
699
void
700
MessageFormat::adoptFormat(const UnicodeString& formatName,
701
                           Format* formatToAdopt,
702
0
                           UErrorCode& status) {
703
0
    LocalPointer<Format> p(formatToAdopt);
704
0
    if (U_FAILURE(status)) {
705
0
        return;
706
0
    }
707
0
    int32_t argNumber = MessagePattern::validateArgumentName(formatName);
708
0
    if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) {
709
0
        status = U_ILLEGAL_ARGUMENT_ERROR;
710
0
        return;
711
0
    }
712
0
    for (int32_t partIndex = 0;
713
0
        (partIndex = nextTopLevelArgStart(partIndex)) >= 0 && U_SUCCESS(status);
714
0
    ) {
715
0
        if (argNameMatches(partIndex + 1, formatName, argNumber)) {
716
0
            Format* f;
717
0
            if (p.isValid()) {
718
0
                f = p.orphan();
719
0
            } else if (formatToAdopt == nullptr) {
720
0
                f = nullptr;
721
0
            } else {
722
0
                f = formatToAdopt->clone();
723
0
                if (f == nullptr) {
724
0
                    status = U_MEMORY_ALLOCATION_ERROR;
725
0
                    return;
726
0
                }
727
0
            }
728
0
            setCustomArgStartFormat(partIndex, f, status);
729
0
        }
730
0
    }
731
0
}
732
733
// -------------------------------------
734
// Set a single format.
735
// Do nothing if the variable is not less than the array count.
736
void
737
0
MessageFormat::setFormat(int32_t n, const Format& newFormat) {
738
739
0
    if (n >= 0) {
740
0
        int32_t formatNumber = 0;
741
0
        for (int32_t partIndex = 0;
742
0
             (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
743
0
            if (n == formatNumber) {
744
0
                Format* new_format = newFormat.clone();
745
0
                if (new_format) {
746
0
                    UErrorCode status = U_ZERO_ERROR;
747
0
                    setCustomArgStartFormat(partIndex, new_format, status);
748
0
                }
749
0
                return;
750
0
            }
751
0
            ++formatNumber;
752
0
        }
753
0
    }
754
0
}
755
756
// -------------------------------------
757
// Get a single format by format name.
758
// Do nothing if the variable is not less than the array count.
759
Format *
760
0
MessageFormat::getFormat(const UnicodeString& formatName, UErrorCode& status) {
761
0
    if (U_FAILURE(status) || cachedFormatters == nullptr) return nullptr;
762
763
0
    int32_t argNumber = MessagePattern::validateArgumentName(formatName);
764
0
    if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) {
765
0
        status = U_ILLEGAL_ARGUMENT_ERROR;
766
0
        return nullptr;
767
0
    }
768
0
    for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
769
0
        if (argNameMatches(partIndex + 1, formatName, argNumber)) {
770
0
            return getCachedFormatter(partIndex);
771
0
        }
772
0
    }
773
0
    return nullptr;
774
0
}
775
776
// -------------------------------------
777
// Set a single format by format name
778
// Do nothing if the variable is not less than the array count.
779
void
780
MessageFormat::setFormat(const UnicodeString& formatName,
781
                         const Format& newFormat,
782
0
                         UErrorCode& status) {
783
0
    if (U_FAILURE(status)) return;
784
785
0
    int32_t argNumber = MessagePattern::validateArgumentName(formatName);
786
0
    if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) {
787
0
        status = U_ILLEGAL_ARGUMENT_ERROR;
788
0
        return;
789
0
    }
790
0
    for (int32_t partIndex = 0;
791
0
        (partIndex = nextTopLevelArgStart(partIndex)) >= 0 && U_SUCCESS(status);
792
0
    ) {
793
0
        if (argNameMatches(partIndex + 1, formatName, argNumber)) {
794
0
            Format* new_format = newFormat.clone();
795
0
            if (new_format == nullptr) {
796
0
                status = U_MEMORY_ALLOCATION_ERROR;
797
0
                return;
798
0
            }
799
0
            setCustomArgStartFormat(partIndex, new_format, status);
800
0
        }
801
0
    }
802
0
}
803
804
// -------------------------------------
805
// Gets the format array.
806
const Format**
807
MessageFormat::getFormats(int32_t& cnt) const
808
0
{
809
    // This old API returns an array (which we hold) of Format*
810
    // pointers.  The array is valid up to the next call to any
811
    // method on this object.  We construct and resize an array
812
    // on demand that contains aliases to the subformats[i].format
813
    // pointers.
814
815
    // Get total required capacity first (it's refreshed on each call).
816
0
    int32_t totalCapacity = 0;
817
0
    for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0; ++totalCapacity) {}
818
819
0
    MessageFormat* t = const_cast<MessageFormat*> (this);
820
0
    cnt = 0;
821
0
    if (formatAliases == nullptr) {
822
0
        t->formatAliasesCapacity = totalCapacity;
823
0
        Format** a = static_cast<Format**>(
824
0
            uprv_malloc(sizeof(Format*) * formatAliasesCapacity));
825
0
        if (a == nullptr) {
826
0
            t->formatAliasesCapacity = 0;
827
0
            return nullptr;
828
0
        }
829
0
        t->formatAliases = a;
830
0
    } else if (totalCapacity > formatAliasesCapacity) {
831
0
        Format** a = static_cast<Format**>(
832
0
            uprv_realloc(formatAliases, sizeof(Format*) * totalCapacity));
833
0
        if (a == nullptr) {
834
0
            t->formatAliasesCapacity = 0;
835
0
            return nullptr;
836
0
        }
837
0
        t->formatAliases = a;
838
0
        t->formatAliasesCapacity = totalCapacity;
839
0
    }
840
841
0
    for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
842
0
        t->formatAliases[cnt++] = getCachedFormatter(partIndex);
843
0
    }
844
845
0
    return (const Format**)formatAliases;
846
0
}
847
848
849
0
UnicodeString MessageFormat::getArgName(int32_t partIndex) {
850
0
    const MessagePattern::Part& part = msgPattern.getPart(partIndex);
851
0
    return msgPattern.getSubstring(part);
852
0
}
853
854
StringEnumeration*
855
0
MessageFormat::getFormatNames(UErrorCode& status) {
856
0
    if (U_FAILURE(status))  return nullptr;
857
858
0
    LocalPointer<UVector> formatNames(new UVector(status), status);
859
0
    if (U_FAILURE(status)) {
860
0
        return nullptr;
861
0
    }
862
0
    formatNames->setDeleter(uprv_deleteUObject);
863
864
0
    for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
865
0
        LocalPointer<UnicodeString> name(getArgName(partIndex + 1).clone(), status);
866
0
        formatNames->adoptElement(name.orphan(), status);
867
0
        if (U_FAILURE(status))  return nullptr;
868
0
    }
869
870
0
    LocalPointer<StringEnumeration> nameEnumerator(
871
0
        new FormatNameEnumeration(std::move(formatNames), status), status);
872
0
    return U_SUCCESS(status) ? nameEnumerator.orphan() : nullptr;
873
0
}
874
875
// -------------------------------------
876
// Formats the source Formattable array and copy into the result buffer.
877
// Ignore the FieldPosition result for error checking.
878
879
UnicodeString&
880
MessageFormat::format(const Formattable* source,
881
                      int32_t cnt,
882
                      UnicodeString& appendTo,
883
                      FieldPosition& ignore,
884
                      UErrorCode& success) const
885
0
{
886
0
    return format(source, nullptr, cnt, appendTo, &ignore, success);
887
0
}
888
889
// -------------------------------------
890
// Internally creates a MessageFormat instance based on the
891
// pattern and formats the arguments Formattable array and
892
// copy into the appendTo buffer.
893
894
UnicodeString&
895
MessageFormat::format(  const UnicodeString& pattern,
896
                        const Formattable* arguments,
897
                        int32_t cnt,
898
                        UnicodeString& appendTo,
899
                        UErrorCode& success)
900
0
{
901
0
    MessageFormat temp(pattern, success);
902
0
    return temp.format(arguments, nullptr, cnt, appendTo, nullptr, success);
903
0
}
904
905
// -------------------------------------
906
// Formats the source Formattable object and copy into the
907
// appendTo buffer.  The Formattable object must be an array
908
// of Formattable instances, returns error otherwise.
909
910
UnicodeString&
911
MessageFormat::format(const Formattable& source,
912
                      UnicodeString& appendTo,
913
                      FieldPosition& ignore,
914
                      UErrorCode& success) const
915
0
{
916
0
    if (U_FAILURE(success))
917
0
        return appendTo;
918
0
    if (source.getType() != Formattable::kArray) {
919
0
        success = U_ILLEGAL_ARGUMENT_ERROR;
920
0
        return appendTo;
921
0
    }
922
0
    int32_t cnt;
923
0
    const Formattable* tmpPtr = source.getArray(cnt);
924
0
    return format(tmpPtr, nullptr, cnt, appendTo, &ignore, success);
925
0
}
926
927
UnicodeString&
928
MessageFormat::format(const UnicodeString* argumentNames,
929
                      const Formattable* arguments,
930
                      int32_t count,
931
                      UnicodeString& appendTo,
932
0
                      UErrorCode& success) const {
933
0
    return format(arguments, argumentNames, count, appendTo, nullptr, success);
934
0
}
935
936
// Does linear search to find the match for an ArgName.
937
const Formattable* MessageFormat::getArgFromListByName(const Formattable* arguments,
938
                                                       const UnicodeString *argumentNames,
939
0
                                                       int32_t cnt, UnicodeString& name) const {
940
0
    for (int32_t i = 0; i < cnt; ++i) {
941
0
        if (0 == argumentNames[i].compare(name)) {
942
0
            return arguments + i;
943
0
        }
944
0
    }
945
0
    return nullptr;
946
0
}
947
948
949
UnicodeString&
950
MessageFormat::format(const Formattable* arguments,
951
                      const UnicodeString *argumentNames,
952
                      int32_t cnt,
953
                      UnicodeString& appendTo,
954
                      FieldPosition* pos,
955
0
                      UErrorCode& status) const {
956
0
    if (U_FAILURE(status)) {
957
0
        return appendTo;
958
0
    }
959
960
0
    UnicodeStringAppendable usapp(appendTo);
961
0
    AppendableWrapper app(usapp);
962
0
    format(0, nullptr, arguments, argumentNames, cnt, app, pos, status);
963
0
    return appendTo;
964
0
}
965
966
namespace {
967
968
/**
969
 * Mutable input/output values for the PluralSelectorProvider.
970
 * Separate so that it is possible to make MessageFormat Freezable.
971
 */
972
class PluralSelectorContext {
973
public:
974
    PluralSelectorContext(int32_t start, const UnicodeString &name,
975
                          const Formattable &num, double off, UErrorCode &errorCode)
976
0
            : startIndex(start), argName(name), offset(off),
977
0
              numberArgIndex(-1), formatter(nullptr), forReplaceNumber(false) {
978
        // number needs to be set even when select() is not called.
979
        // Keep it as a Number/Formattable:
980
        // For format() methods, and to preserve information (e.g., BigDecimal).
981
0
        if(off == 0) {
982
0
            number = num;
983
0
        } else {
984
0
            number = num.getDouble(errorCode) - off;
985
0
        }
986
0
    }
987
988
    // Input values for plural selection with decimals.
989
    int32_t startIndex;
990
    const UnicodeString &argName;
991
    /** argument number - plural offset */
992
    Formattable number;
993
    double offset;
994
    // Output values for plural selection with decimals.
995
    /** -1 if REPLACE_NUMBER, 0 arg not found, >0 ARG_START index */
996
    int32_t numberArgIndex;
997
    const Format *formatter;
998
    /** formatted argument number - plural offset */
999
    UnicodeString numberString;
1000
    /** true if number-offset was formatted with the stock number formatter */
1001
    UBool forReplaceNumber;
1002
};
1003
1004
}  // namespace
1005
1006
// if argumentNames is nullptr, this means arguments is a numeric array.
1007
// arguments can not be nullptr.
1008
// We use const void *plNumber rather than const PluralSelectorContext *pluralNumber
1009
// so that we need not declare the PluralSelectorContext in the public header file.
1010
void MessageFormat::format(int32_t msgStart, const void *plNumber,
1011
                           const Formattable* arguments,
1012
                           const UnicodeString *argumentNames,
1013
                           int32_t cnt,
1014
                           AppendableWrapper& appendTo,
1015
                           FieldPosition* ignore,
1016
0
                           UErrorCode& success) const {
1017
0
    if (U_FAILURE(success)) {
1018
0
        return;
1019
0
    }
1020
1021
0
    const UnicodeString& msgString = msgPattern.getPatternString();
1022
0
    int32_t prevIndex = msgPattern.getPart(msgStart).getLimit();
1023
0
    for (int32_t i = msgStart + 1; U_SUCCESS(success) ; ++i) {
1024
0
        const MessagePattern::Part* part = &msgPattern.getPart(i);
1025
0
        const UMessagePatternPartType type = part->getType();
1026
0
        int32_t index = part->getIndex();
1027
0
        appendTo.append(msgString, prevIndex, index - prevIndex);
1028
0
        if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) {
1029
0
            return;
1030
0
        }
1031
0
        prevIndex = part->getLimit();
1032
0
        if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER) {
1033
0
            const PluralSelectorContext &pluralNumber =
1034
0
                *static_cast<const PluralSelectorContext *>(plNumber);
1035
0
            if(pluralNumber.forReplaceNumber) {
1036
                // number-offset was already formatted.
1037
0
                appendTo.formatAndAppend(pluralNumber.formatter,
1038
0
                        pluralNumber.number, pluralNumber.numberString, success);
1039
0
            } else {
1040
0
                const NumberFormat* nf = getDefaultNumberFormat(success);
1041
0
                appendTo.formatAndAppend(nf, pluralNumber.number, success);
1042
0
            }
1043
0
            continue;
1044
0
        }
1045
0
        if (type != UMSGPAT_PART_TYPE_ARG_START) {
1046
0
            continue;
1047
0
        }
1048
0
        int32_t argLimit = msgPattern.getLimitPartIndex(i);
1049
0
        UMessagePatternArgType argType = part->getArgType();
1050
0
        part = &msgPattern.getPart(++i);
1051
0
        const Formattable* arg;
1052
0
        UBool noArg = false;
1053
0
        UnicodeString argName = msgPattern.getSubstring(*part);
1054
0
        if (argumentNames == nullptr) {
1055
0
            int32_t argNumber = part->getValue();  // ARG_NUMBER
1056
0
            if (0 <= argNumber && argNumber < cnt) {
1057
0
                arg = arguments + argNumber;
1058
0
            } else {
1059
0
                arg = nullptr;
1060
0
                noArg = true;
1061
0
            }
1062
0
        } else {
1063
0
            arg = getArgFromListByName(arguments, argumentNames, cnt, argName);
1064
0
            if (arg == nullptr) {
1065
0
                noArg = true;
1066
0
            }
1067
0
        }
1068
0
        ++i;
1069
0
        int32_t prevDestLength = appendTo.length();
1070
0
        const Format* formatter = nullptr;
1071
0
        if (noArg) {
1072
0
            appendTo.append(
1073
0
                UnicodeString(LEFT_CURLY_BRACE).append(argName).append(RIGHT_CURLY_BRACE));
1074
0
        } else if (arg == nullptr) {
1075
0
            appendTo.append(NULL_STRING, 4);
1076
0
        } else if(plNumber!=nullptr &&
1077
0
                static_cast<const PluralSelectorContext *>(plNumber)->numberArgIndex==(i-2)) {
1078
0
            const PluralSelectorContext &pluralNumber =
1079
0
                *static_cast<const PluralSelectorContext *>(plNumber);
1080
0
            if(pluralNumber.offset == 0) {
1081
                // The number was already formatted with this formatter.
1082
0
                appendTo.formatAndAppend(pluralNumber.formatter, pluralNumber.number,
1083
0
                                         pluralNumber.numberString, success);
1084
0
            } else {
1085
                // Do not use the formatted (number-offset) string for a named argument
1086
                // that formats the number without subtracting the offset.
1087
0
                appendTo.formatAndAppend(pluralNumber.formatter, *arg, success);
1088
0
            }
1089
0
        } else if ((formatter = getCachedFormatter(i - 2)) != nullptr) {
1090
            // Handles all ArgType.SIMPLE, and formatters from setFormat() and its siblings.
1091
0
            if (dynamic_cast<const ChoiceFormat*>(formatter) ||
1092
0
                dynamic_cast<const PluralFormat*>(formatter) ||
1093
0
                dynamic_cast<const SelectFormat*>(formatter)) {
1094
                // We only handle nested formats here if they were provided via
1095
                // setFormat() or its siblings. Otherwise they are not cached and instead
1096
                // handled below according to argType.
1097
0
                UnicodeString subMsgString;
1098
0
                formatter->format(*arg, subMsgString, success);
1099
0
                if (subMsgString.indexOf(LEFT_CURLY_BRACE) >= 0 ||
1100
0
                    (subMsgString.indexOf(SINGLE_QUOTE) >= 0 && !MessageImpl::jdkAposMode(msgPattern))
1101
0
                ) {
1102
0
                    MessageFormat subMsgFormat(subMsgString, fLocale, success);
1103
0
                    subMsgFormat.format(0, nullptr, arguments, argumentNames, cnt, appendTo, ignore, success);
1104
0
                } else {
1105
0
                    appendTo.append(subMsgString);
1106
0
                }
1107
0
            } else {
1108
0
                appendTo.formatAndAppend(formatter, *arg, success);
1109
0
            }
1110
0
        } else if (argType == UMSGPAT_ARG_TYPE_NONE || (cachedFormatters && uhash_iget(cachedFormatters, i - 2))) {
1111
            // We arrive here if getCachedFormatter returned nullptr, but there was actually an element in the hash table.
1112
            // This can only happen if the hash table contained a DummyFormat, so the if statement above is a check
1113
            // for the hash table containing DummyFormat.
1114
0
            if (arg->isNumeric()) {
1115
0
                const NumberFormat* nf = getDefaultNumberFormat(success);
1116
0
                appendTo.formatAndAppend(nf, *arg, success);
1117
0
            } else if (arg->getType() == Formattable::kDate) {
1118
0
                const DateFormat* df = getDefaultDateFormat(success);
1119
0
                appendTo.formatAndAppend(df, *arg, success);
1120
0
            } else {
1121
0
                appendTo.append(arg->getString(success));
1122
0
            }
1123
0
        } else if (argType == UMSGPAT_ARG_TYPE_CHOICE) {
1124
0
            if (!arg->isNumeric()) {
1125
0
                success = U_ILLEGAL_ARGUMENT_ERROR;
1126
0
                return;
1127
0
            }
1128
            // We must use the Formattable::getDouble() variant with the UErrorCode parameter
1129
            // because only this one converts non-double numeric types to double.
1130
0
            const double number = arg->getDouble(success);
1131
0
            int32_t subMsgStart = ChoiceFormat::findSubMessage(msgPattern, i, number);
1132
0
            formatComplexSubMessage(subMsgStart, nullptr, arguments, argumentNames,
1133
0
                                    cnt, appendTo, success);
1134
0
        } else if (UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType)) {
1135
0
            if (!arg->isNumeric()) {
1136
0
                success = U_ILLEGAL_ARGUMENT_ERROR;
1137
0
                return;
1138
0
            }
1139
0
            const PluralSelectorProvider &selector =
1140
0
                argType == UMSGPAT_ARG_TYPE_PLURAL ? pluralProvider : ordinalProvider;
1141
            // We must use the Formattable::getDouble() variant with the UErrorCode parameter
1142
            // because only this one converts non-double numeric types to double.
1143
0
            double offset = msgPattern.getPluralOffset(i);
1144
0
            PluralSelectorContext context(i, argName, *arg, offset, success);
1145
0
            int32_t subMsgStart = PluralFormat::findSubMessage(
1146
0
                    msgPattern, i, selector, &context, arg->getDouble(success), success);
1147
0
            formatComplexSubMessage(subMsgStart, &context, arguments, argumentNames,
1148
0
                                    cnt, appendTo, success);
1149
0
        } else if (argType == UMSGPAT_ARG_TYPE_SELECT) {
1150
0
            int32_t subMsgStart = SelectFormat::findSubMessage(msgPattern, i, arg->getString(success), success);
1151
0
            formatComplexSubMessage(subMsgStart, nullptr, arguments, argumentNames,
1152
0
                                    cnt, appendTo, success);
1153
0
        } else {
1154
            // This should never happen.
1155
0
            success = U_INTERNAL_PROGRAM_ERROR;
1156
0
            return;
1157
0
        }
1158
0
        ignore = updateMetaData(appendTo, prevDestLength, ignore, arg);
1159
0
        prevIndex = msgPattern.getPart(argLimit).getLimit();
1160
0
        i = argLimit;
1161
0
    }
1162
0
}
1163
1164
1165
void MessageFormat::formatComplexSubMessage(int32_t msgStart,
1166
                                            const void *plNumber,
1167
                                            const Formattable* arguments,
1168
                                            const UnicodeString *argumentNames,
1169
                                            int32_t cnt,
1170
                                            AppendableWrapper& appendTo,
1171
0
                                            UErrorCode& success) const {
1172
0
    if (U_FAILURE(success)) {
1173
0
        return;
1174
0
    }
1175
1176
0
    if (!MessageImpl::jdkAposMode(msgPattern)) {
1177
0
        format(msgStart, plNumber, arguments, argumentNames, cnt, appendTo, nullptr, success);
1178
0
        return;
1179
0
    }
1180
1181
    // JDK compatibility mode: (see JDK MessageFormat.format() API docs)
1182
    // - remove SKIP_SYNTAX; that is, remove half of the apostrophes
1183
    // - if the result string contains an open curly brace '{' then
1184
    //   instantiate a temporary MessageFormat object and format again;
1185
    //   otherwise just append the result string
1186
0
    const UnicodeString& msgString = msgPattern.getPatternString();
1187
0
    UnicodeString sb;
1188
0
    int32_t prevIndex = msgPattern.getPart(msgStart).getLimit();
1189
0
    for (int32_t i = msgStart;;) {
1190
0
        const MessagePattern::Part& part = msgPattern.getPart(++i);
1191
0
        const UMessagePatternPartType type = part.getType();
1192
0
        int32_t index = part.getIndex();
1193
0
        if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) {
1194
0
            sb.append(msgString, prevIndex, index - prevIndex);
1195
0
            break;
1196
0
        } else if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER || type == UMSGPAT_PART_TYPE_SKIP_SYNTAX) {
1197
0
            sb.append(msgString, prevIndex, index - prevIndex);
1198
0
            if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER) {
1199
0
                const PluralSelectorContext &pluralNumber =
1200
0
                    *static_cast<const PluralSelectorContext *>(plNumber);
1201
0
                if(pluralNumber.forReplaceNumber) {
1202
                    // number-offset was already formatted.
1203
0
                    sb.append(pluralNumber.numberString);
1204
0
                } else {
1205
0
                    const NumberFormat* nf = getDefaultNumberFormat(success);
1206
0
                    sb.append(nf->format(pluralNumber.number, sb, success));
1207
0
                }
1208
0
            }
1209
0
            prevIndex = part.getLimit();
1210
0
        } else if (type == UMSGPAT_PART_TYPE_ARG_START) {
1211
0
            sb.append(msgString, prevIndex, index - prevIndex);
1212
0
            prevIndex = index;
1213
0
            i = msgPattern.getLimitPartIndex(i);
1214
0
            index = msgPattern.getPart(i).getLimit();
1215
0
            MessageImpl::appendReducedApostrophes(msgString, prevIndex, index, sb);
1216
0
            prevIndex = index;
1217
0
        }
1218
0
    }
1219
0
    if (sb.indexOf(LEFT_CURLY_BRACE) >= 0) {
1220
0
        UnicodeString emptyPattern;  // gcc 3.3.3 fails with "UnicodeString()" as the first parameter.
1221
0
        MessageFormat subMsgFormat(emptyPattern, fLocale, success);
1222
0
        subMsgFormat.applyPattern(sb, UMSGPAT_APOS_DOUBLE_REQUIRED, nullptr, success);
1223
0
        subMsgFormat.format(0, nullptr, arguments, argumentNames, cnt, appendTo, nullptr, success);
1224
0
    } else {
1225
0
        appendTo.append(sb);
1226
0
    }
1227
0
}
1228
1229
1230
0
UnicodeString MessageFormat::getLiteralStringUntilNextArgument(int32_t from) const {
1231
0
    const UnicodeString& msgString=msgPattern.getPatternString();
1232
0
    int32_t prevIndex=msgPattern.getPart(from).getLimit();
1233
0
    UnicodeString b;
1234
0
    for (int32_t i = from + 1; ; ++i) {
1235
0
        const MessagePattern::Part& part = msgPattern.getPart(i);
1236
0
        const UMessagePatternPartType type=part.getType();
1237
0
        int32_t index=part.getIndex();
1238
0
        b.append(msgString, prevIndex, index - prevIndex);
1239
0
        if(type==UMSGPAT_PART_TYPE_ARG_START || type==UMSGPAT_PART_TYPE_MSG_LIMIT) {
1240
0
            return b;
1241
0
        }
1242
        // Unexpected Part "part" in parsed message.
1243
0
        U_ASSERT(type==UMSGPAT_PART_TYPE_SKIP_SYNTAX || type==UMSGPAT_PART_TYPE_INSERT_CHAR);
1244
0
        prevIndex=part.getLimit();
1245
0
    }
1246
0
}
1247
1248
1249
FieldPosition* MessageFormat::updateMetaData(AppendableWrapper& /*dest*/, int32_t /*prevLength*/,
1250
0
                             FieldPosition* /*fp*/, const Formattable* /*argId*/) const {
1251
    // Unlike in Java, there are no field attributes defined for MessageFormat. Do nothing.
1252
0
    return nullptr;
1253
    /*
1254
      if (fp != nullptr && Field.ARGUMENT.equals(fp.getFieldAttribute())) {
1255
          fp->setBeginIndex(prevLength);
1256
          fp->setEndIndex(dest.get_length());
1257
          return nullptr;
1258
      }
1259
      return fp;
1260
    */
1261
0
}
1262
1263
int32_t
1264
0
MessageFormat::findOtherSubMessage(int32_t partIndex) const {
1265
0
    int32_t count=msgPattern.countParts();
1266
0
    const MessagePattern::Part *part = &msgPattern.getPart(partIndex);
1267
0
    if(MessagePattern::Part::hasNumericValue(part->getType())) {
1268
0
        ++partIndex;
1269
0
    }
1270
    // Iterate over (ARG_SELECTOR [ARG_INT|ARG_DOUBLE] message) tuples
1271
    // until ARG_LIMIT or end of plural-only pattern.
1272
0
    UnicodeString other(false, OTHER_STRING, 5);
1273
0
    do {
1274
0
        part=&msgPattern.getPart(partIndex++);
1275
0
        UMessagePatternPartType type=part->getType();
1276
0
        if(type==UMSGPAT_PART_TYPE_ARG_LIMIT) {
1277
0
            break;
1278
0
        }
1279
0
        U_ASSERT(type==UMSGPAT_PART_TYPE_ARG_SELECTOR);
1280
        // part is an ARG_SELECTOR followed by an optional explicit value, and then a message
1281
0
        if(msgPattern.partSubstringMatches(*part, other)) {
1282
0
            return partIndex;
1283
0
        }
1284
0
        if(MessagePattern::Part::hasNumericValue(msgPattern.getPartType(partIndex))) {
1285
0
            ++partIndex;  // skip the numeric-value part of "=1" etc.
1286
0
        }
1287
0
        partIndex=msgPattern.getLimitPartIndex(partIndex);
1288
0
    } while(++partIndex<count);
1289
0
    return 0;
1290
0
}
1291
1292
int32_t
1293
0
MessageFormat::findFirstPluralNumberArg(int32_t msgStart, const UnicodeString &argName) const {
1294
0
    for(int32_t i=msgStart+1;; ++i) {
1295
0
        const MessagePattern::Part &part=msgPattern.getPart(i);
1296
0
        UMessagePatternPartType type=part.getType();
1297
0
        if(type==UMSGPAT_PART_TYPE_MSG_LIMIT) {
1298
0
            return 0;
1299
0
        }
1300
0
        if(type==UMSGPAT_PART_TYPE_REPLACE_NUMBER) {
1301
0
            return -1;
1302
0
        }
1303
0
        if(type==UMSGPAT_PART_TYPE_ARG_START) {
1304
0
            UMessagePatternArgType argType=part.getArgType();
1305
0
            if(!argName.isEmpty() && (argType==UMSGPAT_ARG_TYPE_NONE || argType==UMSGPAT_ARG_TYPE_SIMPLE)) {
1306
                // ARG_NUMBER or ARG_NAME
1307
0
                if(msgPattern.partSubstringMatches(msgPattern.getPart(i+1), argName)) {
1308
0
                    return i;
1309
0
                }
1310
0
            }
1311
0
            i=msgPattern.getLimitPartIndex(i);
1312
0
        }
1313
0
    }
1314
0
}
1315
1316
0
void MessageFormat::copyObjects(const MessageFormat& that, UErrorCode& ec) {
1317
    // Deep copy pointer fields.
1318
    // We need not copy the formatAliases because they are re-filled
1319
    // in each getFormats() call.
1320
    // The defaultNumberFormat, defaultDateFormat and pluralProvider.rules
1321
    // also get created on demand.
1322
0
    argTypeCount = that.argTypeCount;
1323
0
    if (argTypeCount > 0) {
1324
0
        if (!allocateArgTypes(argTypeCount, ec)) {
1325
0
            return;
1326
0
        }
1327
0
        uprv_memcpy(argTypes, that.argTypes, argTypeCount * sizeof(argTypes[0]));
1328
0
    }
1329
0
    if (cachedFormatters != nullptr) {
1330
0
        uhash_removeAll(cachedFormatters);
1331
0
    }
1332
0
    if (customFormatArgStarts != nullptr) {
1333
0
        uhash_removeAll(customFormatArgStarts);
1334
0
    }
1335
0
    if (that.cachedFormatters) {
1336
0
        if (cachedFormatters == nullptr) {
1337
0
            cachedFormatters=uhash_open(uhash_hashLong, uhash_compareLong,
1338
0
                                        equalFormatsForHash, &ec);
1339
0
            if (U_FAILURE(ec)) {
1340
0
                return;
1341
0
            }
1342
0
            uhash_setValueDeleter(cachedFormatters, uprv_deleteUObject);
1343
0
        }
1344
1345
0
        const int32_t count = uhash_count(that.cachedFormatters);
1346
0
        int32_t pos, idx;
1347
0
        for (idx = 0, pos = UHASH_FIRST; idx < count && U_SUCCESS(ec); ++idx) {
1348
0
            const UHashElement* cur = uhash_nextElement(that.cachedFormatters, &pos);
1349
0
            Format* newFormat = static_cast<Format*>(cur->value.pointer)->clone();
1350
0
            if (newFormat) {
1351
0
                uhash_iput(cachedFormatters, cur->key.integer, newFormat, &ec);
1352
0
            } else {
1353
0
                ec = U_MEMORY_ALLOCATION_ERROR;
1354
0
                return;
1355
0
            }
1356
0
        }
1357
0
    }
1358
0
    if (that.customFormatArgStarts) {
1359
0
        if (customFormatArgStarts == nullptr) {
1360
0
            customFormatArgStarts=uhash_open(uhash_hashLong, uhash_compareLong,
1361
0
                                              nullptr, &ec);
1362
0
        }
1363
0
        const int32_t count = uhash_count(that.customFormatArgStarts);
1364
0
        int32_t pos, idx;
1365
0
        for (idx = 0, pos = UHASH_FIRST; idx < count && U_SUCCESS(ec); ++idx) {
1366
0
            const UHashElement* cur = uhash_nextElement(that.customFormatArgStarts, &pos);
1367
0
            uhash_iputi(customFormatArgStarts, cur->key.integer, cur->value.integer, &ec);
1368
0
        }
1369
0
    }
1370
0
}
1371
1372
1373
Formattable*
1374
MessageFormat::parse(int32_t msgStart,
1375
                     const UnicodeString& source,
1376
                     ParsePosition& pos,
1377
                     int32_t& count,
1378
0
                     UErrorCode& ec) const {
1379
0
    count = 0;
1380
0
    if (U_FAILURE(ec)) {
1381
0
        pos.setErrorIndex(pos.getIndex());
1382
0
        return nullptr;
1383
0
    }
1384
    // parse() does not work with named arguments.
1385
0
    if (msgPattern.hasNamedArguments()) {
1386
0
        ec = U_ARGUMENT_TYPE_MISMATCH;
1387
0
        pos.setErrorIndex(pos.getIndex());
1388
0
        return nullptr;
1389
0
    }
1390
0
    LocalArray<Formattable> resultArray(new Formattable[argTypeCount ? argTypeCount : 1]);
1391
0
    const UnicodeString& msgString=msgPattern.getPatternString();
1392
0
    int32_t prevIndex=msgPattern.getPart(msgStart).getLimit();
1393
0
    int32_t sourceOffset = pos.getIndex();
1394
0
    ParsePosition tempStatus(0);
1395
1396
0
    for(int32_t i=msgStart+1; ; ++i) {
1397
0
        UBool haveArgResult = false;
1398
0
        const MessagePattern::Part* part=&msgPattern.getPart(i);
1399
0
        const UMessagePatternPartType type=part->getType();
1400
0
        int32_t index=part->getIndex();
1401
        // Make sure the literal string matches.
1402
0
        int32_t len = index - prevIndex;
1403
0
        if (len == 0 || (0 == msgString.compare(prevIndex, len, source, sourceOffset, len))) {
1404
0
            sourceOffset += len;
1405
0
            prevIndex += len;
1406
0
        } else {
1407
0
            pos.setErrorIndex(sourceOffset);
1408
0
            return nullptr; // leave index as is to signal error
1409
0
        }
1410
0
        if(type==UMSGPAT_PART_TYPE_MSG_LIMIT) {
1411
            // Things went well! Done.
1412
0
            pos.setIndex(sourceOffset);
1413
0
            return resultArray.orphan();
1414
0
        }
1415
0
        if(type==UMSGPAT_PART_TYPE_SKIP_SYNTAX || type==UMSGPAT_PART_TYPE_INSERT_CHAR) {
1416
0
            prevIndex=part->getLimit();
1417
0
            continue;
1418
0
        }
1419
        // We do not support parsing Plural formats. (No REPLACE_NUMBER here.)
1420
        // Unexpected Part "part" in parsed message.
1421
0
        U_ASSERT(type==UMSGPAT_PART_TYPE_ARG_START);
1422
0
        int32_t argLimit=msgPattern.getLimitPartIndex(i);
1423
1424
0
        UMessagePatternArgType argType=part->getArgType();
1425
0
        part=&msgPattern.getPart(++i);
1426
0
        int32_t argNumber = part->getValue();  // ARG_NUMBER
1427
0
        UnicodeString key;
1428
0
        ++i;
1429
0
        const Format* formatter = nullptr;
1430
0
        Formattable& argResult = resultArray[argNumber];
1431
1432
0
        if(cachedFormatters!=nullptr && (formatter = getCachedFormatter(i - 2))!=nullptr) {
1433
            // Just parse using the formatter.
1434
0
            tempStatus.setIndex(sourceOffset);
1435
0
            formatter->parseObject(source, argResult, tempStatus);
1436
0
            if (tempStatus.getIndex() == sourceOffset) {
1437
0
                pos.setErrorIndex(sourceOffset);
1438
0
                return nullptr; // leave index as is to signal error
1439
0
            }
1440
0
            sourceOffset = tempStatus.getIndex();
1441
0
            haveArgResult = true;
1442
0
        } else if(
1443
0
            argType==UMSGPAT_ARG_TYPE_NONE || (cachedFormatters && uhash_iget(cachedFormatters, i -2))) {
1444
            // We arrive here if getCachedFormatter returned nullptr, but there was actually an element in the hash table.
1445
            // This can only happen if the hash table contained a DummyFormat, so the if statement above is a check
1446
            // for the hash table containing DummyFormat.
1447
1448
            // Match as a string.
1449
            // if at end, use longest possible match
1450
            // otherwise uses first match to intervening string
1451
            // does NOT recursively try all possibilities
1452
0
            UnicodeString stringAfterArgument = getLiteralStringUntilNextArgument(argLimit);
1453
0
            int32_t next;
1454
0
            if (!stringAfterArgument.isEmpty()) {
1455
0
                next = source.indexOf(stringAfterArgument, sourceOffset);
1456
0
            } else {
1457
0
                next = source.length();
1458
0
            }
1459
0
            if (next < 0) {
1460
0
                pos.setErrorIndex(sourceOffset);
1461
0
                return nullptr; // leave index as is to signal error
1462
0
            } else {
1463
0
                UnicodeString strValue(source.tempSubString(sourceOffset, next - sourceOffset));
1464
0
                UnicodeString compValue;
1465
0
                compValue.append(LEFT_CURLY_BRACE);
1466
0
                itos(argNumber, compValue);
1467
0
                compValue.append(RIGHT_CURLY_BRACE);
1468
0
                if (0 != strValue.compare(compValue)) {
1469
0
                    argResult.setString(strValue);
1470
0
                    haveArgResult = true;
1471
0
                }
1472
0
                sourceOffset = next;
1473
0
            }
1474
0
        } else if(argType==UMSGPAT_ARG_TYPE_CHOICE) {
1475
0
            tempStatus.setIndex(sourceOffset);
1476
0
            double choiceResult = ChoiceFormat::parseArgument(msgPattern, i, source, tempStatus);
1477
0
            if (tempStatus.getIndex() == sourceOffset) {
1478
0
                pos.setErrorIndex(sourceOffset);
1479
0
                return nullptr; // leave index as is to signal error
1480
0
            }
1481
0
            argResult.setDouble(choiceResult);
1482
0
            haveArgResult = true;
1483
0
            sourceOffset = tempStatus.getIndex();
1484
0
        } else if(UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType) || argType==UMSGPAT_ARG_TYPE_SELECT) {
1485
            // Parsing not supported.
1486
0
            ec = U_UNSUPPORTED_ERROR;
1487
0
            return nullptr;
1488
0
        } else {
1489
            // This should never happen.
1490
0
            ec = U_INTERNAL_PROGRAM_ERROR;
1491
0
            return nullptr;
1492
0
        }
1493
0
        if (haveArgResult && count <= argNumber) {
1494
0
            count = argNumber + 1;
1495
0
        }
1496
0
        prevIndex=msgPattern.getPart(argLimit).getLimit();
1497
0
        i=argLimit;
1498
0
    }
1499
0
}
1500
// -------------------------------------
1501
// Parses the source pattern and returns the Formattable objects array,
1502
// the array count and the ending parse position.  The caller of this method
1503
// owns the array.
1504
1505
Formattable*
1506
MessageFormat::parse(const UnicodeString& source,
1507
                     ParsePosition& pos,
1508
0
                     int32_t& count) const {
1509
0
    UErrorCode ec = U_ZERO_ERROR;
1510
0
    return parse(0, source, pos, count, ec);
1511
0
}
1512
1513
// -------------------------------------
1514
// Parses the source string and returns the array of
1515
// Formattable objects and the array count.  The caller
1516
// owns the returned array.
1517
1518
Formattable*
1519
MessageFormat::parse(const UnicodeString& source,
1520
                     int32_t& cnt,
1521
                     UErrorCode& success) const
1522
0
{
1523
0
    if (msgPattern.hasNamedArguments()) {
1524
0
        success = U_ARGUMENT_TYPE_MISMATCH;
1525
0
        return nullptr;
1526
0
    }
1527
0
    ParsePosition status(0);
1528
    // Calls the actual implementation method and starts
1529
    // from zero offset of the source text.
1530
0
    Formattable* result = parse(source, status, cnt);
1531
0
    if (status.getIndex() == 0) {
1532
0
        success = U_MESSAGE_PARSE_ERROR;
1533
0
        delete[] result;
1534
0
        return nullptr;
1535
0
    }
1536
0
    return result;
1537
0
}
1538
1539
// -------------------------------------
1540
// Parses the source text and copy into the result buffer.
1541
1542
void
1543
MessageFormat::parseObject( const UnicodeString& source,
1544
                            Formattable& result,
1545
                            ParsePosition& status) const
1546
0
{
1547
0
    int32_t cnt = 0;
1548
0
    Formattable* tmpResult = parse(source, status, cnt);
1549
0
    if (tmpResult != nullptr)
1550
0
        result.adoptArray(tmpResult, cnt);
1551
0
}
1552
1553
UnicodeString
1554
0
MessageFormat::autoQuoteApostrophe(const UnicodeString& pattern, UErrorCode& status) {
1555
0
    UnicodeString result;
1556
0
    if (U_SUCCESS(status)) {
1557
0
        int32_t plen = pattern.length();
1558
0
        const char16_t* pat = pattern.getBuffer();
1559
0
        int32_t blen = plen * 2 + 1; // space for null termination, convenience
1560
0
        char16_t* buf = result.getBuffer(blen);
1561
0
        if (buf == nullptr) {
1562
0
            status = U_MEMORY_ALLOCATION_ERROR;
1563
0
        } else {
1564
0
            int32_t len = umsg_autoQuoteApostrophe(pat, plen, buf, blen, &status);
1565
0
            result.releaseBuffer(U_SUCCESS(status) ? len : 0);
1566
0
        }
1567
0
    }
1568
0
    if (U_FAILURE(status)) {
1569
0
        result.setToBogus();
1570
0
    }
1571
0
    return result;
1572
0
}
1573
1574
// -------------------------------------
1575
1576
22.0k
static Format* makeRBNF(URBNFRuleSetTag tag, const Locale& locale, const UnicodeString& defaultRuleSet, UErrorCode& ec) {
1577
22.0k
    RuleBasedNumberFormat* fmt = new RuleBasedNumberFormat(tag, locale, ec);
1578
22.0k
    if (fmt == nullptr) {
1579
0
        ec = U_MEMORY_ALLOCATION_ERROR;
1580
22.0k
    } else if (U_SUCCESS(ec) && defaultRuleSet.length() > 0) {
1581
3.01k
        UErrorCode localStatus = U_ZERO_ERROR; // ignore unrecognized default rule set
1582
3.01k
        fmt->setDefaultRuleSet(defaultRuleSet, localStatus);
1583
3.01k
    }
1584
22.0k
    return fmt;
1585
22.0k
}
1586
1587
7.21k
void MessageFormat::cacheExplicitFormats(UErrorCode& status) {
1588
7.21k
    if (U_FAILURE(status)) {
1589
3.09k
        return;
1590
3.09k
    }
1591
1592
4.11k
    if (cachedFormatters != nullptr) {
1593
0
        uhash_removeAll(cachedFormatters);
1594
0
    }
1595
4.11k
    if (customFormatArgStarts != nullptr) {
1596
0
        uhash_removeAll(customFormatArgStarts);
1597
0
    }
1598
1599
    // The last two "parts" can at most be ARG_LIMIT and MSG_LIMIT
1600
    // which we need not examine.
1601
4.11k
    int32_t limit = msgPattern.countParts() - 2;
1602
4.11k
    argTypeCount = 0;
1603
    // We also need not look at the first two "parts"
1604
    // (at most MSG_START and ARG_START) in this loop.
1605
    // We determine the argTypeCount first so that we can allocateArgTypes
1606
    // so that the next loop can set argTypes[argNumber].
1607
    // (This is for the C API which needs the argTypes to read its va_arg list.)
1608
1.53M
    for (int32_t i = 2; i < limit && U_SUCCESS(status); ++i) {
1609
1.53M
        const MessagePattern::Part& part = msgPattern.getPart(i);
1610
1.53M
        if (part.getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) {
1611
304k
            const int argNumber = part.getValue();
1612
304k
            if (argNumber >= argTypeCount) {
1613
187
                argTypeCount = argNumber + 1;
1614
187
            }
1615
304k
        }
1616
1.53M
    }
1617
4.11k
    if (!allocateArgTypes(argTypeCount, status)) {
1618
0
        return;
1619
0
    }
1620
    // Set all argTypes to kObject, as a "none" value, for lack of any better value.
1621
    // We never use kObject for real arguments.
1622
    // We use it as "no argument yet" for the check for hasArgTypeConflicts.
1623
261k
    for (int32_t i = 0; i < argTypeCount; ++i) {
1624
256k
        argTypes[i] = Formattable::kObject;
1625
256k
    }
1626
4.11k
    hasArgTypeConflicts = false;
1627
1628
    // This loop starts at part index 1 because we do need to examine
1629
    // ARG_START parts. (But we can ignore the MSG_START.)
1630
1.17M
    for (int32_t i = 1; i < limit && U_SUCCESS(status); ++i) {
1631
1.17M
        const MessagePattern::Part* part = &msgPattern.getPart(i);
1632
1.17M
        if (part->getType() != UMSGPAT_PART_TYPE_ARG_START) {
1633
771k
            continue;
1634
771k
        }
1635
403k
        UMessagePatternArgType argType = part->getArgType();
1636
1637
403k
        int32_t argNumber = -1;
1638
403k
        part = &msgPattern.getPart(i + 1);
1639
403k
        if (part->getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) {
1640
304k
            argNumber = part->getValue();
1641
304k
        }
1642
403k
        Formattable::Type formattableType;
1643
1644
403k
        switch (argType) {
1645
328k
        case UMSGPAT_ARG_TYPE_NONE:
1646
328k
            formattableType = Formattable::kString;
1647
328k
            break;
1648
74.3k
        case UMSGPAT_ARG_TYPE_SIMPLE: {
1649
74.3k
            int32_t index = i;
1650
74.3k
            i += 2;
1651
74.3k
            UnicodeString explicitType = msgPattern.getSubstring(msgPattern.getPart(i++));
1652
74.3k
            UnicodeString style;
1653
74.3k
            if ((part = &msgPattern.getPart(i))->getType() == UMSGPAT_PART_TYPE_ARG_STYLE) {
1654
41.9k
                style = msgPattern.getSubstring(*part);
1655
41.9k
                ++i;
1656
41.9k
            }
1657
74.3k
            UParseError parseError;
1658
74.3k
            Format* formatter = createAppropriateFormat(explicitType, style, formattableType, parseError, status);
1659
74.3k
            setArgStartFormat(index, formatter, status);
1660
74.3k
            break;
1661
0
        }
1662
463
        case UMSGPAT_ARG_TYPE_CHOICE:
1663
463
        case UMSGPAT_ARG_TYPE_PLURAL:
1664
463
        case UMSGPAT_ARG_TYPE_SELECTORDINAL:
1665
463
            formattableType = Formattable::kDouble;
1666
463
            break;
1667
0
        case UMSGPAT_ARG_TYPE_SELECT:
1668
0
            formattableType = Formattable::kString;
1669
0
            break;
1670
0
        default:
1671
0
            status = U_INTERNAL_PROGRAM_ERROR;  // Should be unreachable.
1672
0
            formattableType = Formattable::kString;
1673
0
            break;
1674
403k
        }
1675
403k
        if (argNumber != -1) {
1676
304k
            if (argTypes[argNumber] != Formattable::kObject && argTypes[argNumber] != formattableType) {
1677
255
                hasArgTypeConflicts = true;
1678
255
            }
1679
304k
            argTypes[argNumber] = formattableType;
1680
304k
        }
1681
403k
    }
1682
4.11k
}
1683
1684
Format* MessageFormat::createAppropriateFormat(UnicodeString& type, UnicodeString& style,
1685
                                               Formattable::Type& formattableType, UParseError& parseError,
1686
74.3k
                                               UErrorCode& ec) {
1687
74.3k
    if (U_FAILURE(ec)) {
1688
0
        return nullptr;
1689
0
    }
1690
74.3k
    Format* fmt = nullptr;
1691
74.3k
    int32_t typeID, styleID;
1692
74.3k
    DateFormat::EStyle date_style;
1693
74.3k
    int32_t firstNonSpace;
1694
1695
74.3k
    switch (typeID = findKeyword(type, TYPE_IDS)) {
1696
0
    case 0: // number
1697
0
        formattableType = Formattable::kDouble;
1698
0
        switch (findKeyword(style, NUMBER_STYLE_IDS)) {
1699
0
        case 0: // default
1700
0
            fmt = NumberFormat::createInstance(fLocale, ec);
1701
0
            break;
1702
0
        case 1: // currency
1703
0
            fmt = NumberFormat::createCurrencyInstance(fLocale, ec);
1704
0
            break;
1705
0
        case 2: // percent
1706
0
            fmt = NumberFormat::createPercentInstance(fLocale, ec);
1707
0
            break;
1708
0
        case 3: // integer
1709
0
            formattableType = Formattable::kLong;
1710
0
            fmt = createIntegerFormat(fLocale, ec);
1711
0
            break;
1712
0
        default: // pattern or skeleton
1713
0
            firstNonSpace = PatternProps::skipWhiteSpace(style, 0);
1714
0
            if (style.compare(firstNonSpace, 2, u"::", 0, 2) == 0) {
1715
                // Skeleton
1716
0
                UnicodeString skeleton = style.tempSubString(firstNonSpace + 2);
1717
0
                fmt = number::NumberFormatter::forSkeleton(skeleton, ec).locale(fLocale).toFormat(ec);
1718
0
            } else {
1719
                // Pattern
1720
0
                fmt = NumberFormat::createInstance(fLocale, ec);
1721
0
                if (fmt) {
1722
0
                    auto* decfmt = dynamic_cast<DecimalFormat*>(fmt);
1723
0
                    if (decfmt != nullptr) {
1724
0
                        decfmt->applyPattern(style, parseError, ec);
1725
0
                    }
1726
0
                }
1727
0
            }
1728
0
            break;
1729
0
        }
1730
0
        break;
1731
1732
51.3k
    case 1: // date
1733
52.0k
    case 2: // time
1734
52.0k
        formattableType = Formattable::kDate;
1735
52.0k
        firstNonSpace = PatternProps::skipWhiteSpace(style, 0);
1736
52.0k
        if (style.compare(firstNonSpace, 2, u"::", 0, 2) == 0) {
1737
            // Skeleton
1738
25.9k
            UnicodeString skeleton = style.tempSubString(firstNonSpace + 2);
1739
25.9k
            fmt = DateFormat::createInstanceForSkeleton(skeleton, fLocale, ec);
1740
26.1k
        } else {
1741
            // Pattern
1742
26.1k
            styleID = findKeyword(style, DATE_STYLE_IDS);
1743
26.1k
            date_style = (styleID >= 0) ? DATE_STYLES[styleID] : DateFormat::kDefault;
1744
1745
26.1k
            if (typeID == 1) {
1746
25.4k
                fmt = DateFormat::createDateInstance(date_style, fLocale);
1747
25.4k
            } else {
1748
726
                fmt = DateFormat::createTimeInstance(date_style, fLocale);
1749
726
            }
1750
1751
26.1k
            if (styleID < 0 && fmt != nullptr) {
1752
12.1k
                SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(fmt);
1753
12.1k
                if (sdtfmt != nullptr) {
1754
12.1k
                    sdtfmt->applyPattern(style);
1755
12.1k
                }
1756
12.1k
            }
1757
26.1k
        }
1758
52.0k
        break;
1759
1760
0
    case 3: // spellout
1761
0
        formattableType = Formattable::kDouble;
1762
0
        fmt = makeRBNF(URBNF_SPELLOUT, fLocale, style, ec);
1763
0
        break;
1764
22.0k
    case 4: // ordinal
1765
22.0k
        formattableType = Formattable::kDouble;
1766
22.0k
        fmt = makeRBNF(URBNF_ORDINAL, fLocale, style, ec);
1767
22.0k
        break;
1768
0
    case 5: // duration
1769
0
        formattableType = Formattable::kDouble;
1770
0
        fmt = makeRBNF(URBNF_DURATION, fLocale, style, ec);
1771
0
        break;
1772
335
    default:
1773
335
        formattableType = Formattable::kString;
1774
335
        ec = U_ILLEGAL_ARGUMENT_ERROR;
1775
335
        break;
1776
74.3k
    }
1777
1778
74.3k
    return fmt;
1779
74.3k
}
1780
1781
1782
//-------------------------------------
1783
// Finds the string, s, in the string array, list.
1784
int32_t MessageFormat::findKeyword(const UnicodeString& s,
1785
                                   const char16_t * const *list)
1786
100k
{
1787
100k
    if (s.isEmpty()) {
1788
13.2k
        return 0; // default
1789
13.2k
    }
1790
1791
87.2k
    int32_t length = s.length();
1792
87.2k
    const char16_t *ps = PatternProps::trimWhiteSpace(s.getBuffer(), length);
1793
87.2k
    UnicodeString buffer(false, ps, length);
1794
    // Trims the space characters and turns all characters
1795
    // in s to lower case.
1796
87.2k
    buffer.toLower("");
1797
290k
    for (int32_t i = 0; list[i]; ++i) {
1798
278k
        if (!buffer.compare(list[i], u_strlen(list[i]))) {
1799
74.7k
            return i;
1800
74.7k
        }
1801
278k
    }
1802
12.4k
    return -1;
1803
87.2k
}
1804
1805
/**
1806
 * Convenience method that ought to be in NumberFormat
1807
 */
1808
NumberFormat*
1809
0
MessageFormat::createIntegerFormat(const Locale& locale, UErrorCode& status) const {
1810
0
    NumberFormat *temp = NumberFormat::createInstance(locale, status);
1811
0
    DecimalFormat *temp2;
1812
0
    if (temp != nullptr && (temp2 = dynamic_cast<DecimalFormat*>(temp)) != nullptr) {
1813
0
        temp2->setMaximumFractionDigits(0);
1814
0
        temp2->setDecimalSeparatorAlwaysShown(false);
1815
0
        temp2->setParseIntegerOnly(true);
1816
0
    }
1817
1818
0
    return temp;
1819
0
}
1820
1821
/**
1822
 * Return the default number format.  Used to format a numeric
1823
 * argument when subformats[i].format is nullptr.  Returns nullptr
1824
 * on failure.
1825
 *
1826
 * Semantically const but may modify *this.
1827
 */
1828
0
const NumberFormat* MessageFormat::getDefaultNumberFormat(UErrorCode& ec) const {
1829
0
    if (defaultNumberFormat == nullptr) {
1830
0
        MessageFormat* t = const_cast<MessageFormat*>(this);
1831
0
        t->defaultNumberFormat = NumberFormat::createInstance(fLocale, ec);
1832
0
        if (U_FAILURE(ec)) {
1833
0
            delete t->defaultNumberFormat;
1834
0
            t->defaultNumberFormat = nullptr;
1835
0
        } else if (t->defaultNumberFormat == nullptr) {
1836
0
            ec = U_MEMORY_ALLOCATION_ERROR;
1837
0
        }
1838
0
    }
1839
0
    return defaultNumberFormat;
1840
0
}
1841
1842
/**
1843
 * Return the default date format.  Used to format a date
1844
 * argument when subformats[i].format is nullptr.  Returns nullptr
1845
 * on failure.
1846
 *
1847
 * Semantically const but may modify *this.
1848
 */
1849
0
const DateFormat* MessageFormat::getDefaultDateFormat(UErrorCode& ec) const {
1850
0
    if (defaultDateFormat == nullptr) {
1851
0
        MessageFormat* t = const_cast<MessageFormat*>(this);
1852
0
        t->defaultDateFormat = DateFormat::createDateTimeInstance(DateFormat::kShort, DateFormat::kShort, fLocale);
1853
0
        if (t->defaultDateFormat == nullptr) {
1854
0
            ec = U_MEMORY_ALLOCATION_ERROR;
1855
0
        }
1856
0
    }
1857
0
    return defaultDateFormat;
1858
0
}
1859
1860
UBool
1861
0
MessageFormat::usesNamedArguments() const {
1862
0
    return msgPattern.hasNamedArguments();
1863
0
}
1864
1865
int32_t
1866
0
MessageFormat::getArgTypeCount() const {
1867
0
    return argTypeCount;
1868
0
}
1869
1870
0
UBool MessageFormat::equalFormats(const void* left, const void* right) {
1871
0
    return *static_cast<const Format*>(left) == *static_cast<const Format*>(right);
1872
0
}
1873
1874
1875
0
bool MessageFormat::DummyFormat::operator==(const Format&) const {
1876
0
    return true;
1877
0
}
1878
1879
0
MessageFormat::DummyFormat* MessageFormat::DummyFormat::clone() const {
1880
0
    return new DummyFormat();
1881
0
}
1882
1883
UnicodeString& MessageFormat::DummyFormat::format(const Formattable&,
1884
                          UnicodeString& appendTo,
1885
0
                          UErrorCode& status) const {
1886
0
    if (U_SUCCESS(status)) {
1887
0
        status = U_UNSUPPORTED_ERROR;
1888
0
    }
1889
0
    return appendTo;
1890
0
}
1891
1892
UnicodeString& MessageFormat::DummyFormat::format(const Formattable&,
1893
                          UnicodeString& appendTo,
1894
                          FieldPosition&,
1895
0
                          UErrorCode& status) const {
1896
0
    if (U_SUCCESS(status)) {
1897
0
        status = U_UNSUPPORTED_ERROR;
1898
0
    }
1899
0
    return appendTo;
1900
0
}
1901
1902
UnicodeString& MessageFormat::DummyFormat::format(const Formattable&,
1903
                          UnicodeString& appendTo,
1904
                          FieldPositionIterator*,
1905
0
                          UErrorCode& status) const {
1906
0
    if (U_SUCCESS(status)) {
1907
0
        status = U_UNSUPPORTED_ERROR;
1908
0
    }
1909
0
    return appendTo;
1910
0
}
1911
1912
void MessageFormat::DummyFormat::parseObject(const UnicodeString&,
1913
                                                     Formattable&,
1914
0
                                                     ParsePosition& ) const {
1915
0
}
1916
1917
1918
0
FormatNameEnumeration::FormatNameEnumeration(LocalPointer<UVector> nameList, UErrorCode& /*status*/) {
1919
0
    pos=0;
1920
0
    fFormatNames = std::move(nameList);
1921
0
}
1922
1923
const UnicodeString*
1924
0
FormatNameEnumeration::snext(UErrorCode& status) {
1925
0
    if (U_SUCCESS(status) && pos < fFormatNames->size()) {
1926
0
        return static_cast<const UnicodeString*>(fFormatNames->elementAt(pos++));
1927
0
    }
1928
0
    return nullptr;
1929
0
}
1930
1931
void
1932
0
FormatNameEnumeration::reset(UErrorCode& /*status*/) {
1933
0
    pos=0;
1934
0
}
1935
1936
int32_t
1937
0
FormatNameEnumeration::count(UErrorCode& /*status*/) const {
1938
0
    return (fFormatNames==nullptr) ? 0 : fFormatNames->size();
1939
0
}
1940
1941
0
FormatNameEnumeration::~FormatNameEnumeration() {
1942
0
}
1943
1944
MessageFormat::PluralSelectorProvider::PluralSelectorProvider(const MessageFormat &mf, UPluralType t)
1945
14.4k
        : msgFormat(mf), rules(nullptr), type(t) {
1946
14.4k
}
1947
1948
14.4k
MessageFormat::PluralSelectorProvider::~PluralSelectorProvider() {
1949
14.4k
    delete rules;
1950
14.4k
}
1951
1952
UnicodeString MessageFormat::PluralSelectorProvider::select(void *ctx, double number,
1953
0
                                                            UErrorCode& ec) const {
1954
0
    if (U_FAILURE(ec)) {
1955
0
        return UnicodeString(false, OTHER_STRING, 5);
1956
0
    }
1957
0
    MessageFormat::PluralSelectorProvider* t = const_cast<MessageFormat::PluralSelectorProvider*>(this);
1958
0
    if(rules == nullptr) {
1959
0
        t->rules = PluralRules::forLocale(msgFormat.fLocale, type, ec);
1960
0
        if (U_FAILURE(ec)) {
1961
0
            return UnicodeString(false, OTHER_STRING, 5);
1962
0
        }
1963
0
    }
1964
    // Select a sub-message according to how the number is formatted,
1965
    // which is specified in the selected sub-message.
1966
    // We avoid this circle by looking at how
1967
    // the number is formatted in the "other" sub-message
1968
    // which must always be present and usually contains the number.
1969
    // Message authors should be consistent across sub-messages.
1970
0
    PluralSelectorContext &context = *static_cast<PluralSelectorContext *>(ctx);
1971
0
    int32_t otherIndex = msgFormat.findOtherSubMessage(context.startIndex);
1972
0
    context.numberArgIndex = msgFormat.findFirstPluralNumberArg(otherIndex, context.argName);
1973
0
    if(context.numberArgIndex > 0 && msgFormat.cachedFormatters != nullptr) {
1974
0
        context.formatter =
1975
0
            static_cast<const Format*>(uhash_iget(msgFormat.cachedFormatters, context.numberArgIndex));
1976
0
    }
1977
0
    if(context.formatter == nullptr) {
1978
0
        context.formatter = msgFormat.getDefaultNumberFormat(ec);
1979
0
        context.forReplaceNumber = true;
1980
0
    }
1981
0
    if (context.number.getDouble(ec) != number) {
1982
0
        ec = U_INTERNAL_PROGRAM_ERROR;
1983
0
        return UnicodeString(false, OTHER_STRING, 5);
1984
0
    }
1985
0
    context.formatter->format(context.number, context.numberString, ec);
1986
0
    const auto* decFmt = dynamic_cast<const DecimalFormat*>(context.formatter);
1987
0
    if(decFmt != nullptr) {
1988
0
        number::impl::DecimalQuantity dq;
1989
0
        decFmt->formatToDecimalQuantity(context.number, dq, ec);
1990
0
        if (U_FAILURE(ec)) {
1991
0
            return UnicodeString(false, OTHER_STRING, 5);
1992
0
        }
1993
0
        return rules->select(dq);
1994
0
    } else {
1995
0
        return rules->select(number);
1996
0
    }
1997
0
}
1998
1999
0
void MessageFormat::PluralSelectorProvider::reset() {
2000
0
    delete rules;
2001
0
    rules = nullptr;
2002
0
}
2003
2004
2005
U_NAMESPACE_END
2006
2007
#endif /* #if !UCONFIG_NO_FORMATTING */
2008
2009
//eof