• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define SINGLE_QUOTE      ((char16_t)0x0027)
59 #define COMMA             ((char16_t)0x002C)
60 #define LEFT_CURLY_BRACE  ((char16_t)0x007B)
61 #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
equalFormatsForHash(const UHashTok key1,const UHashTok key2)160 static UBool U_CALLCONV equalFormatsForHash(const UHashTok key1,
161                                             const UHashTok key2) {
162     return icu::MessageFormat::equalFormats(key1.pointer, key2.pointer);
163 }
164 
165 U_CDECL_END
166 
167 U_NAMESPACE_BEGIN
168 
169 // -------------------------------------
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MessageFormat)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 static UnicodeString& itos(int32_t i, UnicodeString& appendTo) {
180     char16_t temp[16];
181     uprv_itou(temp,16,i,10,0); // 10 == radix
182     appendTo.append(temp, -1);
183     return appendTo;
184 }
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:
AppendableWrapper(Appendable & appendable)191     AppendableWrapper(Appendable& appendable) : app(appendable), len(0) {
192     }
append(const UnicodeString & s)193     void append(const UnicodeString& s) {
194         app.appendString(s.getBuffer(), s.length());
195         len += s.length();
196     }
append(const char16_t * s,const int32_t sLength)197     void append(const char16_t* s, const int32_t sLength) {
198         app.appendString(s, sLength);
199         len += sLength;
200     }
append(const UnicodeString & s,int32_t start,int32_t length)201     void append(const UnicodeString& s, int32_t start, int32_t length) {
202         append(s.tempSubString(start, length));
203     }
formatAndAppend(const Format * formatter,const Formattable & arg,UErrorCode & ec)204     void formatAndAppend(const Format* formatter, const Formattable& arg, UErrorCode& ec) {
205         UnicodeString s;
206         formatter->format(arg, s, ec);
207         if (U_SUCCESS(ec)) {
208             append(s);
209         }
210     }
formatAndAppend(const Format * formatter,const Formattable & arg,const UnicodeString & argString,UErrorCode & ec)211     void formatAndAppend(const Format* formatter, const Formattable& arg,
212                          const UnicodeString &argString, UErrorCode& ec) {
213         if (!argString.isEmpty()) {
214             if (U_SUCCESS(ec)) {
215                 append(argString);
216             }
217         } else {
218             formatAndAppend(formatter, arg, ec);
219         }
220     }
length()221     int32_t length() {
222         return len;
223     }
224 private:
225     Appendable& app;
226     int32_t len;
227 };
228 
229 
230 // -------------------------------------
231 // Creates a MessageFormat instance based on the pattern.
232 
MessageFormat(const UnicodeString & pattern,UErrorCode & success)233 MessageFormat::MessageFormat(const UnicodeString& pattern,
234                              UErrorCode& success)
235 : fLocale(Locale::getDefault()),  // Uses the default locale
236   msgPattern(success),
237   formatAliases(nullptr),
238   formatAliasesCapacity(0),
239   argTypes(nullptr),
240   argTypeCount(0),
241   argTypeCapacity(0),
242   hasArgTypeConflicts(false),
243   defaultNumberFormat(nullptr),
244   defaultDateFormat(nullptr),
245   cachedFormatters(nullptr),
246   customFormatArgStarts(nullptr),
247   pluralProvider(*this, UPLURAL_TYPE_CARDINAL),
248   ordinalProvider(*this, UPLURAL_TYPE_ORDINAL)
249 {
250     setLocaleIDs(fLocale.getName(), fLocale.getName());
251     applyPattern(pattern, success);
252 }
253 
MessageFormat(const UnicodeString & pattern,const Locale & newLocale,UErrorCode & success)254 MessageFormat::MessageFormat(const UnicodeString& pattern,
255                              const Locale& newLocale,
256                              UErrorCode& success)
257 : fLocale(newLocale),
258   msgPattern(success),
259   formatAliases(nullptr),
260   formatAliasesCapacity(0),
261   argTypes(nullptr),
262   argTypeCount(0),
263   argTypeCapacity(0),
264   hasArgTypeConflicts(false),
265   defaultNumberFormat(nullptr),
266   defaultDateFormat(nullptr),
267   cachedFormatters(nullptr),
268   customFormatArgStarts(nullptr),
269   pluralProvider(*this, UPLURAL_TYPE_CARDINAL),
270   ordinalProvider(*this, UPLURAL_TYPE_ORDINAL)
271 {
272     setLocaleIDs(fLocale.getName(), fLocale.getName());
273     applyPattern(pattern, success);
274 }
275 
MessageFormat(const UnicodeString & pattern,const Locale & newLocale,UParseError & parseError,UErrorCode & success)276 MessageFormat::MessageFormat(const UnicodeString& pattern,
277                              const Locale& newLocale,
278                              UParseError& parseError,
279                              UErrorCode& success)
280 : fLocale(newLocale),
281   msgPattern(success),
282   formatAliases(nullptr),
283   formatAliasesCapacity(0),
284   argTypes(nullptr),
285   argTypeCount(0),
286   argTypeCapacity(0),
287   hasArgTypeConflicts(false),
288   defaultNumberFormat(nullptr),
289   defaultDateFormat(nullptr),
290   cachedFormatters(nullptr),
291   customFormatArgStarts(nullptr),
292   pluralProvider(*this, UPLURAL_TYPE_CARDINAL),
293   ordinalProvider(*this, UPLURAL_TYPE_ORDINAL)
294 {
295     setLocaleIDs(fLocale.getName(), fLocale.getName());
296     applyPattern(pattern, parseError, success);
297 }
298 
MessageFormat(const MessageFormat & that)299 MessageFormat::MessageFormat(const MessageFormat& that)
300 :
301   Format(that),
302   fLocale(that.fLocale),
303   msgPattern(that.msgPattern),
304   formatAliases(nullptr),
305   formatAliasesCapacity(0),
306   argTypes(nullptr),
307   argTypeCount(0),
308   argTypeCapacity(0),
309   hasArgTypeConflicts(that.hasArgTypeConflicts),
310   defaultNumberFormat(nullptr),
311   defaultDateFormat(nullptr),
312   cachedFormatters(nullptr),
313   customFormatArgStarts(nullptr),
314   pluralProvider(*this, UPLURAL_TYPE_CARDINAL),
315   ordinalProvider(*this, UPLURAL_TYPE_ORDINAL)
316 {
317     // This will take care of creating the hash tables (since they are nullptr).
318     UErrorCode ec = U_ZERO_ERROR;
319     copyObjects(that, ec);
320     if (U_FAILURE(ec)) {
321         resetPattern();
322     }
323 }
324 
~MessageFormat()325 MessageFormat::~MessageFormat()
326 {
327     uhash_close(cachedFormatters);
328     uhash_close(customFormatArgStarts);
329 
330     uprv_free(argTypes);
331     uprv_free(formatAliases);
332     delete defaultNumberFormat;
333     delete defaultDateFormat;
334 }
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  */
allocateArgTypes(int32_t capacity,UErrorCode & status)346 UBool MessageFormat::allocateArgTypes(int32_t capacity, UErrorCode& status) {
347     if (U_FAILURE(status)) {
348         return false;
349     }
350     if (argTypeCapacity >= capacity) {
351         return true;
352     }
353     if (capacity < DEFAULT_INITIAL_CAPACITY) {
354         capacity = DEFAULT_INITIAL_CAPACITY;
355     } else if (capacity < 2*argTypeCapacity) {
356         capacity = 2*argTypeCapacity;
357     }
358     Formattable::Type* a = (Formattable::Type*)
359             uprv_realloc(argTypes, sizeof(*argTypes) * capacity);
360     if (a == nullptr) {
361         status = U_MEMORY_ALLOCATION_ERROR;
362         return false;
363     }
364     argTypes = a;
365     argTypeCapacity = capacity;
366     return true;
367 }
368 
369 // -------------------------------------
370 // assignment operator
371 
372 const MessageFormat&
operator =(const MessageFormat & that)373 MessageFormat::operator=(const MessageFormat& that)
374 {
375     if (this != &that) {
376         // Calls the super class for assignment first.
377         Format::operator=(that);
378 
379         setLocale(that.fLocale);
380         msgPattern = that.msgPattern;
381         hasArgTypeConflicts = that.hasArgTypeConflicts;
382 
383         UErrorCode ec = U_ZERO_ERROR;
384         copyObjects(that, ec);
385         if (U_FAILURE(ec)) {
386             resetPattern();
387         }
388     }
389     return *this;
390 }
391 
392 bool
operator ==(const Format & rhs) const393 MessageFormat::operator==(const Format& rhs) const
394 {
395     if (this == &rhs) return true;
396 
397     // Check class ID before checking MessageFormat members
398     if (!Format::operator==(rhs)) return false;
399 
400     const MessageFormat& that = static_cast<const MessageFormat&>(rhs);
401     if (msgPattern != that.msgPattern ||
402         fLocale != that.fLocale) {
403         return false;
404     }
405 
406     // Compare hashtables.
407     if ((customFormatArgStarts == nullptr) != (that.customFormatArgStarts == nullptr)) {
408         return false;
409     }
410     if (customFormatArgStarts == nullptr) {
411         return true;
412     }
413 
414     UErrorCode ec = U_ZERO_ERROR;
415     const int32_t count = uhash_count(customFormatArgStarts);
416     const int32_t rhs_count = uhash_count(that.customFormatArgStarts);
417     if (count != rhs_count) {
418         return false;
419     }
420     int32_t idx = 0, rhs_idx = 0, pos = UHASH_FIRST, rhs_pos = UHASH_FIRST;
421     for (; idx < count && rhs_idx < rhs_count && U_SUCCESS(ec); ++idx, ++rhs_idx) {
422         const UHashElement* cur = uhash_nextElement(customFormatArgStarts, &pos);
423         const UHashElement* rhs_cur = uhash_nextElement(that.customFormatArgStarts, &rhs_pos);
424         if (cur->key.integer != rhs_cur->key.integer) {
425             return false;
426         }
427         const Format* format = (const Format*)uhash_iget(cachedFormatters, cur->key.integer);
428         const Format* rhs_format = (const Format*)uhash_iget(that.cachedFormatters, rhs_cur->key.integer);
429         if (*format != *rhs_format) {
430             return false;
431         }
432     }
433     return true;
434 }
435 
436 // -------------------------------------
437 // Creates a copy of this MessageFormat, the caller owns the copy.
438 
439 MessageFormat*
clone() const440 MessageFormat::clone() const
441 {
442     return new MessageFormat(*this);
443 }
444 
445 // -------------------------------------
446 // Sets the locale of this MessageFormat object to theLocale.
447 
448 void
setLocale(const Locale & theLocale)449 MessageFormat::setLocale(const Locale& theLocale)
450 {
451     if (fLocale != theLocale) {
452         delete defaultNumberFormat;
453         defaultNumberFormat = nullptr;
454         delete defaultDateFormat;
455         defaultDateFormat = nullptr;
456         fLocale = theLocale;
457         setLocaleIDs(fLocale.getName(), fLocale.getName());
458         pluralProvider.reset();
459         ordinalProvider.reset();
460     }
461 }
462 
463 // -------------------------------------
464 // Gets the locale of this MessageFormat object.
465 
466 const Locale&
getLocale() const467 MessageFormat::getLocale() const
468 {
469     return fLocale;
470 }
471 
472 void
applyPattern(const UnicodeString & newPattern,UErrorCode & status)473 MessageFormat::applyPattern(const UnicodeString& newPattern,
474                             UErrorCode& status)
475 {
476     UParseError parseError;
477     applyPattern(newPattern,parseError,status);
478 }
479 
480 
481 // -------------------------------------
482 // Applies the new pattern and returns an error if the pattern
483 // is not correct.
484 void
applyPattern(const UnicodeString & pattern,UParseError & parseError,UErrorCode & ec)485 MessageFormat::applyPattern(const UnicodeString& pattern,
486                             UParseError& parseError,
487                             UErrorCode& ec)
488 {
489     if(U_FAILURE(ec)) {
490         return;
491     }
492     msgPattern.parse(pattern, &parseError, ec);
493     cacheExplicitFormats(ec);
494 
495     if (U_FAILURE(ec)) {
496         resetPattern();
497     }
498 }
499 
resetPattern()500 void MessageFormat::resetPattern() {
501     msgPattern.clear();
502     uhash_close(cachedFormatters);
503     cachedFormatters = nullptr;
504     uhash_close(customFormatArgStarts);
505     customFormatArgStarts = nullptr;
506     argTypeCount = 0;
507     hasArgTypeConflicts = false;
508 }
509 
510 void
applyPattern(const UnicodeString & pattern,UMessagePatternApostropheMode aposMode,UParseError * parseError,UErrorCode & status)511 MessageFormat::applyPattern(const UnicodeString& pattern,
512                             UMessagePatternApostropheMode aposMode,
513                             UParseError* parseError,
514                             UErrorCode& status) {
515     if (aposMode != msgPattern.getApostropheMode()) {
516         msgPattern.clearPatternAndSetApostropheMode(aposMode);
517     }
518     UParseError tempParseError;
519     applyPattern(pattern, (parseError == nullptr) ? tempParseError : *parseError, status);
520 }
521 
522 // -------------------------------------
523 // Converts this MessageFormat instance to a pattern.
524 
525 UnicodeString&
toPattern(UnicodeString & appendTo) const526 MessageFormat::toPattern(UnicodeString& appendTo) const {
527     if ((customFormatArgStarts != nullptr && 0 != uhash_count(customFormatArgStarts)) ||
528         0 == msgPattern.countParts()
529     ) {
530         appendTo.setToBogus();
531         return appendTo;
532     }
533     return appendTo.append(msgPattern.getPatternString());
534 }
535 
nextTopLevelArgStart(int32_t partIndex) const536 int32_t MessageFormat::nextTopLevelArgStart(int32_t partIndex) const {
537     if (partIndex != 0) {
538         partIndex = msgPattern.getLimitPartIndex(partIndex);
539     }
540     for (;;) {
541         UMessagePatternPartType type = msgPattern.getPartType(++partIndex);
542         if (type == UMSGPAT_PART_TYPE_ARG_START) {
543             return partIndex;
544         }
545         if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) {
546             return -1;
547         }
548     }
549 }
550 
setArgStartFormat(int32_t argStart,Format * formatter,UErrorCode & status)551 void MessageFormat::setArgStartFormat(int32_t argStart,
552                                       Format* formatter,
553                                       UErrorCode& status) {
554     if (U_FAILURE(status)) {
555         delete formatter;
556         return;
557     }
558     if (cachedFormatters == nullptr) {
559         cachedFormatters=uhash_open(uhash_hashLong, uhash_compareLong,
560                                     equalFormatsForHash, &status);
561         if (U_FAILURE(status)) {
562             delete formatter;
563             return;
564         }
565         uhash_setValueDeleter(cachedFormatters, uprv_deleteUObject);
566     }
567     if (formatter == nullptr) {
568         formatter = new DummyFormat();
569     }
570     uhash_iput(cachedFormatters, argStart, formatter, &status);
571 }
572 
573 
argNameMatches(int32_t partIndex,const UnicodeString & argName,int32_t argNumber)574 UBool MessageFormat::argNameMatches(int32_t partIndex, const UnicodeString& argName, int32_t argNumber) {
575     const MessagePattern::Part& part = msgPattern.getPart(partIndex);
576     return part.getType() == UMSGPAT_PART_TYPE_ARG_NAME ?
577         msgPattern.partSubstringMatches(part, argName) :
578         part.getValue() == argNumber;  // ARG_NUMBER
579 }
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.
setCustomArgStartFormat(int32_t argStart,Format * formatter,UErrorCode & status)583 void MessageFormat::setCustomArgStartFormat(int32_t argStart,
584                                             Format* formatter,
585                                             UErrorCode& status) {
586     setArgStartFormat(argStart, formatter, status);
587     if (customFormatArgStarts == nullptr) {
588         customFormatArgStarts=uhash_open(uhash_hashLong, uhash_compareLong,
589                                          nullptr, &status);
590     }
591     uhash_iputi(customFormatArgStarts, argStart, 1, &status);
592 }
593 
getCachedFormatter(int32_t argumentNumber) const594 Format* MessageFormat::getCachedFormatter(int32_t argumentNumber) const {
595     if (cachedFormatters == nullptr) {
596         return nullptr;
597     }
598     void* ptr = uhash_iget(cachedFormatters, argumentNumber);
599     if (ptr != nullptr && dynamic_cast<DummyFormat*>((Format*)ptr) == nullptr) {
600         return (Format*) ptr;
601     } else {
602         // Not cached, or a DummyFormat representing setFormat(nullptr).
603         return nullptr;
604     }
605 }
606 
607 // -------------------------------------
608 // Adopts the new formats array and updates the array count.
609 // This MessageFormat instance owns the new formats.
610 void
adoptFormats(Format ** newFormats,int32_t count)611 MessageFormat::adoptFormats(Format** newFormats,
612                             int32_t count) {
613     if (newFormats == nullptr || count < 0) {
614         return;
615     }
616     // Throw away any cached formatters.
617     if (cachedFormatters != nullptr) {
618         uhash_removeAll(cachedFormatters);
619     }
620     if (customFormatArgStarts != nullptr) {
621         uhash_removeAll(customFormatArgStarts);
622     }
623 
624     int32_t formatNumber = 0;
625     UErrorCode status = U_ZERO_ERROR;
626     for (int32_t partIndex = 0;
627         formatNumber < count && U_SUCCESS(status) &&
628             (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
629         setCustomArgStartFormat(partIndex, newFormats[formatNumber], status);
630         ++formatNumber;
631     }
632     // Delete those that didn't get used (if any).
633     for (; formatNumber < count; ++formatNumber) {
634         delete newFormats[formatNumber];
635     }
636 
637 }
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
setFormats(const Format ** newFormats,int32_t count)644 MessageFormat::setFormats(const Format** newFormats,
645                           int32_t count) {
646     if (newFormats == nullptr || count < 0) {
647         return;
648     }
649     // Throw away any cached formatters.
650     if (cachedFormatters != nullptr) {
651         uhash_removeAll(cachedFormatters);
652     }
653     if (customFormatArgStarts != nullptr) {
654         uhash_removeAll(customFormatArgStarts);
655     }
656 
657     UErrorCode status = U_ZERO_ERROR;
658     int32_t formatNumber = 0;
659     for (int32_t partIndex = 0;
660         formatNumber < count && U_SUCCESS(status) && (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
661       Format* newFormat = nullptr;
662       if (newFormats[formatNumber] != nullptr) {
663           newFormat = newFormats[formatNumber]->clone();
664           if (newFormat == nullptr) {
665               status = U_MEMORY_ALLOCATION_ERROR;
666           }
667       }
668       setCustomArgStartFormat(partIndex, newFormat, status);
669       ++formatNumber;
670     }
671     if (U_FAILURE(status)) {
672         resetPattern();
673     }
674 }
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
adoptFormat(int32_t n,Format * newFormat)681 MessageFormat::adoptFormat(int32_t n, Format *newFormat) {
682     LocalPointer<Format> p(newFormat);
683     if (n >= 0) {
684         int32_t formatNumber = 0;
685         for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
686             if (n == formatNumber) {
687                 UErrorCode status = U_ZERO_ERROR;
688                 setCustomArgStartFormat(partIndex, p.orphan(), status);
689                 return;
690             }
691             ++formatNumber;
692         }
693     }
694 }
695 
696 // -------------------------------------
697 // Adopt a single format by format name.
698 // Do nothing if there is no match of formatName.
699 void
adoptFormat(const UnicodeString & formatName,Format * formatToAdopt,UErrorCode & status)700 MessageFormat::adoptFormat(const UnicodeString& formatName,
701                            Format* formatToAdopt,
702                            UErrorCode& status) {
703     LocalPointer<Format> p(formatToAdopt);
704     if (U_FAILURE(status)) {
705         return;
706     }
707     int32_t argNumber = MessagePattern::validateArgumentName(formatName);
708     if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) {
709         status = U_ILLEGAL_ARGUMENT_ERROR;
710         return;
711     }
712     for (int32_t partIndex = 0;
713         (partIndex = nextTopLevelArgStart(partIndex)) >= 0 && U_SUCCESS(status);
714     ) {
715         if (argNameMatches(partIndex + 1, formatName, argNumber)) {
716             Format* f;
717             if (p.isValid()) {
718                 f = p.orphan();
719             } else if (formatToAdopt == nullptr) {
720                 f = nullptr;
721             } else {
722                 f = formatToAdopt->clone();
723                 if (f == nullptr) {
724                     status = U_MEMORY_ALLOCATION_ERROR;
725                     return;
726                 }
727             }
728             setCustomArgStartFormat(partIndex, f, status);
729         }
730     }
731 }
732 
733 // -------------------------------------
734 // Set a single format.
735 // Do nothing if the variable is not less than the array count.
736 void
setFormat(int32_t n,const Format & newFormat)737 MessageFormat::setFormat(int32_t n, const Format& newFormat) {
738 
739     if (n >= 0) {
740         int32_t formatNumber = 0;
741         for (int32_t partIndex = 0;
742              (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
743             if (n == formatNumber) {
744                 Format* new_format = newFormat.clone();
745                 if (new_format) {
746                     UErrorCode status = U_ZERO_ERROR;
747                     setCustomArgStartFormat(partIndex, new_format, status);
748                 }
749                 return;
750             }
751             ++formatNumber;
752         }
753     }
754 }
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 *
getFormat(const UnicodeString & formatName,UErrorCode & status)760 MessageFormat::getFormat(const UnicodeString& formatName, UErrorCode& status) {
761     if (U_FAILURE(status) || cachedFormatters == nullptr) return nullptr;
762 
763     int32_t argNumber = MessagePattern::validateArgumentName(formatName);
764     if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) {
765         status = U_ILLEGAL_ARGUMENT_ERROR;
766         return nullptr;
767     }
768     for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
769         if (argNameMatches(partIndex + 1, formatName, argNumber)) {
770             return getCachedFormatter(partIndex);
771         }
772     }
773     return nullptr;
774 }
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
setFormat(const UnicodeString & formatName,const Format & newFormat,UErrorCode & status)780 MessageFormat::setFormat(const UnicodeString& formatName,
781                          const Format& newFormat,
782                          UErrorCode& status) {
783     if (U_FAILURE(status)) return;
784 
785     int32_t argNumber = MessagePattern::validateArgumentName(formatName);
786     if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) {
787         status = U_ILLEGAL_ARGUMENT_ERROR;
788         return;
789     }
790     for (int32_t partIndex = 0;
791         (partIndex = nextTopLevelArgStart(partIndex)) >= 0 && U_SUCCESS(status);
792     ) {
793         if (argNameMatches(partIndex + 1, formatName, argNumber)) {
794             Format* new_format = newFormat.clone();
795             if (new_format == nullptr) {
796                 status = U_MEMORY_ALLOCATION_ERROR;
797                 return;
798             }
799             setCustomArgStartFormat(partIndex, new_format, status);
800         }
801     }
802 }
803 
804 // -------------------------------------
805 // Gets the format array.
806 const Format**
getFormats(int32_t & cnt) const807 MessageFormat::getFormats(int32_t& cnt) const
808 {
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     int32_t totalCapacity = 0;
817     for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0; ++totalCapacity) {}
818 
819     MessageFormat* t = const_cast<MessageFormat*> (this);
820     cnt = 0;
821     if (formatAliases == nullptr) {
822         t->formatAliasesCapacity = totalCapacity;
823         Format** a = (Format**)
824             uprv_malloc(sizeof(Format*) * formatAliasesCapacity);
825         if (a == nullptr) {
826             t->formatAliasesCapacity = 0;
827             return nullptr;
828         }
829         t->formatAliases = a;
830     } else if (totalCapacity > formatAliasesCapacity) {
831         Format** a = (Format**)
832             uprv_realloc(formatAliases, sizeof(Format*) * totalCapacity);
833         if (a == nullptr) {
834             t->formatAliasesCapacity = 0;
835             return nullptr;
836         }
837         t->formatAliases = a;
838         t->formatAliasesCapacity = totalCapacity;
839     }
840 
841     for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
842         t->formatAliases[cnt++] = getCachedFormatter(partIndex);
843     }
844 
845     return (const Format**)formatAliases;
846 }
847 
848 
getArgName(int32_t partIndex)849 UnicodeString MessageFormat::getArgName(int32_t partIndex) {
850     const MessagePattern::Part& part = msgPattern.getPart(partIndex);
851     return msgPattern.getSubstring(part);
852 }
853 
854 StringEnumeration*
getFormatNames(UErrorCode & status)855 MessageFormat::getFormatNames(UErrorCode& status) {
856     if (U_FAILURE(status))  return nullptr;
857 
858     LocalPointer<UVector> formatNames(new UVector(status), status);
859     if (U_FAILURE(status)) {
860         return nullptr;
861     }
862     formatNames->setDeleter(uprv_deleteUObject);
863 
864     for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
865         LocalPointer<UnicodeString> name(getArgName(partIndex + 1).clone(), status);
866         formatNames->adoptElement(name.orphan(), status);
867         if (U_FAILURE(status))  return nullptr;
868     }
869 
870     LocalPointer<StringEnumeration> nameEnumerator(
871         new FormatNameEnumeration(std::move(formatNames), status), status);
872     return U_SUCCESS(status) ? nameEnumerator.orphan() : nullptr;
873 }
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&
format(const Formattable * source,int32_t cnt,UnicodeString & appendTo,FieldPosition & ignore,UErrorCode & success) const880 MessageFormat::format(const Formattable* source,
881                       int32_t cnt,
882                       UnicodeString& appendTo,
883                       FieldPosition& ignore,
884                       UErrorCode& success) const
885 {
886     return format(source, nullptr, cnt, appendTo, &ignore, success);
887 }
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&
format(const UnicodeString & pattern,const Formattable * arguments,int32_t cnt,UnicodeString & appendTo,UErrorCode & success)895 MessageFormat::format(  const UnicodeString& pattern,
896                         const Formattable* arguments,
897                         int32_t cnt,
898                         UnicodeString& appendTo,
899                         UErrorCode& success)
900 {
901     MessageFormat temp(pattern, success);
902     return temp.format(arguments, nullptr, cnt, appendTo, nullptr, success);
903 }
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&
format(const Formattable & source,UnicodeString & appendTo,FieldPosition & ignore,UErrorCode & success) const911 MessageFormat::format(const Formattable& source,
912                       UnicodeString& appendTo,
913                       FieldPosition& ignore,
914                       UErrorCode& success) const
915 {
916     if (U_FAILURE(success))
917         return appendTo;
918     if (source.getType() != Formattable::kArray) {
919         success = U_ILLEGAL_ARGUMENT_ERROR;
920         return appendTo;
921     }
922     int32_t cnt;
923     const Formattable* tmpPtr = source.getArray(cnt);
924     return format(tmpPtr, nullptr, cnt, appendTo, &ignore, success);
925 }
926 
927 UnicodeString&
format(const UnicodeString * argumentNames,const Formattable * arguments,int32_t count,UnicodeString & appendTo,UErrorCode & success) const928 MessageFormat::format(const UnicodeString* argumentNames,
929                       const Formattable* arguments,
930                       int32_t count,
931                       UnicodeString& appendTo,
932                       UErrorCode& success) const {
933     return format(arguments, argumentNames, count, appendTo, nullptr, success);
934 }
935 
936 // Does linear search to find the match for an ArgName.
getArgFromListByName(const Formattable * arguments,const UnicodeString * argumentNames,int32_t cnt,UnicodeString & name) const937 const Formattable* MessageFormat::getArgFromListByName(const Formattable* arguments,
938                                                        const UnicodeString *argumentNames,
939                                                        int32_t cnt, UnicodeString& name) const {
940     for (int32_t i = 0; i < cnt; ++i) {
941         if (0 == argumentNames[i].compare(name)) {
942             return arguments + i;
943         }
944     }
945     return nullptr;
946 }
947 
948 
949 UnicodeString&
format(const Formattable * arguments,const UnicodeString * argumentNames,int32_t cnt,UnicodeString & appendTo,FieldPosition * pos,UErrorCode & status) const950 MessageFormat::format(const Formattable* arguments,
951                       const UnicodeString *argumentNames,
952                       int32_t cnt,
953                       UnicodeString& appendTo,
954                       FieldPosition* pos,
955                       UErrorCode& status) const {
956     if (U_FAILURE(status)) {
957         return appendTo;
958     }
959 
960     UnicodeStringAppendable usapp(appendTo);
961     AppendableWrapper app(usapp);
962     format(0, nullptr, arguments, argumentNames, cnt, app, pos, status);
963     return appendTo;
964 }
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:
PluralSelectorContext(int32_t start,const UnicodeString & name,const Formattable & num,double off,UErrorCode & errorCode)974     PluralSelectorContext(int32_t start, const UnicodeString &name,
975                           const Formattable &num, double off, UErrorCode &errorCode)
976             : startIndex(start), argName(name), offset(off),
977               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         if(off == 0) {
982             number = num;
983         } else {
984             number = num.getDouble(errorCode) - off;
985         }
986     }
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.
format(int32_t msgStart,const void * plNumber,const Formattable * arguments,const UnicodeString * argumentNames,int32_t cnt,AppendableWrapper & appendTo,FieldPosition * ignore,UErrorCode & success) const1010 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                            UErrorCode& success) const {
1017     if (U_FAILURE(success)) {
1018         return;
1019     }
1020 
1021     const UnicodeString& msgString = msgPattern.getPatternString();
1022     int32_t prevIndex = msgPattern.getPart(msgStart).getLimit();
1023     for (int32_t i = msgStart + 1; U_SUCCESS(success) ; ++i) {
1024         const MessagePattern::Part* part = &msgPattern.getPart(i);
1025         const UMessagePatternPartType type = part->getType();
1026         int32_t index = part->getIndex();
1027         appendTo.append(msgString, prevIndex, index - prevIndex);
1028         if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) {
1029             return;
1030         }
1031         prevIndex = part->getLimit();
1032         if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER) {
1033             const PluralSelectorContext &pluralNumber =
1034                 *static_cast<const PluralSelectorContext *>(plNumber);
1035             if(pluralNumber.forReplaceNumber) {
1036                 // number-offset was already formatted.
1037                 appendTo.formatAndAppend(pluralNumber.formatter,
1038                         pluralNumber.number, pluralNumber.numberString, success);
1039             } else {
1040                 const NumberFormat* nf = getDefaultNumberFormat(success);
1041                 appendTo.formatAndAppend(nf, pluralNumber.number, success);
1042             }
1043             continue;
1044         }
1045         if (type != UMSGPAT_PART_TYPE_ARG_START) {
1046             continue;
1047         }
1048         int32_t argLimit = msgPattern.getLimitPartIndex(i);
1049         UMessagePatternArgType argType = part->getArgType();
1050         part = &msgPattern.getPart(++i);
1051         const Formattable* arg;
1052         UBool noArg = false;
1053         UnicodeString argName = msgPattern.getSubstring(*part);
1054         if (argumentNames == nullptr) {
1055             int32_t argNumber = part->getValue();  // ARG_NUMBER
1056             if (0 <= argNumber && argNumber < cnt) {
1057                 arg = arguments + argNumber;
1058             } else {
1059                 arg = nullptr;
1060                 noArg = true;
1061             }
1062         } else {
1063             arg = getArgFromListByName(arguments, argumentNames, cnt, argName);
1064             if (arg == nullptr) {
1065                 noArg = true;
1066             }
1067         }
1068         ++i;
1069         int32_t prevDestLength = appendTo.length();
1070         const Format* formatter = nullptr;
1071         if (noArg) {
1072             appendTo.append(
1073                 UnicodeString(LEFT_CURLY_BRACE).append(argName).append(RIGHT_CURLY_BRACE));
1074         } else if (arg == nullptr) {
1075             appendTo.append(NULL_STRING, 4);
1076         } else if(plNumber!=nullptr &&
1077                 static_cast<const PluralSelectorContext *>(plNumber)->numberArgIndex==(i-2)) {
1078             const PluralSelectorContext &pluralNumber =
1079                 *static_cast<const PluralSelectorContext *>(plNumber);
1080             if(pluralNumber.offset == 0) {
1081                 // The number was already formatted with this formatter.
1082                 appendTo.formatAndAppend(pluralNumber.formatter, pluralNumber.number,
1083                                          pluralNumber.numberString, success);
1084             } else {
1085                 // Do not use the formatted (number-offset) string for a named argument
1086                 // that formats the number without subtracting the offset.
1087                 appendTo.formatAndAppend(pluralNumber.formatter, *arg, success);
1088             }
1089         } else if ((formatter = getCachedFormatter(i -2)) != 0) {
1090             // Handles all ArgType.SIMPLE, and formatters from setFormat() and its siblings.
1091             if (dynamic_cast<const ChoiceFormat*>(formatter) ||
1092                 dynamic_cast<const PluralFormat*>(formatter) ||
1093                 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                 UnicodeString subMsgString;
1098                 formatter->format(*arg, subMsgString, success);
1099                 if (subMsgString.indexOf(LEFT_CURLY_BRACE) >= 0 ||
1100                     (subMsgString.indexOf(SINGLE_QUOTE) >= 0 && !MessageImpl::jdkAposMode(msgPattern))
1101                 ) {
1102                     MessageFormat subMsgFormat(subMsgString, fLocale, success);
1103                     subMsgFormat.format(0, nullptr, arguments, argumentNames, cnt, appendTo, ignore, success);
1104                 } else {
1105                     appendTo.append(subMsgString);
1106                 }
1107             } else {
1108                 appendTo.formatAndAppend(formatter, *arg, success);
1109             }
1110         } 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             if (arg->isNumeric()) {
1115                 const NumberFormat* nf = getDefaultNumberFormat(success);
1116                 appendTo.formatAndAppend(nf, *arg, success);
1117             } else if (arg->getType() == Formattable::kDate) {
1118                 const DateFormat* df = getDefaultDateFormat(success);
1119                 appendTo.formatAndAppend(df, *arg, success);
1120             } else {
1121                 appendTo.append(arg->getString(success));
1122             }
1123         } else if (argType == UMSGPAT_ARG_TYPE_CHOICE) {
1124             if (!arg->isNumeric()) {
1125                 success = U_ILLEGAL_ARGUMENT_ERROR;
1126                 return;
1127             }
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             const double number = arg->getDouble(success);
1131             int32_t subMsgStart = ChoiceFormat::findSubMessage(msgPattern, i, number);
1132             formatComplexSubMessage(subMsgStart, nullptr, arguments, argumentNames,
1133                                     cnt, appendTo, success);
1134         } else if (UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType)) {
1135             if (!arg->isNumeric()) {
1136                 success = U_ILLEGAL_ARGUMENT_ERROR;
1137                 return;
1138             }
1139             const PluralSelectorProvider &selector =
1140                 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             double offset = msgPattern.getPluralOffset(i);
1144             PluralSelectorContext context(i, argName, *arg, offset, success);
1145             int32_t subMsgStart = PluralFormat::findSubMessage(
1146                     msgPattern, i, selector, &context, arg->getDouble(success), success);
1147             formatComplexSubMessage(subMsgStart, &context, arguments, argumentNames,
1148                                     cnt, appendTo, success);
1149         } else if (argType == UMSGPAT_ARG_TYPE_SELECT) {
1150             int32_t subMsgStart = SelectFormat::findSubMessage(msgPattern, i, arg->getString(success), success);
1151             formatComplexSubMessage(subMsgStart, nullptr, arguments, argumentNames,
1152                                     cnt, appendTo, success);
1153         } else {
1154             // This should never happen.
1155             success = U_INTERNAL_PROGRAM_ERROR;
1156             return;
1157         }
1158         ignore = updateMetaData(appendTo, prevDestLength, ignore, arg);
1159         prevIndex = msgPattern.getPart(argLimit).getLimit();
1160         i = argLimit;
1161     }
1162 }
1163 
1164 
formatComplexSubMessage(int32_t msgStart,const void * plNumber,const Formattable * arguments,const UnicodeString * argumentNames,int32_t cnt,AppendableWrapper & appendTo,UErrorCode & success) const1165 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                                             UErrorCode& success) const {
1172     if (U_FAILURE(success)) {
1173         return;
1174     }
1175 
1176     if (!MessageImpl::jdkAposMode(msgPattern)) {
1177         format(msgStart, plNumber, arguments, argumentNames, cnt, appendTo, nullptr, success);
1178         return;
1179     }
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     const UnicodeString& msgString = msgPattern.getPatternString();
1187     UnicodeString sb;
1188     int32_t prevIndex = msgPattern.getPart(msgStart).getLimit();
1189     for (int32_t i = msgStart;;) {
1190         const MessagePattern::Part& part = msgPattern.getPart(++i);
1191         const UMessagePatternPartType type = part.getType();
1192         int32_t index = part.getIndex();
1193         if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) {
1194             sb.append(msgString, prevIndex, index - prevIndex);
1195             break;
1196         } else if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER || type == UMSGPAT_PART_TYPE_SKIP_SYNTAX) {
1197             sb.append(msgString, prevIndex, index - prevIndex);
1198             if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER) {
1199                 const PluralSelectorContext &pluralNumber =
1200                     *static_cast<const PluralSelectorContext *>(plNumber);
1201                 if(pluralNumber.forReplaceNumber) {
1202                     // number-offset was already formatted.
1203                     sb.append(pluralNumber.numberString);
1204                 } else {
1205                     const NumberFormat* nf = getDefaultNumberFormat(success);
1206                     sb.append(nf->format(pluralNumber.number, sb, success));
1207                 }
1208             }
1209             prevIndex = part.getLimit();
1210         } else if (type == UMSGPAT_PART_TYPE_ARG_START) {
1211             sb.append(msgString, prevIndex, index - prevIndex);
1212             prevIndex = index;
1213             i = msgPattern.getLimitPartIndex(i);
1214             index = msgPattern.getPart(i).getLimit();
1215             MessageImpl::appendReducedApostrophes(msgString, prevIndex, index, sb);
1216             prevIndex = index;
1217         }
1218     }
1219     if (sb.indexOf(LEFT_CURLY_BRACE) >= 0) {
1220         UnicodeString emptyPattern;  // gcc 3.3.3 fails with "UnicodeString()" as the first parameter.
1221         MessageFormat subMsgFormat(emptyPattern, fLocale, success);
1222         subMsgFormat.applyPattern(sb, UMSGPAT_APOS_DOUBLE_REQUIRED, nullptr, success);
1223         subMsgFormat.format(0, nullptr, arguments, argumentNames, cnt, appendTo, nullptr, success);
1224     } else {
1225         appendTo.append(sb);
1226     }
1227 }
1228 
1229 
getLiteralStringUntilNextArgument(int32_t from) const1230 UnicodeString MessageFormat::getLiteralStringUntilNextArgument(int32_t from) const {
1231     const UnicodeString& msgString=msgPattern.getPatternString();
1232     int32_t prevIndex=msgPattern.getPart(from).getLimit();
1233     UnicodeString b;
1234     for (int32_t i = from + 1; ; ++i) {
1235         const MessagePattern::Part& part = msgPattern.getPart(i);
1236         const UMessagePatternPartType type=part.getType();
1237         int32_t index=part.getIndex();
1238         b.append(msgString, prevIndex, index - prevIndex);
1239         if(type==UMSGPAT_PART_TYPE_ARG_START || type==UMSGPAT_PART_TYPE_MSG_LIMIT) {
1240             return b;
1241         }
1242         // Unexpected Part "part" in parsed message.
1243         U_ASSERT(type==UMSGPAT_PART_TYPE_SKIP_SYNTAX || type==UMSGPAT_PART_TYPE_INSERT_CHAR);
1244         prevIndex=part.getLimit();
1245     }
1246 }
1247 
1248 
updateMetaData(AppendableWrapper &,int32_t,FieldPosition *,const Formattable *) const1249 FieldPosition* MessageFormat::updateMetaData(AppendableWrapper& /*dest*/, int32_t /*prevLength*/,
1250                              FieldPosition* /*fp*/, const Formattable* /*argId*/) const {
1251     // Unlike in Java, there are no field attributes defined for MessageFormat. Do nothing.
1252     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 }
1262 
1263 int32_t
findOtherSubMessage(int32_t partIndex) const1264 MessageFormat::findOtherSubMessage(int32_t partIndex) const {
1265     int32_t count=msgPattern.countParts();
1266     const MessagePattern::Part *part = &msgPattern.getPart(partIndex);
1267     if(MessagePattern::Part::hasNumericValue(part->getType())) {
1268         ++partIndex;
1269     }
1270     // Iterate over (ARG_SELECTOR [ARG_INT|ARG_DOUBLE] message) tuples
1271     // until ARG_LIMIT or end of plural-only pattern.
1272     UnicodeString other(false, OTHER_STRING, 5);
1273     do {
1274         part=&msgPattern.getPart(partIndex++);
1275         UMessagePatternPartType type=part->getType();
1276         if(type==UMSGPAT_PART_TYPE_ARG_LIMIT) {
1277             break;
1278         }
1279         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         if(msgPattern.partSubstringMatches(*part, other)) {
1282             return partIndex;
1283         }
1284         if(MessagePattern::Part::hasNumericValue(msgPattern.getPartType(partIndex))) {
1285             ++partIndex;  // skip the numeric-value part of "=1" etc.
1286         }
1287         partIndex=msgPattern.getLimitPartIndex(partIndex);
1288     } while(++partIndex<count);
1289     return 0;
1290 }
1291 
1292 int32_t
findFirstPluralNumberArg(int32_t msgStart,const UnicodeString & argName) const1293 MessageFormat::findFirstPluralNumberArg(int32_t msgStart, const UnicodeString &argName) const {
1294     for(int32_t i=msgStart+1;; ++i) {
1295         const MessagePattern::Part &part=msgPattern.getPart(i);
1296         UMessagePatternPartType type=part.getType();
1297         if(type==UMSGPAT_PART_TYPE_MSG_LIMIT) {
1298             return 0;
1299         }
1300         if(type==UMSGPAT_PART_TYPE_REPLACE_NUMBER) {
1301             return -1;
1302         }
1303         if(type==UMSGPAT_PART_TYPE_ARG_START) {
1304             UMessagePatternArgType argType=part.getArgType();
1305             if(!argName.isEmpty() && (argType==UMSGPAT_ARG_TYPE_NONE || argType==UMSGPAT_ARG_TYPE_SIMPLE)) {
1306                 // ARG_NUMBER or ARG_NAME
1307                 if(msgPattern.partSubstringMatches(msgPattern.getPart(i+1), argName)) {
1308                     return i;
1309                 }
1310             }
1311             i=msgPattern.getLimitPartIndex(i);
1312         }
1313     }
1314 }
1315 
copyObjects(const MessageFormat & that,UErrorCode & ec)1316 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     argTypeCount = that.argTypeCount;
1323     if (argTypeCount > 0) {
1324         if (!allocateArgTypes(argTypeCount, ec)) {
1325             return;
1326         }
1327         uprv_memcpy(argTypes, that.argTypes, argTypeCount * sizeof(argTypes[0]));
1328     }
1329     if (cachedFormatters != nullptr) {
1330         uhash_removeAll(cachedFormatters);
1331     }
1332     if (customFormatArgStarts != nullptr) {
1333         uhash_removeAll(customFormatArgStarts);
1334     }
1335     if (that.cachedFormatters) {
1336         if (cachedFormatters == nullptr) {
1337             cachedFormatters=uhash_open(uhash_hashLong, uhash_compareLong,
1338                                         equalFormatsForHash, &ec);
1339             if (U_FAILURE(ec)) {
1340                 return;
1341             }
1342             uhash_setValueDeleter(cachedFormatters, uprv_deleteUObject);
1343         }
1344 
1345         const int32_t count = uhash_count(that.cachedFormatters);
1346         int32_t pos, idx;
1347         for (idx = 0, pos = UHASH_FIRST; idx < count && U_SUCCESS(ec); ++idx) {
1348             const UHashElement* cur = uhash_nextElement(that.cachedFormatters, &pos);
1349             Format* newFormat = ((Format*)(cur->value.pointer))->clone();
1350             if (newFormat) {
1351                 uhash_iput(cachedFormatters, cur->key.integer, newFormat, &ec);
1352             } else {
1353                 ec = U_MEMORY_ALLOCATION_ERROR;
1354                 return;
1355             }
1356         }
1357     }
1358     if (that.customFormatArgStarts) {
1359         if (customFormatArgStarts == nullptr) {
1360             customFormatArgStarts=uhash_open(uhash_hashLong, uhash_compareLong,
1361                                               nullptr, &ec);
1362         }
1363         const int32_t count = uhash_count(that.customFormatArgStarts);
1364         int32_t pos, idx;
1365         for (idx = 0, pos = UHASH_FIRST; idx < count && U_SUCCESS(ec); ++idx) {
1366             const UHashElement* cur = uhash_nextElement(that.customFormatArgStarts, &pos);
1367             uhash_iputi(customFormatArgStarts, cur->key.integer, cur->value.integer, &ec);
1368         }
1369     }
1370 }
1371 
1372 
1373 Formattable*
parse(int32_t msgStart,const UnicodeString & source,ParsePosition & pos,int32_t & count,UErrorCode & ec) const1374 MessageFormat::parse(int32_t msgStart,
1375                      const UnicodeString& source,
1376                      ParsePosition& pos,
1377                      int32_t& count,
1378                      UErrorCode& ec) const {
1379     count = 0;
1380     if (U_FAILURE(ec)) {
1381         pos.setErrorIndex(pos.getIndex());
1382         return nullptr;
1383     }
1384     // parse() does not work with named arguments.
1385     if (msgPattern.hasNamedArguments()) {
1386         ec = U_ARGUMENT_TYPE_MISMATCH;
1387         pos.setErrorIndex(pos.getIndex());
1388         return nullptr;
1389     }
1390     LocalArray<Formattable> resultArray(new Formattable[argTypeCount ? argTypeCount : 1]);
1391     const UnicodeString& msgString=msgPattern.getPatternString();
1392     int32_t prevIndex=msgPattern.getPart(msgStart).getLimit();
1393     int32_t sourceOffset = pos.getIndex();
1394     ParsePosition tempStatus(0);
1395 
1396     for(int32_t i=msgStart+1; ; ++i) {
1397         UBool haveArgResult = false;
1398         const MessagePattern::Part* part=&msgPattern.getPart(i);
1399         const UMessagePatternPartType type=part->getType();
1400         int32_t index=part->getIndex();
1401         // Make sure the literal string matches.
1402         int32_t len = index - prevIndex;
1403         if (len == 0 || (0 == msgString.compare(prevIndex, len, source, sourceOffset, len))) {
1404             sourceOffset += len;
1405             prevIndex += len;
1406         } else {
1407             pos.setErrorIndex(sourceOffset);
1408             return nullptr; // leave index as is to signal error
1409         }
1410         if(type==UMSGPAT_PART_TYPE_MSG_LIMIT) {
1411             // Things went well! Done.
1412             pos.setIndex(sourceOffset);
1413             return resultArray.orphan();
1414         }
1415         if(type==UMSGPAT_PART_TYPE_SKIP_SYNTAX || type==UMSGPAT_PART_TYPE_INSERT_CHAR) {
1416             prevIndex=part->getLimit();
1417             continue;
1418         }
1419         // We do not support parsing Plural formats. (No REPLACE_NUMBER here.)
1420         // Unexpected Part "part" in parsed message.
1421         U_ASSERT(type==UMSGPAT_PART_TYPE_ARG_START);
1422         int32_t argLimit=msgPattern.getLimitPartIndex(i);
1423 
1424         UMessagePatternArgType argType=part->getArgType();
1425         part=&msgPattern.getPart(++i);
1426         int32_t argNumber = part->getValue();  // ARG_NUMBER
1427         UnicodeString key;
1428         ++i;
1429         const Format* formatter = nullptr;
1430         Formattable& argResult = resultArray[argNumber];
1431 
1432         if(cachedFormatters!=nullptr && (formatter = getCachedFormatter(i - 2))!=nullptr) {
1433             // Just parse using the formatter.
1434             tempStatus.setIndex(sourceOffset);
1435             formatter->parseObject(source, argResult, tempStatus);
1436             if (tempStatus.getIndex() == sourceOffset) {
1437                 pos.setErrorIndex(sourceOffset);
1438                 return nullptr; // leave index as is to signal error
1439             }
1440             sourceOffset = tempStatus.getIndex();
1441             haveArgResult = true;
1442         } else if(
1443             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             UnicodeString stringAfterArgument = getLiteralStringUntilNextArgument(argLimit);
1453             int32_t next;
1454             if (!stringAfterArgument.isEmpty()) {
1455                 next = source.indexOf(stringAfterArgument, sourceOffset);
1456             } else {
1457                 next = source.length();
1458             }
1459             if (next < 0) {
1460                 pos.setErrorIndex(sourceOffset);
1461                 return nullptr; // leave index as is to signal error
1462             } else {
1463                 UnicodeString strValue(source.tempSubString(sourceOffset, next - sourceOffset));
1464                 UnicodeString compValue;
1465                 compValue.append(LEFT_CURLY_BRACE);
1466                 itos(argNumber, compValue);
1467                 compValue.append(RIGHT_CURLY_BRACE);
1468                 if (0 != strValue.compare(compValue)) {
1469                     argResult.setString(strValue);
1470                     haveArgResult = true;
1471                 }
1472                 sourceOffset = next;
1473             }
1474         } else if(argType==UMSGPAT_ARG_TYPE_CHOICE) {
1475             tempStatus.setIndex(sourceOffset);
1476             double choiceResult = ChoiceFormat::parseArgument(msgPattern, i, source, tempStatus);
1477             if (tempStatus.getIndex() == sourceOffset) {
1478                 pos.setErrorIndex(sourceOffset);
1479                 return nullptr; // leave index as is to signal error
1480             }
1481             argResult.setDouble(choiceResult);
1482             haveArgResult = true;
1483             sourceOffset = tempStatus.getIndex();
1484         } else if(UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType) || argType==UMSGPAT_ARG_TYPE_SELECT) {
1485             // Parsing not supported.
1486             ec = U_UNSUPPORTED_ERROR;
1487             return nullptr;
1488         } else {
1489             // This should never happen.
1490             ec = U_INTERNAL_PROGRAM_ERROR;
1491             return nullptr;
1492         }
1493         if (haveArgResult && count <= argNumber) {
1494             count = argNumber + 1;
1495         }
1496         prevIndex=msgPattern.getPart(argLimit).getLimit();
1497         i=argLimit;
1498     }
1499 }
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*
parse(const UnicodeString & source,ParsePosition & pos,int32_t & count) const1506 MessageFormat::parse(const UnicodeString& source,
1507                      ParsePosition& pos,
1508                      int32_t& count) const {
1509     UErrorCode ec = U_ZERO_ERROR;
1510     return parse(0, source, pos, count, ec);
1511 }
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*
parse(const UnicodeString & source,int32_t & cnt,UErrorCode & success) const1519 MessageFormat::parse(const UnicodeString& source,
1520                      int32_t& cnt,
1521                      UErrorCode& success) const
1522 {
1523     if (msgPattern.hasNamedArguments()) {
1524         success = U_ARGUMENT_TYPE_MISMATCH;
1525         return nullptr;
1526     }
1527     ParsePosition status(0);
1528     // Calls the actual implementation method and starts
1529     // from zero offset of the source text.
1530     Formattable* result = parse(source, status, cnt);
1531     if (status.getIndex() == 0) {
1532         success = U_MESSAGE_PARSE_ERROR;
1533         delete[] result;
1534         return nullptr;
1535     }
1536     return result;
1537 }
1538 
1539 // -------------------------------------
1540 // Parses the source text and copy into the result buffer.
1541 
1542 void
parseObject(const UnicodeString & source,Formattable & result,ParsePosition & status) const1543 MessageFormat::parseObject( const UnicodeString& source,
1544                             Formattable& result,
1545                             ParsePosition& status) const
1546 {
1547     int32_t cnt = 0;
1548     Formattable* tmpResult = parse(source, status, cnt);
1549     if (tmpResult != nullptr)
1550         result.adoptArray(tmpResult, cnt);
1551 }
1552 
1553 UnicodeString
autoQuoteApostrophe(const UnicodeString & pattern,UErrorCode & status)1554 MessageFormat::autoQuoteApostrophe(const UnicodeString& pattern, UErrorCode& status) {
1555     UnicodeString result;
1556     if (U_SUCCESS(status)) {
1557         int32_t plen = pattern.length();
1558         const char16_t* pat = pattern.getBuffer();
1559         int32_t blen = plen * 2 + 1; // space for null termination, convenience
1560         char16_t* buf = result.getBuffer(blen);
1561         if (buf == nullptr) {
1562             status = U_MEMORY_ALLOCATION_ERROR;
1563         } else {
1564             int32_t len = umsg_autoQuoteApostrophe(pat, plen, buf, blen, &status);
1565             result.releaseBuffer(U_SUCCESS(status) ? len : 0);
1566         }
1567     }
1568     if (U_FAILURE(status)) {
1569         result.setToBogus();
1570     }
1571     return result;
1572 }
1573 
1574 // -------------------------------------
1575 
makeRBNF(URBNFRuleSetTag tag,const Locale & locale,const UnicodeString & defaultRuleSet,UErrorCode & ec)1576 static Format* makeRBNF(URBNFRuleSetTag tag, const Locale& locale, const UnicodeString& defaultRuleSet, UErrorCode& ec) {
1577     RuleBasedNumberFormat* fmt = new RuleBasedNumberFormat(tag, locale, ec);
1578     if (fmt == nullptr) {
1579         ec = U_MEMORY_ALLOCATION_ERROR;
1580     } else if (U_SUCCESS(ec) && defaultRuleSet.length() > 0) {
1581         UErrorCode localStatus = U_ZERO_ERROR; // ignore unrecognized default rule set
1582         fmt->setDefaultRuleSet(defaultRuleSet, localStatus);
1583     }
1584     return fmt;
1585 }
1586 
cacheExplicitFormats(UErrorCode & status)1587 void MessageFormat::cacheExplicitFormats(UErrorCode& status) {
1588     if (U_FAILURE(status)) {
1589         return;
1590     }
1591 
1592     if (cachedFormatters != nullptr) {
1593         uhash_removeAll(cachedFormatters);
1594     }
1595     if (customFormatArgStarts != nullptr) {
1596         uhash_removeAll(customFormatArgStarts);
1597     }
1598 
1599     // The last two "parts" can at most be ARG_LIMIT and MSG_LIMIT
1600     // which we need not examine.
1601     int32_t limit = msgPattern.countParts() - 2;
1602     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     for (int32_t i = 2; i < limit && U_SUCCESS(status); ++i) {
1609         const MessagePattern::Part& part = msgPattern.getPart(i);
1610         if (part.getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) {
1611             const int argNumber = part.getValue();
1612             if (argNumber >= argTypeCount) {
1613                 argTypeCount = argNumber + 1;
1614             }
1615         }
1616     }
1617     if (!allocateArgTypes(argTypeCount, status)) {
1618         return;
1619     }
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     for (int32_t i = 0; i < argTypeCount; ++i) {
1624         argTypes[i] = Formattable::kObject;
1625     }
1626     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     for (int32_t i = 1; i < limit && U_SUCCESS(status); ++i) {
1631         const MessagePattern::Part* part = &msgPattern.getPart(i);
1632         if (part->getType() != UMSGPAT_PART_TYPE_ARG_START) {
1633             continue;
1634         }
1635         UMessagePatternArgType argType = part->getArgType();
1636 
1637         int32_t argNumber = -1;
1638         part = &msgPattern.getPart(i + 1);
1639         if (part->getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) {
1640             argNumber = part->getValue();
1641         }
1642         Formattable::Type formattableType;
1643 
1644         switch (argType) {
1645         case UMSGPAT_ARG_TYPE_NONE:
1646             formattableType = Formattable::kString;
1647             break;
1648         case UMSGPAT_ARG_TYPE_SIMPLE: {
1649             int32_t index = i;
1650             i += 2;
1651             UnicodeString explicitType = msgPattern.getSubstring(msgPattern.getPart(i++));
1652             UnicodeString style;
1653             if ((part = &msgPattern.getPart(i))->getType() == UMSGPAT_PART_TYPE_ARG_STYLE) {
1654                 style = msgPattern.getSubstring(*part);
1655                 ++i;
1656             }
1657             UParseError parseError;
1658             Format* formatter = createAppropriateFormat(explicitType, style, formattableType, parseError, status);
1659             setArgStartFormat(index, formatter, status);
1660             break;
1661         }
1662         case UMSGPAT_ARG_TYPE_CHOICE:
1663         case UMSGPAT_ARG_TYPE_PLURAL:
1664         case UMSGPAT_ARG_TYPE_SELECTORDINAL:
1665             formattableType = Formattable::kDouble;
1666             break;
1667         case UMSGPAT_ARG_TYPE_SELECT:
1668             formattableType = Formattable::kString;
1669             break;
1670         default:
1671             status = U_INTERNAL_PROGRAM_ERROR;  // Should be unreachable.
1672             formattableType = Formattable::kString;
1673             break;
1674         }
1675         if (argNumber != -1) {
1676             if (argTypes[argNumber] != Formattable::kObject && argTypes[argNumber] != formattableType) {
1677                 hasArgTypeConflicts = true;
1678             }
1679             argTypes[argNumber] = formattableType;
1680         }
1681     }
1682 }
1683 
createAppropriateFormat(UnicodeString & type,UnicodeString & style,Formattable::Type & formattableType,UParseError & parseError,UErrorCode & ec)1684 Format* MessageFormat::createAppropriateFormat(UnicodeString& type, UnicodeString& style,
1685                                                Formattable::Type& formattableType, UParseError& parseError,
1686                                                UErrorCode& ec) {
1687     if (U_FAILURE(ec)) {
1688         return nullptr;
1689     }
1690     Format* fmt = nullptr;
1691     int32_t typeID, styleID;
1692     DateFormat::EStyle date_style;
1693     int32_t firstNonSpace;
1694 
1695     switch (typeID = findKeyword(type, TYPE_IDS)) {
1696     case 0: // number
1697         formattableType = Formattable::kDouble;
1698         switch (findKeyword(style, NUMBER_STYLE_IDS)) {
1699         case 0: // default
1700             fmt = NumberFormat::createInstance(fLocale, ec);
1701             break;
1702         case 1: // currency
1703             fmt = NumberFormat::createCurrencyInstance(fLocale, ec);
1704             break;
1705         case 2: // percent
1706             fmt = NumberFormat::createPercentInstance(fLocale, ec);
1707             break;
1708         case 3: // integer
1709             formattableType = Formattable::kLong;
1710             fmt = createIntegerFormat(fLocale, ec);
1711             break;
1712         default: // pattern or skeleton
1713             firstNonSpace = PatternProps::skipWhiteSpace(style, 0);
1714             if (style.compare(firstNonSpace, 2, u"::", 0, 2) == 0) {
1715                 // Skeleton
1716                 UnicodeString skeleton = style.tempSubString(firstNonSpace + 2);
1717                 fmt = number::NumberFormatter::forSkeleton(skeleton, ec).locale(fLocale).toFormat(ec);
1718             } else {
1719                 // Pattern
1720                 fmt = NumberFormat::createInstance(fLocale, ec);
1721                 if (fmt) {
1722                     auto* decfmt = dynamic_cast<DecimalFormat*>(fmt);
1723                     if (decfmt != nullptr) {
1724                         decfmt->applyPattern(style, parseError, ec);
1725                     }
1726                 }
1727             }
1728             break;
1729         }
1730         break;
1731 
1732     case 1: // date
1733     case 2: // time
1734         formattableType = Formattable::kDate;
1735         firstNonSpace = PatternProps::skipWhiteSpace(style, 0);
1736         if (style.compare(firstNonSpace, 2, u"::", 0, 2) == 0) {
1737             // Skeleton
1738             UnicodeString skeleton = style.tempSubString(firstNonSpace + 2);
1739             fmt = DateFormat::createInstanceForSkeleton(skeleton, fLocale, ec);
1740         } else {
1741             // Pattern
1742             styleID = findKeyword(style, DATE_STYLE_IDS);
1743             date_style = (styleID >= 0) ? DATE_STYLES[styleID] : DateFormat::kDefault;
1744 
1745             if (typeID == 1) {
1746                 fmt = DateFormat::createDateInstance(date_style, fLocale);
1747             } else {
1748                 fmt = DateFormat::createTimeInstance(date_style, fLocale);
1749             }
1750 
1751             if (styleID < 0 && fmt != nullptr) {
1752                 SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(fmt);
1753                 if (sdtfmt != nullptr) {
1754                     sdtfmt->applyPattern(style);
1755                 }
1756             }
1757         }
1758         break;
1759 
1760     case 3: // spellout
1761         formattableType = Formattable::kDouble;
1762         fmt = makeRBNF(URBNF_SPELLOUT, fLocale, style, ec);
1763         break;
1764     case 4: // ordinal
1765         formattableType = Formattable::kDouble;
1766         fmt = makeRBNF(URBNF_ORDINAL, fLocale, style, ec);
1767         break;
1768     case 5: // duration
1769         formattableType = Formattable::kDouble;
1770         fmt = makeRBNF(URBNF_DURATION, fLocale, style, ec);
1771         break;
1772     default:
1773         formattableType = Formattable::kString;
1774         ec = U_ILLEGAL_ARGUMENT_ERROR;
1775         break;
1776     }
1777 
1778     return fmt;
1779 }
1780 
1781 
1782 //-------------------------------------
1783 // Finds the string, s, in the string array, list.
findKeyword(const UnicodeString & s,const char16_t * const * list)1784 int32_t MessageFormat::findKeyword(const UnicodeString& s,
1785                                    const char16_t * const *list)
1786 {
1787     if (s.isEmpty()) {
1788         return 0; // default
1789     }
1790 
1791     int32_t length = s.length();
1792     const char16_t *ps = PatternProps::trimWhiteSpace(s.getBuffer(), length);
1793     UnicodeString buffer(false, ps, length);
1794     // Trims the space characters and turns all characters
1795     // in s to lower case.
1796     buffer.toLower("");
1797     for (int32_t i = 0; list[i]; ++i) {
1798         if (!buffer.compare(list[i], u_strlen(list[i]))) {
1799             return i;
1800         }
1801     }
1802     return -1;
1803 }
1804 
1805 /**
1806  * Convenience method that ought to be in NumberFormat
1807  */
1808 NumberFormat*
createIntegerFormat(const Locale & locale,UErrorCode & status) const1809 MessageFormat::createIntegerFormat(const Locale& locale, UErrorCode& status) const {
1810     NumberFormat *temp = NumberFormat::createInstance(locale, status);
1811     DecimalFormat *temp2;
1812     if (temp != nullptr && (temp2 = dynamic_cast<DecimalFormat*>(temp)) != nullptr) {
1813         temp2->setMaximumFractionDigits(0);
1814         temp2->setDecimalSeparatorAlwaysShown(false);
1815         temp2->setParseIntegerOnly(true);
1816     }
1817 
1818     return temp;
1819 }
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  */
getDefaultNumberFormat(UErrorCode & ec) const1828 const NumberFormat* MessageFormat::getDefaultNumberFormat(UErrorCode& ec) const {
1829     if (defaultNumberFormat == nullptr) {
1830         MessageFormat* t = (MessageFormat*) this;
1831         t->defaultNumberFormat = NumberFormat::createInstance(fLocale, ec);
1832         if (U_FAILURE(ec)) {
1833             delete t->defaultNumberFormat;
1834             t->defaultNumberFormat = nullptr;
1835         } else if (t->defaultNumberFormat == nullptr) {
1836             ec = U_MEMORY_ALLOCATION_ERROR;
1837         }
1838     }
1839     return defaultNumberFormat;
1840 }
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  */
getDefaultDateFormat(UErrorCode & ec) const1849 const DateFormat* MessageFormat::getDefaultDateFormat(UErrorCode& ec) const {
1850     if (defaultDateFormat == nullptr) {
1851         MessageFormat* t = (MessageFormat*) this;
1852         t->defaultDateFormat = DateFormat::createDateTimeInstance(DateFormat::kShort, DateFormat::kShort, fLocale);
1853         if (t->defaultDateFormat == nullptr) {
1854             ec = U_MEMORY_ALLOCATION_ERROR;
1855         }
1856     }
1857     return defaultDateFormat;
1858 }
1859 
1860 UBool
usesNamedArguments() const1861 MessageFormat::usesNamedArguments() const {
1862     return msgPattern.hasNamedArguments();
1863 }
1864 
1865 int32_t
getArgTypeCount() const1866 MessageFormat::getArgTypeCount() const {
1867     return argTypeCount;
1868 }
1869 
equalFormats(const void * left,const void * right)1870 UBool MessageFormat::equalFormats(const void* left, const void* right) {
1871     return *(const Format*)left==*(const Format*)right;
1872 }
1873 
1874 
operator ==(const Format &) const1875 bool MessageFormat::DummyFormat::operator==(const Format&) const {
1876     return true;
1877 }
1878 
clone() const1879 MessageFormat::DummyFormat* MessageFormat::DummyFormat::clone() const {
1880     return new DummyFormat();
1881 }
1882 
format(const Formattable &,UnicodeString & appendTo,UErrorCode & status) const1883 UnicodeString& MessageFormat::DummyFormat::format(const Formattable&,
1884                           UnicodeString& appendTo,
1885                           UErrorCode& status) const {
1886     if (U_SUCCESS(status)) {
1887         status = U_UNSUPPORTED_ERROR;
1888     }
1889     return appendTo;
1890 }
1891 
format(const Formattable &,UnicodeString & appendTo,FieldPosition &,UErrorCode & status) const1892 UnicodeString& MessageFormat::DummyFormat::format(const Formattable&,
1893                           UnicodeString& appendTo,
1894                           FieldPosition&,
1895                           UErrorCode& status) const {
1896     if (U_SUCCESS(status)) {
1897         status = U_UNSUPPORTED_ERROR;
1898     }
1899     return appendTo;
1900 }
1901 
format(const Formattable &,UnicodeString & appendTo,FieldPositionIterator *,UErrorCode & status) const1902 UnicodeString& MessageFormat::DummyFormat::format(const Formattable&,
1903                           UnicodeString& appendTo,
1904                           FieldPositionIterator*,
1905                           UErrorCode& status) const {
1906     if (U_SUCCESS(status)) {
1907         status = U_UNSUPPORTED_ERROR;
1908     }
1909     return appendTo;
1910 }
1911 
parseObject(const UnicodeString &,Formattable &,ParsePosition &) const1912 void MessageFormat::DummyFormat::parseObject(const UnicodeString&,
1913                                                      Formattable&,
1914                                                      ParsePosition& ) const {
1915 }
1916 
1917 
FormatNameEnumeration(LocalPointer<UVector> nameList,UErrorCode &)1918 FormatNameEnumeration::FormatNameEnumeration(LocalPointer<UVector> nameList, UErrorCode& /*status*/) {
1919     pos=0;
1920     fFormatNames = std::move(nameList);
1921 }
1922 
1923 const UnicodeString*
snext(UErrorCode & status)1924 FormatNameEnumeration::snext(UErrorCode& status) {
1925     if (U_SUCCESS(status) && pos < fFormatNames->size()) {
1926         return (const UnicodeString*)fFormatNames->elementAt(pos++);
1927     }
1928     return nullptr;
1929 }
1930 
1931 void
reset(UErrorCode &)1932 FormatNameEnumeration::reset(UErrorCode& /*status*/) {
1933     pos=0;
1934 }
1935 
1936 int32_t
count(UErrorCode &) const1937 FormatNameEnumeration::count(UErrorCode& /*status*/) const {
1938     return (fFormatNames==nullptr) ? 0 : fFormatNames->size();
1939 }
1940 
~FormatNameEnumeration()1941 FormatNameEnumeration::~FormatNameEnumeration() {
1942 }
1943 
PluralSelectorProvider(const MessageFormat & mf,UPluralType t)1944 MessageFormat::PluralSelectorProvider::PluralSelectorProvider(const MessageFormat &mf, UPluralType t)
1945         : msgFormat(mf), rules(nullptr), type(t) {
1946 }
1947 
~PluralSelectorProvider()1948 MessageFormat::PluralSelectorProvider::~PluralSelectorProvider() {
1949     delete rules;
1950 }
1951 
select(void * ctx,double number,UErrorCode & ec) const1952 UnicodeString MessageFormat::PluralSelectorProvider::select(void *ctx, double number,
1953                                                             UErrorCode& ec) const {
1954     if (U_FAILURE(ec)) {
1955         return UnicodeString(false, OTHER_STRING, 5);
1956     }
1957     MessageFormat::PluralSelectorProvider* t = const_cast<MessageFormat::PluralSelectorProvider*>(this);
1958     if(rules == nullptr) {
1959         t->rules = PluralRules::forLocale(msgFormat.fLocale, type, ec);
1960         if (U_FAILURE(ec)) {
1961             return UnicodeString(false, OTHER_STRING, 5);
1962         }
1963     }
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     PluralSelectorContext &context = *static_cast<PluralSelectorContext *>(ctx);
1971     int32_t otherIndex = msgFormat.findOtherSubMessage(context.startIndex);
1972     context.numberArgIndex = msgFormat.findFirstPluralNumberArg(otherIndex, context.argName);
1973     if(context.numberArgIndex > 0 && msgFormat.cachedFormatters != nullptr) {
1974         context.formatter =
1975             (const Format*)uhash_iget(msgFormat.cachedFormatters, context.numberArgIndex);
1976     }
1977     if(context.formatter == nullptr) {
1978         context.formatter = msgFormat.getDefaultNumberFormat(ec);
1979         context.forReplaceNumber = true;
1980     }
1981     if (context.number.getDouble(ec) != number) {
1982         ec = U_INTERNAL_PROGRAM_ERROR;
1983         return UnicodeString(false, OTHER_STRING, 5);
1984     }
1985     context.formatter->format(context.number, context.numberString, ec);
1986     auto* decFmt = dynamic_cast<const DecimalFormat *>(context.formatter);
1987     if(decFmt != nullptr) {
1988         number::impl::DecimalQuantity dq;
1989         decFmt->formatToDecimalQuantity(context.number, dq, ec);
1990         if (U_FAILURE(ec)) {
1991             return UnicodeString(false, OTHER_STRING, 5);
1992         }
1993         return rules->select(dq);
1994     } else {
1995         return rules->select(number);
1996     }
1997 }
1998 
reset()1999 void MessageFormat::PluralSelectorProvider::reset() {
2000     delete rules;
2001     rules = nullptr;
2002 }
2003 
2004 
2005 U_NAMESPACE_END
2006 
2007 #endif /* #if !UCONFIG_NO_FORMATTING */
2008 
2009 //eof
2010