Coverage Report

Created: 2026-08-14 06:11

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
8.36k
: fLocale(Locale::getDefault()),  // Uses the default locale
236
8.36k
  msgPattern(success),
237
8.36k
  formatAliases(nullptr),
238
8.36k
  formatAliasesCapacity(0),
239
8.36k
  argTypes(nullptr),
240
8.36k
  argTypeCount(0),
241
8.36k
  argTypeCapacity(0),
242
8.36k
  hasArgTypeConflicts(false),
243
8.36k
  defaultNumberFormat(nullptr),
244
8.36k
  defaultDateFormat(nullptr),
245
8.36k
  cachedFormatters(nullptr),
246
8.36k
  customFormatArgStarts(nullptr),
247
8.36k
  pluralProvider(*this, UPLURAL_TYPE_CARDINAL),
248
8.36k
  ordinalProvider(*this, UPLURAL_TYPE_ORDINAL)
249
8.36k
{
250
8.36k
    setLocaleIDs(fLocale.getName(), fLocale.getName());
251
8.36k
    applyPattern(pattern, success);
252
8.36k
}
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
8.36k
{
327
8.36k
    uhash_close(cachedFormatters);
328
8.36k
    uhash_close(customFormatArgStarts);
329
330
8.36k
    uprv_free(argTypes);
331
8.36k
    uprv_free(formatAliases);
332
8.36k
    delete defaultNumberFormat;
333
8.36k
    delete defaultDateFormat;
334
8.36k
}
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.08k
UBool MessageFormat::allocateArgTypes(int32_t capacity, UErrorCode& status) {
347
4.08k
    if (U_FAILURE(status)) {
348
0
        return false;
349
0
    }
350
4.08k
    if (argTypeCapacity >= capacity) {
351
3.94k
        return true;
352
3.94k
    }
353
144
    if (capacity < DEFAULT_INITIAL_CAPACITY) {
354
94
        capacity = DEFAULT_INITIAL_CAPACITY;
355
94
    } else if (capacity < 2*argTypeCapacity) {
356
0
        capacity = 2*argTypeCapacity;
357
0
    }
358
144
    Formattable::Type* a = static_cast<Formattable::Type*>(
359
144
            uprv_realloc(argTypes, sizeof(*argTypes) * capacity));
360
144
    if (a == nullptr) {
361
0
        status = U_MEMORY_ALLOCATION_ERROR;
362
0
        return false;
363
0
    }
364
144
    argTypes = a;
365
144
    argTypeCapacity = capacity;
366
144
    return true;
367
144
}
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
8.36k
{
476
8.36k
    UParseError parseError;
477
8.36k
    applyPattern(newPattern,parseError,status);
478
8.36k
}
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
8.36k
{
489
8.36k
    if(U_FAILURE(ec)) {
490
0
        return;
491
0
    }
492
8.36k
    msgPattern.parse(pattern, &parseError, ec);
493
8.36k
    cacheExplicitFormats(ec);
494
495
8.36k
    if (U_FAILURE(ec)) {
496
4.60k
        resetPattern();
497
4.60k
    }
498
8.36k
}
499
500
4.60k
void MessageFormat::resetPattern() {
501
4.60k
    msgPattern.clear();
502
4.60k
    uhash_close(cachedFormatters);
503
4.60k
    cachedFormatters = nullptr;
504
4.60k
    uhash_close(customFormatArgStarts);
505
4.60k
    customFormatArgStarts = nullptr;
506
4.60k
    argTypeCount = 0;
507
4.60k
    hasArgTypeConflicts = false;
508
4.60k
}
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
76.5k
                                      UErrorCode& status) {
554
76.5k
    if (U_FAILURE(status)) {
555
325
        delete formatter;
556
325
        return;
557
325
    }
558
76.1k
    if (cachedFormatters == nullptr) {
559
2.61k
        cachedFormatters=uhash_open(uhash_hashLong, uhash_compareLong,
560
2.61k
                                    equalFormatsForHash, &status);
561
2.61k
        if (U_FAILURE(status)) {
562
0
            delete formatter;
563
0
            return;
564
0
        }
565
2.61k
        uhash_setValueDeleter(cachedFormatters, uprv_deleteUObject);
566
2.61k
    }
567
76.1k
    if (formatter == nullptr) {
568
0
        formatter = new DummyFormat();
569
0
    }
570
76.1k
    uhash_iput(cachedFormatters, argStart, formatter, &status);
571
76.1k
}
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
4.13k
        UErrorCode localStatus = U_ZERO_ERROR; // ignore unrecognized default rule set
1582
4.13k
        fmt->setDefaultRuleSet(defaultRuleSet, localStatus);
1583
4.13k
    }
1584
22.0k
    return fmt;
1585
22.0k
}
1586
1587
8.36k
void MessageFormat::cacheExplicitFormats(UErrorCode& status) {
1588
8.36k
    if (U_FAILURE(status)) {
1589
4.28k
        return;
1590
4.28k
    }
1591
1592
4.08k
    if (cachedFormatters != nullptr) {
1593
0
        uhash_removeAll(cachedFormatters);
1594
0
    }
1595
4.08k
    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.08k
    int32_t limit = msgPattern.countParts() - 2;
1602
4.08k
    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.06M
    for (int32_t i = 2; i < limit && U_SUCCESS(status); ++i) {
1609
1.06M
        const MessagePattern::Part& part = msgPattern.getPart(i);
1610
1.06M
        if (part.getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) {
1611
170k
            const int argNumber = part.getValue();
1612
170k
            if (argNumber >= argTypeCount) {
1613
214
                argTypeCount = argNumber + 1;
1614
214
            }
1615
170k
        }
1616
1.06M
    }
1617
4.08k
    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
257k
    for (int32_t i = 0; i < argTypeCount; ++i) {
1624
253k
        argTypes[i] = Formattable::kObject;
1625
253k
    }
1626
4.08k
    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
721k
    for (int32_t i = 1; i < limit && U_SUCCESS(status); ++i) {
1631
717k
        const MessagePattern::Part* part = &msgPattern.getPart(i);
1632
717k
        if (part->getType() != UMSGPAT_PART_TYPE_ARG_START) {
1633
458k
            continue;
1634
458k
        }
1635
259k
        UMessagePatternArgType argType = part->getArgType();
1636
1637
259k
        int32_t argNumber = -1;
1638
259k
        part = &msgPattern.getPart(i + 1);
1639
259k
        if (part->getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) {
1640
170k
            argNumber = part->getValue();
1641
170k
        }
1642
259k
        Formattable::Type formattableType;
1643
1644
259k
        switch (argType) {
1645
182k
        case UMSGPAT_ARG_TYPE_NONE:
1646
182k
            formattableType = Formattable::kString;
1647
182k
            break;
1648
76.5k
        case UMSGPAT_ARG_TYPE_SIMPLE: {
1649
76.5k
            int32_t index = i;
1650
76.5k
            i += 2;
1651
76.5k
            UnicodeString explicitType = msgPattern.getSubstring(msgPattern.getPart(i++));
1652
76.5k
            UnicodeString style;
1653
76.5k
            if ((part = &msgPattern.getPart(i))->getType() == UMSGPAT_PART_TYPE_ARG_STYLE) {
1654
51.7k
                style = msgPattern.getSubstring(*part);
1655
51.7k
                ++i;
1656
51.7k
            }
1657
76.5k
            UParseError parseError;
1658
76.5k
            Format* formatter = createAppropriateFormat(explicitType, style, formattableType, parseError, status);
1659
76.5k
            setArgStartFormat(index, formatter, status);
1660
76.5k
            break;
1661
0
        }
1662
515
        case UMSGPAT_ARG_TYPE_CHOICE:
1663
515
        case UMSGPAT_ARG_TYPE_PLURAL:
1664
515
        case UMSGPAT_ARG_TYPE_SELECTORDINAL:
1665
515
            formattableType = Formattable::kDouble;
1666
515
            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
259k
        }
1675
259k
        if (argNumber != -1) {
1676
170k
            if (argTypes[argNumber] != Formattable::kObject && argTypes[argNumber] != formattableType) {
1677
195
                hasArgTypeConflicts = true;
1678
195
            }
1679
170k
            argTypes[argNumber] = formattableType;
1680
170k
        }
1681
259k
    }
1682
4.08k
}
1683
1684
Format* MessageFormat::createAppropriateFormat(UnicodeString& type, UnicodeString& style,
1685
                                               Formattable::Type& formattableType, UParseError& parseError,
1686
76.5k
                                               UErrorCode& ec) {
1687
76.5k
    if (U_FAILURE(ec)) {
1688
0
        return nullptr;
1689
0
    }
1690
76.5k
    Format* fmt = nullptr;
1691
76.5k
    int32_t typeID, styleID;
1692
76.5k
    DateFormat::EStyle date_style;
1693
76.5k
    int32_t firstNonSpace;
1694
1695
76.5k
    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
52.6k
    case 1: // date
1733
54.1k
    case 2: // time
1734
54.1k
        formattableType = Formattable::kDate;
1735
54.1k
        firstNonSpace = PatternProps::skipWhiteSpace(style, 0);
1736
54.1k
        if (style.compare(firstNonSpace, 2, u"::", 0, 2) == 0) {
1737
            // Skeleton
1738
35.5k
            UnicodeString skeleton = style.tempSubString(firstNonSpace + 2);
1739
35.5k
            fmt = DateFormat::createInstanceForSkeleton(skeleton, fLocale, ec);
1740
35.5k
        } else {
1741
            // Pattern
1742
18.6k
            styleID = findKeyword(style, DATE_STYLE_IDS);
1743
18.6k
            date_style = (styleID >= 0) ? DATE_STYLES[styleID] : DateFormat::kDefault;
1744
1745
18.6k
            if (typeID == 1) {
1746
17.1k
                fmt = DateFormat::createDateInstance(date_style, fLocale);
1747
17.1k
            } else {
1748
1.48k
                fmt = DateFormat::createTimeInstance(date_style, fLocale);
1749
1.48k
            }
1750
1751
18.6k
            if (styleID < 0 && fmt != nullptr) {
1752
11.3k
                SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(fmt);
1753
11.3k
                if (sdtfmt != nullptr) {
1754
11.3k
                    sdtfmt->applyPattern(style);
1755
11.3k
                }
1756
11.3k
            }
1757
18.6k
        }
1758
54.1k
        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
325
    default:
1773
325
        formattableType = Formattable::kString;
1774
325
        ec = U_ILLEGAL_ARGUMENT_ERROR;
1775
325
        break;
1776
76.5k
    }
1777
1778
76.5k
    return fmt;
1779
76.5k
}
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
95.1k
{
1787
95.1k
    if (s.isEmpty()) {
1788
6.66k
        return 0; // default
1789
6.66k
    }
1790
1791
88.4k
    int32_t length = s.length();
1792
88.4k
    const char16_t *ps = PatternProps::trimWhiteSpace(s.getBuffer(), length);
1793
88.4k
    UnicodeString buffer(false, ps, length);
1794
    // Trims the space characters and turns all characters
1795
    // in s to lower case.
1796
88.4k
    buffer.toLower("");
1797
290k
    for (int32_t i = 0; list[i]; ++i) {
1798
279k
        if (!buffer.compare(list[i], u_strlen(list[i]))) {
1799
76.8k
            return i;
1800
76.8k
        }
1801
279k
    }
1802
11.6k
    return -1;
1803
88.4k
}
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
16.7k
        : msgFormat(mf), rules(nullptr), type(t) {
1946
16.7k
}
1947
1948
16.7k
MessageFormat::PluralSelectorProvider::~PluralSelectorProvider() {
1949
16.7k
    delete rules;
1950
16.7k
}
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