• 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      ((UChar)0x0027)
59 #define COMMA             ((UChar)0x002C)
60 #define LEFT_CURLY_BRACE  ((UChar)0x007B)
61 #define RIGHT_CURLY_BRACE ((UChar)0x007D)
62 
63 //---------------------------------------
64 // static data
65 
66 static const UChar ID_NUMBER[]    = {
67     0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0  /* "number" */
68 };
69 static const UChar ID_DATE[]      = {
70     0x64, 0x61, 0x74, 0x65, 0              /* "date" */
71 };
72 static const UChar ID_TIME[]      = {
73     0x74, 0x69, 0x6D, 0x65, 0              /* "time" */
74 };
75 static const UChar ID_SPELLOUT[]  = {
76     0x73, 0x70, 0x65, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0 /* "spellout" */
77 };
78 static const UChar ID_ORDINAL[]   = {
79     0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0 /* "ordinal" */
80 };
81 static const UChar 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 UChar * const TYPE_IDS[] = {
87     ID_NUMBER,
88     ID_DATE,
89     ID_TIME,
90     ID_SPELLOUT,
91     ID_ORDINAL,
92     ID_DURATION,
93     NULL,
94 };
95 
96 static const UChar ID_EMPTY[]     = {
97     0 /* empty string, used for default so that null can mark end of list */
98 };
99 static const UChar ID_CURRENCY[]  = {
100     0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x63, 0x79, 0  /* "currency" */
101 };
102 static const UChar ID_PERCENT[]   = {
103     0x70, 0x65, 0x72, 0x63, 0x65, 0x6E, 0x74, 0        /* "percent" */
104 };
105 static const UChar 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 UChar * const NUMBER_STYLE_IDS[] = {
111     ID_EMPTY,
112     ID_CURRENCY,
113     ID_PERCENT,
114     ID_INTEGER,
115     NULL,
116 };
117 
118 static const UChar ID_SHORT[]     = {
119     0x73, 0x68, 0x6F, 0x72, 0x74, 0        /* "short" */
120 };
121 static const UChar ID_MEDIUM[]    = {
122     0x6D, 0x65, 0x64, 0x69, 0x75, 0x6D, 0  /* "medium" */
123 };
124 static const UChar ID_LONG[]      = {
125     0x6C, 0x6F, 0x6E, 0x67, 0              /* "long" */
126 };
127 static const UChar ID_FULL[]      = {
128     0x66, 0x75, 0x6C, 0x6C, 0              /* "full" */
129 };
130 
131 // DateFormat modifier list, default, short, medium, long or full
132 static const UChar * const DATE_STYLE_IDS[] = {
133     ID_EMPTY,
134     ID_SHORT,
135     ID_MEDIUM,
136     ID_LONG,
137     ID_FULL,
138     NULL,
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 UChar NULL_STRING[] = {
152     0x6E, 0x75, 0x6C, 0x6C, 0  // "null"
153 };
154 
155 static const UChar 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     UChar 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 UChar * s,const int32_t sLength)197     void append(const UChar* 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(NULL),
238   formatAliasesCapacity(0),
239   argTypes(NULL),
240   argTypeCount(0),
241   argTypeCapacity(0),
242   hasArgTypeConflicts(false),
243   defaultNumberFormat(NULL),
244   defaultDateFormat(NULL),
245   cachedFormatters(NULL),
246   customFormatArgStarts(NULL),
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(NULL),
260   formatAliasesCapacity(0),
261   argTypes(NULL),
262   argTypeCount(0),
263   argTypeCapacity(0),
264   hasArgTypeConflicts(false),
265   defaultNumberFormat(NULL),
266   defaultDateFormat(NULL),
267   cachedFormatters(NULL),
268   customFormatArgStarts(NULL),
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(NULL),
283   formatAliasesCapacity(0),
284   argTypes(NULL),
285   argTypeCount(0),
286   argTypeCapacity(0),
287   hasArgTypeConflicts(false),
288   defaultNumberFormat(NULL),
289   defaultDateFormat(NULL),
290   cachedFormatters(NULL),
291   customFormatArgStarts(NULL),
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(NULL),
305   formatAliasesCapacity(0),
306   argTypes(NULL),
307   argTypeCount(0),
308   argTypeCapacity(0),
309   hasArgTypeConflicts(that.hasArgTypeConflicts),
310   defaultNumberFormat(NULL),
311   defaultDateFormat(NULL),
312   cachedFormatters(NULL),
313   customFormatArgStarts(NULL),
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 NULL).
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 NULL, allocate it.  If it is not NULL, 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 == NULL) {
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     MessageFormat& that = (MessageFormat&)rhs;
398 
399     // Check class ID before checking MessageFormat members
400     if (!Format::operator==(rhs) ||
401         msgPattern != that.msgPattern ||
402         fLocale != that.fLocale) {
403         return false;
404     }
405 
406     // Compare hashtables.
407     if ((customFormatArgStarts == NULL) != (that.customFormatArgStarts == NULL)) {
408         return false;
409     }
410     if (customFormatArgStarts == NULL) {
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 = NULL;
454         delete defaultDateFormat;
455         defaultDateFormat = NULL;
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 = NULL;
504     uhash_close(customFormatArgStarts);
505     customFormatArgStarts = NULL;
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     applyPattern(pattern, *parseError, status);
519 }
520 
521 // -------------------------------------
522 // Converts this MessageFormat instance to a pattern.
523 
524 UnicodeString&
toPattern(UnicodeString & appendTo) const525 MessageFormat::toPattern(UnicodeString& appendTo) const {
526     if ((customFormatArgStarts != NULL && 0 != uhash_count(customFormatArgStarts)) ||
527         0 == msgPattern.countParts()
528     ) {
529         appendTo.setToBogus();
530         return appendTo;
531     }
532     return appendTo.append(msgPattern.getPatternString());
533 }
534 
nextTopLevelArgStart(int32_t partIndex) const535 int32_t MessageFormat::nextTopLevelArgStart(int32_t partIndex) const {
536     if (partIndex != 0) {
537         partIndex = msgPattern.getLimitPartIndex(partIndex);
538     }
539     for (;;) {
540         UMessagePatternPartType type = msgPattern.getPartType(++partIndex);
541         if (type == UMSGPAT_PART_TYPE_ARG_START) {
542             return partIndex;
543         }
544         if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) {
545             return -1;
546         }
547     }
548 }
549 
setArgStartFormat(int32_t argStart,Format * formatter,UErrorCode & status)550 void MessageFormat::setArgStartFormat(int32_t argStart,
551                                       Format* formatter,
552                                       UErrorCode& status) {
553     if (U_FAILURE(status)) {
554         delete formatter;
555         return;
556     }
557     if (cachedFormatters == NULL) {
558         cachedFormatters=uhash_open(uhash_hashLong, uhash_compareLong,
559                                     equalFormatsForHash, &status);
560         if (U_FAILURE(status)) {
561             delete formatter;
562             return;
563         }
564         uhash_setValueDeleter(cachedFormatters, uprv_deleteUObject);
565     }
566     if (formatter == NULL) {
567         formatter = new DummyFormat();
568     }
569     uhash_iput(cachedFormatters, argStart, formatter, &status);
570 }
571 
572 
argNameMatches(int32_t partIndex,const UnicodeString & argName,int32_t argNumber)573 UBool MessageFormat::argNameMatches(int32_t partIndex, const UnicodeString& argName, int32_t argNumber) {
574     const MessagePattern::Part& part = msgPattern.getPart(partIndex);
575     return part.getType() == UMSGPAT_PART_TYPE_ARG_NAME ?
576         msgPattern.partSubstringMatches(part, argName) :
577         part.getValue() == argNumber;  // ARG_NUMBER
578 }
579 
580 // Sets a custom formatter for a MessagePattern ARG_START part index.
581 // "Custom" formatters are provided by the user via setFormat() or similar APIs.
setCustomArgStartFormat(int32_t argStart,Format * formatter,UErrorCode & status)582 void MessageFormat::setCustomArgStartFormat(int32_t argStart,
583                                             Format* formatter,
584                                             UErrorCode& status) {
585     setArgStartFormat(argStart, formatter, status);
586     if (customFormatArgStarts == NULL) {
587         customFormatArgStarts=uhash_open(uhash_hashLong, uhash_compareLong,
588                                          NULL, &status);
589     }
590     uhash_iputi(customFormatArgStarts, argStart, 1, &status);
591 }
592 
getCachedFormatter(int32_t argumentNumber) const593 Format* MessageFormat::getCachedFormatter(int32_t argumentNumber) const {
594     if (cachedFormatters == NULL) {
595         return NULL;
596     }
597     void* ptr = uhash_iget(cachedFormatters, argumentNumber);
598     if (ptr != NULL && dynamic_cast<DummyFormat*>((Format*)ptr) == NULL) {
599         return (Format*) ptr;
600     } else {
601         // Not cached, or a DummyFormat representing setFormat(NULL).
602         return NULL;
603     }
604 }
605 
606 // -------------------------------------
607 // Adopts the new formats array and updates the array count.
608 // This MessageFormat instance owns the new formats.
609 void
adoptFormats(Format ** newFormats,int32_t count)610 MessageFormat::adoptFormats(Format** newFormats,
611                             int32_t count) {
612     if (newFormats == NULL || count < 0) {
613         return;
614     }
615     // Throw away any cached formatters.
616     if (cachedFormatters != NULL) {
617         uhash_removeAll(cachedFormatters);
618     }
619     if (customFormatArgStarts != NULL) {
620         uhash_removeAll(customFormatArgStarts);
621     }
622 
623     int32_t formatNumber = 0;
624     UErrorCode status = U_ZERO_ERROR;
625     for (int32_t partIndex = 0;
626         formatNumber < count && U_SUCCESS(status) &&
627             (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
628         setCustomArgStartFormat(partIndex, newFormats[formatNumber], status);
629         ++formatNumber;
630     }
631     // Delete those that didn't get used (if any).
632     for (; formatNumber < count; ++formatNumber) {
633         delete newFormats[formatNumber];
634     }
635 
636 }
637 
638 // -------------------------------------
639 // Sets the new formats array and updates the array count.
640 // This MessageFormat instance makes a copy of the new formats.
641 
642 void
setFormats(const Format ** newFormats,int32_t count)643 MessageFormat::setFormats(const Format** newFormats,
644                           int32_t count) {
645     if (newFormats == NULL || count < 0) {
646         return;
647     }
648     // Throw away any cached formatters.
649     if (cachedFormatters != NULL) {
650         uhash_removeAll(cachedFormatters);
651     }
652     if (customFormatArgStarts != NULL) {
653         uhash_removeAll(customFormatArgStarts);
654     }
655 
656     UErrorCode status = U_ZERO_ERROR;
657     int32_t formatNumber = 0;
658     for (int32_t partIndex = 0;
659         formatNumber < count && U_SUCCESS(status) && (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
660       Format* newFormat = NULL;
661       if (newFormats[formatNumber] != NULL) {
662           newFormat = newFormats[formatNumber]->clone();
663           if (newFormat == NULL) {
664               status = U_MEMORY_ALLOCATION_ERROR;
665           }
666       }
667       setCustomArgStartFormat(partIndex, newFormat, status);
668       ++formatNumber;
669     }
670     if (U_FAILURE(status)) {
671         resetPattern();
672     }
673 }
674 
675 // -------------------------------------
676 // Adopt a single format by format number.
677 // Do nothing if the format number is not less than the array count.
678 
679 void
adoptFormat(int32_t n,Format * newFormat)680 MessageFormat::adoptFormat(int32_t n, Format *newFormat) {
681     LocalPointer<Format> p(newFormat);
682     if (n >= 0) {
683         int32_t formatNumber = 0;
684         for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
685             if (n == formatNumber) {
686                 UErrorCode status = U_ZERO_ERROR;
687                 setCustomArgStartFormat(partIndex, p.orphan(), status);
688                 return;
689             }
690             ++formatNumber;
691         }
692     }
693 }
694 
695 // -------------------------------------
696 // Adopt a single format by format name.
697 // Do nothing if there is no match of formatName.
698 void
adoptFormat(const UnicodeString & formatName,Format * formatToAdopt,UErrorCode & status)699 MessageFormat::adoptFormat(const UnicodeString& formatName,
700                            Format* formatToAdopt,
701                            UErrorCode& status) {
702     LocalPointer<Format> p(formatToAdopt);
703     if (U_FAILURE(status)) {
704         return;
705     }
706     int32_t argNumber = MessagePattern::validateArgumentName(formatName);
707     if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) {
708         status = U_ILLEGAL_ARGUMENT_ERROR;
709         return;
710     }
711     for (int32_t partIndex = 0;
712         (partIndex = nextTopLevelArgStart(partIndex)) >= 0 && U_SUCCESS(status);
713     ) {
714         if (argNameMatches(partIndex + 1, formatName, argNumber)) {
715             Format* f;
716             if (p.isValid()) {
717                 f = p.orphan();
718             } else if (formatToAdopt == NULL) {
719                 f = NULL;
720             } else {
721                 f = formatToAdopt->clone();
722                 if (f == NULL) {
723                     status = U_MEMORY_ALLOCATION_ERROR;
724                     return;
725                 }
726             }
727             setCustomArgStartFormat(partIndex, f, status);
728         }
729     }
730 }
731 
732 // -------------------------------------
733 // Set a single format.
734 // Do nothing if the variable is not less than the array count.
735 void
setFormat(int32_t n,const Format & newFormat)736 MessageFormat::setFormat(int32_t n, const Format& newFormat) {
737 
738     if (n >= 0) {
739         int32_t formatNumber = 0;
740         for (int32_t partIndex = 0;
741              (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
742             if (n == formatNumber) {
743                 Format* new_format = newFormat.clone();
744                 if (new_format) {
745                     UErrorCode status = U_ZERO_ERROR;
746                     setCustomArgStartFormat(partIndex, new_format, status);
747                 }
748                 return;
749             }
750             ++formatNumber;
751         }
752     }
753 }
754 
755 // -------------------------------------
756 // Get a single format by format name.
757 // Do nothing if the variable is not less than the array count.
758 Format *
getFormat(const UnicodeString & formatName,UErrorCode & status)759 MessageFormat::getFormat(const UnicodeString& formatName, UErrorCode& status) {
760     if (U_FAILURE(status) || cachedFormatters == NULL) return NULL;
761 
762     int32_t argNumber = MessagePattern::validateArgumentName(formatName);
763     if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) {
764         status = U_ILLEGAL_ARGUMENT_ERROR;
765         return NULL;
766     }
767     for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
768         if (argNameMatches(partIndex + 1, formatName, argNumber)) {
769             return getCachedFormatter(partIndex);
770         }
771     }
772     return NULL;
773 }
774 
775 // -------------------------------------
776 // Set a single format by format name
777 // Do nothing if the variable is not less than the array count.
778 void
setFormat(const UnicodeString & formatName,const Format & newFormat,UErrorCode & status)779 MessageFormat::setFormat(const UnicodeString& formatName,
780                          const Format& newFormat,
781                          UErrorCode& status) {
782     if (U_FAILURE(status)) return;
783 
784     int32_t argNumber = MessagePattern::validateArgumentName(formatName);
785     if (argNumber < UMSGPAT_ARG_NAME_NOT_NUMBER) {
786         status = U_ILLEGAL_ARGUMENT_ERROR;
787         return;
788     }
789     for (int32_t partIndex = 0;
790         (partIndex = nextTopLevelArgStart(partIndex)) >= 0 && U_SUCCESS(status);
791     ) {
792         if (argNameMatches(partIndex + 1, formatName, argNumber)) {
793             Format* new_format = newFormat.clone();
794             if (new_format == NULL) {
795                 status = U_MEMORY_ALLOCATION_ERROR;
796                 return;
797             }
798             setCustomArgStartFormat(partIndex, new_format, status);
799         }
800     }
801 }
802 
803 // -------------------------------------
804 // Gets the format array.
805 const Format**
getFormats(int32_t & cnt) const806 MessageFormat::getFormats(int32_t& cnt) const
807 {
808     // This old API returns an array (which we hold) of Format*
809     // pointers.  The array is valid up to the next call to any
810     // method on this object.  We construct and resize an array
811     // on demand that contains aliases to the subformats[i].format
812     // pointers.
813 
814     // Get total required capacity first (it's refreshed on each call).
815     int32_t totalCapacity = 0;
816     for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0; ++totalCapacity) {}
817 
818     MessageFormat* t = const_cast<MessageFormat*> (this);
819     cnt = 0;
820     if (formatAliases == nullptr) {
821         t->formatAliasesCapacity = totalCapacity;
822         Format** a = (Format**)
823             uprv_malloc(sizeof(Format*) * formatAliasesCapacity);
824         if (a == nullptr) {
825             t->formatAliasesCapacity = 0;
826             return nullptr;
827         }
828         t->formatAliases = a;
829     } else if (totalCapacity > formatAliasesCapacity) {
830         Format** a = (Format**)
831             uprv_realloc(formatAliases, sizeof(Format*) * totalCapacity);
832         if (a == nullptr) {
833             t->formatAliasesCapacity = 0;
834             return nullptr;
835         }
836         t->formatAliases = a;
837         t->formatAliasesCapacity = totalCapacity;
838     }
839 
840     for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
841         t->formatAliases[cnt++] = getCachedFormatter(partIndex);
842     }
843 
844     return (const Format**)formatAliases;
845 }
846 
847 
getArgName(int32_t partIndex)848 UnicodeString MessageFormat::getArgName(int32_t partIndex) {
849     const MessagePattern::Part& part = msgPattern.getPart(partIndex);
850     return msgPattern.getSubstring(part);
851 }
852 
853 StringEnumeration*
getFormatNames(UErrorCode & status)854 MessageFormat::getFormatNames(UErrorCode& status) {
855     if (U_FAILURE(status))  return NULL;
856 
857     LocalPointer<UVector> formatNames(new UVector(status), status);
858     if (U_FAILURE(status)) {
859         return nullptr;
860     }
861     formatNames->setDeleter(uprv_deleteUObject);
862 
863     for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
864         LocalPointer<UnicodeString> name(getArgName(partIndex + 1).clone(), status);
865         formatNames->adoptElement(name.orphan(), status);
866         if (U_FAILURE(status))  return nullptr;
867     }
868 
869     LocalPointer<StringEnumeration> nameEnumerator(
870         new FormatNameEnumeration(std::move(formatNames), status), status);
871     return U_SUCCESS(status) ? nameEnumerator.orphan() : nullptr;
872 }
873 
874 // -------------------------------------
875 // Formats the source Formattable array and copy into the result buffer.
876 // Ignore the FieldPosition result for error checking.
877 
878 UnicodeString&
format(const Formattable * source,int32_t cnt,UnicodeString & appendTo,FieldPosition & ignore,UErrorCode & success) const879 MessageFormat::format(const Formattable* source,
880                       int32_t cnt,
881                       UnicodeString& appendTo,
882                       FieldPosition& ignore,
883                       UErrorCode& success) const
884 {
885     return format(source, NULL, cnt, appendTo, &ignore, success);
886 }
887 
888 // -------------------------------------
889 // Internally creates a MessageFormat instance based on the
890 // pattern and formats the arguments Formattable array and
891 // copy into the appendTo buffer.
892 
893 UnicodeString&
format(const UnicodeString & pattern,const Formattable * arguments,int32_t cnt,UnicodeString & appendTo,UErrorCode & success)894 MessageFormat::format(  const UnicodeString& pattern,
895                         const Formattable* arguments,
896                         int32_t cnt,
897                         UnicodeString& appendTo,
898                         UErrorCode& success)
899 {
900     MessageFormat temp(pattern, success);
901     return temp.format(arguments, NULL, cnt, appendTo, NULL, success);
902 }
903 
904 // -------------------------------------
905 // Formats the source Formattable object and copy into the
906 // appendTo buffer.  The Formattable object must be an array
907 // of Formattable instances, returns error otherwise.
908 
909 UnicodeString&
format(const Formattable & source,UnicodeString & appendTo,FieldPosition & ignore,UErrorCode & success) const910 MessageFormat::format(const Formattable& source,
911                       UnicodeString& appendTo,
912                       FieldPosition& ignore,
913                       UErrorCode& success) const
914 {
915     if (U_FAILURE(success))
916         return appendTo;
917     if (source.getType() != Formattable::kArray) {
918         success = U_ILLEGAL_ARGUMENT_ERROR;
919         return appendTo;
920     }
921     int32_t cnt;
922     const Formattable* tmpPtr = source.getArray(cnt);
923     return format(tmpPtr, NULL, cnt, appendTo, &ignore, success);
924 }
925 
926 UnicodeString&
format(const UnicodeString * argumentNames,const Formattable * arguments,int32_t count,UnicodeString & appendTo,UErrorCode & success) const927 MessageFormat::format(const UnicodeString* argumentNames,
928                       const Formattable* arguments,
929                       int32_t count,
930                       UnicodeString& appendTo,
931                       UErrorCode& success) const {
932     return format(arguments, argumentNames, count, appendTo, NULL, success);
933 }
934 
935 // Does linear search to find the match for an ArgName.
getArgFromListByName(const Formattable * arguments,const UnicodeString * argumentNames,int32_t cnt,UnicodeString & name) const936 const Formattable* MessageFormat::getArgFromListByName(const Formattable* arguments,
937                                                        const UnicodeString *argumentNames,
938                                                        int32_t cnt, UnicodeString& name) const {
939     for (int32_t i = 0; i < cnt; ++i) {
940         if (0 == argumentNames[i].compare(name)) {
941             return arguments + i;
942         }
943     }
944     return NULL;
945 }
946 
947 
948 UnicodeString&
format(const Formattable * arguments,const UnicodeString * argumentNames,int32_t cnt,UnicodeString & appendTo,FieldPosition * pos,UErrorCode & status) const949 MessageFormat::format(const Formattable* arguments,
950                       const UnicodeString *argumentNames,
951                       int32_t cnt,
952                       UnicodeString& appendTo,
953                       FieldPosition* pos,
954                       UErrorCode& status) const {
955     if (U_FAILURE(status)) {
956         return appendTo;
957     }
958 
959     UnicodeStringAppendable usapp(appendTo);
960     AppendableWrapper app(usapp);
961     format(0, NULL, arguments, argumentNames, cnt, app, pos, status);
962     return appendTo;
963 }
964 
965 namespace {
966 
967 /**
968  * Mutable input/output values for the PluralSelectorProvider.
969  * Separate so that it is possible to make MessageFormat Freezable.
970  */
971 class PluralSelectorContext {
972 public:
PluralSelectorContext(int32_t start,const UnicodeString & name,const Formattable & num,double off,UErrorCode & errorCode)973     PluralSelectorContext(int32_t start, const UnicodeString &name,
974                           const Formattable &num, double off, UErrorCode &errorCode)
975             : startIndex(start), argName(name), offset(off),
976               numberArgIndex(-1), formatter(NULL), forReplaceNumber(false) {
977         // number needs to be set even when select() is not called.
978         // Keep it as a Number/Formattable:
979         // For format() methods, and to preserve information (e.g., BigDecimal).
980         if(off == 0) {
981             number = num;
982         } else {
983             number = num.getDouble(errorCode) - off;
984         }
985     }
986 
987     // Input values for plural selection with decimals.
988     int32_t startIndex;
989     const UnicodeString &argName;
990     /** argument number - plural offset */
991     Formattable number;
992     double offset;
993     // Output values for plural selection with decimals.
994     /** -1 if REPLACE_NUMBER, 0 arg not found, >0 ARG_START index */
995     int32_t numberArgIndex;
996     const Format *formatter;
997     /** formatted argument number - plural offset */
998     UnicodeString numberString;
999     /** true if number-offset was formatted with the stock number formatter */
1000     UBool forReplaceNumber;
1001 };
1002 
1003 }  // namespace
1004 
1005 // if argumentNames is NULL, this means arguments is a numeric array.
1006 // arguments can not be NULL.
1007 // We use const void *plNumber rather than const PluralSelectorContext *pluralNumber
1008 // 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) const1009 void MessageFormat::format(int32_t msgStart, const void *plNumber,
1010                            const Formattable* arguments,
1011                            const UnicodeString *argumentNames,
1012                            int32_t cnt,
1013                            AppendableWrapper& appendTo,
1014                            FieldPosition* ignore,
1015                            UErrorCode& success) const {
1016     if (U_FAILURE(success)) {
1017         return;
1018     }
1019 
1020     const UnicodeString& msgString = msgPattern.getPatternString();
1021     int32_t prevIndex = msgPattern.getPart(msgStart).getLimit();
1022     for (int32_t i = msgStart + 1; U_SUCCESS(success) ; ++i) {
1023         const MessagePattern::Part* part = &msgPattern.getPart(i);
1024         const UMessagePatternPartType type = part->getType();
1025         int32_t index = part->getIndex();
1026         appendTo.append(msgString, prevIndex, index - prevIndex);
1027         if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) {
1028             return;
1029         }
1030         prevIndex = part->getLimit();
1031         if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER) {
1032             const PluralSelectorContext &pluralNumber =
1033                 *static_cast<const PluralSelectorContext *>(plNumber);
1034             if(pluralNumber.forReplaceNumber) {
1035                 // number-offset was already formatted.
1036                 appendTo.formatAndAppend(pluralNumber.formatter,
1037                         pluralNumber.number, pluralNumber.numberString, success);
1038             } else {
1039                 const NumberFormat* nf = getDefaultNumberFormat(success);
1040                 appendTo.formatAndAppend(nf, pluralNumber.number, success);
1041             }
1042             continue;
1043         }
1044         if (type != UMSGPAT_PART_TYPE_ARG_START) {
1045             continue;
1046         }
1047         int32_t argLimit = msgPattern.getLimitPartIndex(i);
1048         UMessagePatternArgType argType = part->getArgType();
1049         part = &msgPattern.getPart(++i);
1050         const Formattable* arg;
1051         UBool noArg = false;
1052         UnicodeString argName = msgPattern.getSubstring(*part);
1053         if (argumentNames == NULL) {
1054             int32_t argNumber = part->getValue();  // ARG_NUMBER
1055             if (0 <= argNumber && argNumber < cnt) {
1056                 arg = arguments + argNumber;
1057             } else {
1058                 arg = NULL;
1059                 noArg = true;
1060             }
1061         } else {
1062             arg = getArgFromListByName(arguments, argumentNames, cnt, argName);
1063             if (arg == NULL) {
1064                 noArg = true;
1065             }
1066         }
1067         ++i;
1068         int32_t prevDestLength = appendTo.length();
1069         const Format* formatter = NULL;
1070         if (noArg) {
1071             appendTo.append(
1072                 UnicodeString(LEFT_CURLY_BRACE).append(argName).append(RIGHT_CURLY_BRACE));
1073         } else if (arg == NULL) {
1074             appendTo.append(NULL_STRING, 4);
1075         } else if(plNumber!=NULL &&
1076                 static_cast<const PluralSelectorContext *>(plNumber)->numberArgIndex==(i-2)) {
1077             const PluralSelectorContext &pluralNumber =
1078                 *static_cast<const PluralSelectorContext *>(plNumber);
1079             if(pluralNumber.offset == 0) {
1080                 // The number was already formatted with this formatter.
1081                 appendTo.formatAndAppend(pluralNumber.formatter, pluralNumber.number,
1082                                          pluralNumber.numberString, success);
1083             } else {
1084                 // Do not use the formatted (number-offset) string for a named argument
1085                 // that formats the number without subtracting the offset.
1086                 appendTo.formatAndAppend(pluralNumber.formatter, *arg, success);
1087             }
1088         } else if ((formatter = getCachedFormatter(i -2)) != 0) {
1089             // Handles all ArgType.SIMPLE, and formatters from setFormat() and its siblings.
1090             if (dynamic_cast<const ChoiceFormat*>(formatter) ||
1091                 dynamic_cast<const PluralFormat*>(formatter) ||
1092                 dynamic_cast<const SelectFormat*>(formatter)) {
1093                 // We only handle nested formats here if they were provided via
1094                 // setFormat() or its siblings. Otherwise they are not cached and instead
1095                 // handled below according to argType.
1096                 UnicodeString subMsgString;
1097                 formatter->format(*arg, subMsgString, success);
1098                 if (subMsgString.indexOf(LEFT_CURLY_BRACE) >= 0 ||
1099                     (subMsgString.indexOf(SINGLE_QUOTE) >= 0 && !MessageImpl::jdkAposMode(msgPattern))
1100                 ) {
1101                     MessageFormat subMsgFormat(subMsgString, fLocale, success);
1102                     subMsgFormat.format(0, NULL, arguments, argumentNames, cnt, appendTo, ignore, success);
1103                 } else {
1104                     appendTo.append(subMsgString);
1105                 }
1106             } else {
1107                 appendTo.formatAndAppend(formatter, *arg, success);
1108             }
1109         } else if (argType == UMSGPAT_ARG_TYPE_NONE || (cachedFormatters && uhash_iget(cachedFormatters, i - 2))) {
1110             // We arrive here if getCachedFormatter returned NULL, but there was actually an element in the hash table.
1111             // This can only happen if the hash table contained a DummyFormat, so the if statement above is a check
1112             // for the hash table containing DummyFormat.
1113             if (arg->isNumeric()) {
1114                 const NumberFormat* nf = getDefaultNumberFormat(success);
1115                 appendTo.formatAndAppend(nf, *arg, success);
1116             } else if (arg->getType() == Formattable::kDate) {
1117                 const DateFormat* df = getDefaultDateFormat(success);
1118                 appendTo.formatAndAppend(df, *arg, success);
1119             } else {
1120                 appendTo.append(arg->getString(success));
1121             }
1122         } else if (argType == UMSGPAT_ARG_TYPE_CHOICE) {
1123             if (!arg->isNumeric()) {
1124                 success = U_ILLEGAL_ARGUMENT_ERROR;
1125                 return;
1126             }
1127             // We must use the Formattable::getDouble() variant with the UErrorCode parameter
1128             // because only this one converts non-double numeric types to double.
1129             const double number = arg->getDouble(success);
1130             int32_t subMsgStart = ChoiceFormat::findSubMessage(msgPattern, i, number);
1131             formatComplexSubMessage(subMsgStart, NULL, arguments, argumentNames,
1132                                     cnt, appendTo, success);
1133         } else if (UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType)) {
1134             if (!arg->isNumeric()) {
1135                 success = U_ILLEGAL_ARGUMENT_ERROR;
1136                 return;
1137             }
1138             const PluralSelectorProvider &selector =
1139                 argType == UMSGPAT_ARG_TYPE_PLURAL ? pluralProvider : ordinalProvider;
1140             // We must use the Formattable::getDouble() variant with the UErrorCode parameter
1141             // because only this one converts non-double numeric types to double.
1142             double offset = msgPattern.getPluralOffset(i);
1143             PluralSelectorContext context(i, argName, *arg, offset, success);
1144             int32_t subMsgStart = PluralFormat::findSubMessage(
1145                     msgPattern, i, selector, &context, arg->getDouble(success), success);
1146             formatComplexSubMessage(subMsgStart, &context, arguments, argumentNames,
1147                                     cnt, appendTo, success);
1148         } else if (argType == UMSGPAT_ARG_TYPE_SELECT) {
1149             int32_t subMsgStart = SelectFormat::findSubMessage(msgPattern, i, arg->getString(success), success);
1150             formatComplexSubMessage(subMsgStart, NULL, arguments, argumentNames,
1151                                     cnt, appendTo, success);
1152         } else {
1153             // This should never happen.
1154             success = U_INTERNAL_PROGRAM_ERROR;
1155             return;
1156         }
1157         ignore = updateMetaData(appendTo, prevDestLength, ignore, arg);
1158         prevIndex = msgPattern.getPart(argLimit).getLimit();
1159         i = argLimit;
1160     }
1161 }
1162 
1163 
formatComplexSubMessage(int32_t msgStart,const void * plNumber,const Formattable * arguments,const UnicodeString * argumentNames,int32_t cnt,AppendableWrapper & appendTo,UErrorCode & success) const1164 void MessageFormat::formatComplexSubMessage(int32_t msgStart,
1165                                             const void *plNumber,
1166                                             const Formattable* arguments,
1167                                             const UnicodeString *argumentNames,
1168                                             int32_t cnt,
1169                                             AppendableWrapper& appendTo,
1170                                             UErrorCode& success) const {
1171     if (U_FAILURE(success)) {
1172         return;
1173     }
1174 
1175     if (!MessageImpl::jdkAposMode(msgPattern)) {
1176         format(msgStart, plNumber, arguments, argumentNames, cnt, appendTo, NULL, success);
1177         return;
1178     }
1179 
1180     // JDK compatibility mode: (see JDK MessageFormat.format() API docs)
1181     // - remove SKIP_SYNTAX; that is, remove half of the apostrophes
1182     // - if the result string contains an open curly brace '{' then
1183     //   instantiate a temporary MessageFormat object and format again;
1184     //   otherwise just append the result string
1185     const UnicodeString& msgString = msgPattern.getPatternString();
1186     UnicodeString sb;
1187     int32_t prevIndex = msgPattern.getPart(msgStart).getLimit();
1188     for (int32_t i = msgStart;;) {
1189         const MessagePattern::Part& part = msgPattern.getPart(++i);
1190         const UMessagePatternPartType type = part.getType();
1191         int32_t index = part.getIndex();
1192         if (type == UMSGPAT_PART_TYPE_MSG_LIMIT) {
1193             sb.append(msgString, prevIndex, index - prevIndex);
1194             break;
1195         } else if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER || type == UMSGPAT_PART_TYPE_SKIP_SYNTAX) {
1196             sb.append(msgString, prevIndex, index - prevIndex);
1197             if (type == UMSGPAT_PART_TYPE_REPLACE_NUMBER) {
1198                 const PluralSelectorContext &pluralNumber =
1199                     *static_cast<const PluralSelectorContext *>(plNumber);
1200                 if(pluralNumber.forReplaceNumber) {
1201                     // number-offset was already formatted.
1202                     sb.append(pluralNumber.numberString);
1203                 } else {
1204                     const NumberFormat* nf = getDefaultNumberFormat(success);
1205                     sb.append(nf->format(pluralNumber.number, sb, success));
1206                 }
1207             }
1208             prevIndex = part.getLimit();
1209         } else if (type == UMSGPAT_PART_TYPE_ARG_START) {
1210             sb.append(msgString, prevIndex, index - prevIndex);
1211             prevIndex = index;
1212             i = msgPattern.getLimitPartIndex(i);
1213             index = msgPattern.getPart(i).getLimit();
1214             MessageImpl::appendReducedApostrophes(msgString, prevIndex, index, sb);
1215             prevIndex = index;
1216         }
1217     }
1218     if (sb.indexOf(LEFT_CURLY_BRACE) >= 0) {
1219         UnicodeString emptyPattern;  // gcc 3.3.3 fails with "UnicodeString()" as the first parameter.
1220         MessageFormat subMsgFormat(emptyPattern, fLocale, success);
1221         subMsgFormat.applyPattern(sb, UMSGPAT_APOS_DOUBLE_REQUIRED, NULL, success);
1222         subMsgFormat.format(0, NULL, arguments, argumentNames, cnt, appendTo, NULL, success);
1223     } else {
1224         appendTo.append(sb);
1225     }
1226 }
1227 
1228 
getLiteralStringUntilNextArgument(int32_t from) const1229 UnicodeString MessageFormat::getLiteralStringUntilNextArgument(int32_t from) const {
1230     const UnicodeString& msgString=msgPattern.getPatternString();
1231     int32_t prevIndex=msgPattern.getPart(from).getLimit();
1232     UnicodeString b;
1233     for (int32_t i = from + 1; ; ++i) {
1234         const MessagePattern::Part& part = msgPattern.getPart(i);
1235         const UMessagePatternPartType type=part.getType();
1236         int32_t index=part.getIndex();
1237         b.append(msgString, prevIndex, index - prevIndex);
1238         if(type==UMSGPAT_PART_TYPE_ARG_START || type==UMSGPAT_PART_TYPE_MSG_LIMIT) {
1239             return b;
1240         }
1241         // Unexpected Part "part" in parsed message.
1242         U_ASSERT(type==UMSGPAT_PART_TYPE_SKIP_SYNTAX || type==UMSGPAT_PART_TYPE_INSERT_CHAR);
1243         prevIndex=part.getLimit();
1244     }
1245 }
1246 
1247 
updateMetaData(AppendableWrapper &,int32_t,FieldPosition *,const Formattable *) const1248 FieldPosition* MessageFormat::updateMetaData(AppendableWrapper& /*dest*/, int32_t /*prevLength*/,
1249                              FieldPosition* /*fp*/, const Formattable* /*argId*/) const {
1250     // Unlike in Java, there are no field attributes defined for MessageFormat. Do nothing.
1251     return NULL;
1252     /*
1253       if (fp != NULL && Field.ARGUMENT.equals(fp.getFieldAttribute())) {
1254           fp->setBeginIndex(prevLength);
1255           fp->setEndIndex(dest.get_length());
1256           return NULL;
1257       }
1258       return fp;
1259     */
1260 }
1261 
1262 int32_t
findOtherSubMessage(int32_t partIndex) const1263 MessageFormat::findOtherSubMessage(int32_t partIndex) const {
1264     int32_t count=msgPattern.countParts();
1265     const MessagePattern::Part *part = &msgPattern.getPart(partIndex);
1266     if(MessagePattern::Part::hasNumericValue(part->getType())) {
1267         ++partIndex;
1268     }
1269     // Iterate over (ARG_SELECTOR [ARG_INT|ARG_DOUBLE] message) tuples
1270     // until ARG_LIMIT or end of plural-only pattern.
1271     UnicodeString other(false, OTHER_STRING, 5);
1272     do {
1273         part=&msgPattern.getPart(partIndex++);
1274         UMessagePatternPartType type=part->getType();
1275         if(type==UMSGPAT_PART_TYPE_ARG_LIMIT) {
1276             break;
1277         }
1278         U_ASSERT(type==UMSGPAT_PART_TYPE_ARG_SELECTOR);
1279         // part is an ARG_SELECTOR followed by an optional explicit value, and then a message
1280         if(msgPattern.partSubstringMatches(*part, other)) {
1281             return partIndex;
1282         }
1283         if(MessagePattern::Part::hasNumericValue(msgPattern.getPartType(partIndex))) {
1284             ++partIndex;  // skip the numeric-value part of "=1" etc.
1285         }
1286         partIndex=msgPattern.getLimitPartIndex(partIndex);
1287     } while(++partIndex<count);
1288     return 0;
1289 }
1290 
1291 int32_t
findFirstPluralNumberArg(int32_t msgStart,const UnicodeString & argName) const1292 MessageFormat::findFirstPluralNumberArg(int32_t msgStart, const UnicodeString &argName) const {
1293     for(int32_t i=msgStart+1;; ++i) {
1294         const MessagePattern::Part &part=msgPattern.getPart(i);
1295         UMessagePatternPartType type=part.getType();
1296         if(type==UMSGPAT_PART_TYPE_MSG_LIMIT) {
1297             return 0;
1298         }
1299         if(type==UMSGPAT_PART_TYPE_REPLACE_NUMBER) {
1300             return -1;
1301         }
1302         if(type==UMSGPAT_PART_TYPE_ARG_START) {
1303             UMessagePatternArgType argType=part.getArgType();
1304             if(!argName.isEmpty() && (argType==UMSGPAT_ARG_TYPE_NONE || argType==UMSGPAT_ARG_TYPE_SIMPLE)) {
1305                 // ARG_NUMBER or ARG_NAME
1306                 if(msgPattern.partSubstringMatches(msgPattern.getPart(i+1), argName)) {
1307                     return i;
1308                 }
1309             }
1310             i=msgPattern.getLimitPartIndex(i);
1311         }
1312     }
1313 }
1314 
copyObjects(const MessageFormat & that,UErrorCode & ec)1315 void MessageFormat::copyObjects(const MessageFormat& that, UErrorCode& ec) {
1316     // Deep copy pointer fields.
1317     // We need not copy the formatAliases because they are re-filled
1318     // in each getFormats() call.
1319     // The defaultNumberFormat, defaultDateFormat and pluralProvider.rules
1320     // also get created on demand.
1321     argTypeCount = that.argTypeCount;
1322     if (argTypeCount > 0) {
1323         if (!allocateArgTypes(argTypeCount, ec)) {
1324             return;
1325         }
1326         uprv_memcpy(argTypes, that.argTypes, argTypeCount * sizeof(argTypes[0]));
1327     }
1328     if (cachedFormatters != NULL) {
1329         uhash_removeAll(cachedFormatters);
1330     }
1331     if (customFormatArgStarts != NULL) {
1332         uhash_removeAll(customFormatArgStarts);
1333     }
1334     if (that.cachedFormatters) {
1335         if (cachedFormatters == NULL) {
1336             cachedFormatters=uhash_open(uhash_hashLong, uhash_compareLong,
1337                                         equalFormatsForHash, &ec);
1338             if (U_FAILURE(ec)) {
1339                 return;
1340             }
1341             uhash_setValueDeleter(cachedFormatters, uprv_deleteUObject);
1342         }
1343 
1344         const int32_t count = uhash_count(that.cachedFormatters);
1345         int32_t pos, idx;
1346         for (idx = 0, pos = UHASH_FIRST; idx < count && U_SUCCESS(ec); ++idx) {
1347             const UHashElement* cur = uhash_nextElement(that.cachedFormatters, &pos);
1348             Format* newFormat = ((Format*)(cur->value.pointer))->clone();
1349             if (newFormat) {
1350                 uhash_iput(cachedFormatters, cur->key.integer, newFormat, &ec);
1351             } else {
1352                 ec = U_MEMORY_ALLOCATION_ERROR;
1353                 return;
1354             }
1355         }
1356     }
1357     if (that.customFormatArgStarts) {
1358         if (customFormatArgStarts == NULL) {
1359             customFormatArgStarts=uhash_open(uhash_hashLong, uhash_compareLong,
1360                                               NULL, &ec);
1361         }
1362         const int32_t count = uhash_count(that.customFormatArgStarts);
1363         int32_t pos, idx;
1364         for (idx = 0, pos = UHASH_FIRST; idx < count && U_SUCCESS(ec); ++idx) {
1365             const UHashElement* cur = uhash_nextElement(that.customFormatArgStarts, &pos);
1366             uhash_iputi(customFormatArgStarts, cur->key.integer, cur->value.integer, &ec);
1367         }
1368     }
1369 }
1370 
1371 
1372 Formattable*
parse(int32_t msgStart,const UnicodeString & source,ParsePosition & pos,int32_t & count,UErrorCode & ec) const1373 MessageFormat::parse(int32_t msgStart,
1374                      const UnicodeString& source,
1375                      ParsePosition& pos,
1376                      int32_t& count,
1377                      UErrorCode& ec) const {
1378     count = 0;
1379     if (U_FAILURE(ec)) {
1380         pos.setErrorIndex(pos.getIndex());
1381         return NULL;
1382     }
1383     // parse() does not work with named arguments.
1384     if (msgPattern.hasNamedArguments()) {
1385         ec = U_ARGUMENT_TYPE_MISMATCH;
1386         pos.setErrorIndex(pos.getIndex());
1387         return NULL;
1388     }
1389     LocalArray<Formattable> resultArray(new Formattable[argTypeCount ? argTypeCount : 1]);
1390     const UnicodeString& msgString=msgPattern.getPatternString();
1391     int32_t prevIndex=msgPattern.getPart(msgStart).getLimit();
1392     int32_t sourceOffset = pos.getIndex();
1393     ParsePosition tempStatus(0);
1394 
1395     for(int32_t i=msgStart+1; ; ++i) {
1396         UBool haveArgResult = false;
1397         const MessagePattern::Part* part=&msgPattern.getPart(i);
1398         const UMessagePatternPartType type=part->getType();
1399         int32_t index=part->getIndex();
1400         // Make sure the literal string matches.
1401         int32_t len = index - prevIndex;
1402         if (len == 0 || (0 == msgString.compare(prevIndex, len, source, sourceOffset, len))) {
1403             sourceOffset += len;
1404             prevIndex += len;
1405         } else {
1406             pos.setErrorIndex(sourceOffset);
1407             return NULL; // leave index as is to signal error
1408         }
1409         if(type==UMSGPAT_PART_TYPE_MSG_LIMIT) {
1410             // Things went well! Done.
1411             pos.setIndex(sourceOffset);
1412             return resultArray.orphan();
1413         }
1414         if(type==UMSGPAT_PART_TYPE_SKIP_SYNTAX || type==UMSGPAT_PART_TYPE_INSERT_CHAR) {
1415             prevIndex=part->getLimit();
1416             continue;
1417         }
1418         // We do not support parsing Plural formats. (No REPLACE_NUMBER here.)
1419         // Unexpected Part "part" in parsed message.
1420         U_ASSERT(type==UMSGPAT_PART_TYPE_ARG_START);
1421         int32_t argLimit=msgPattern.getLimitPartIndex(i);
1422 
1423         UMessagePatternArgType argType=part->getArgType();
1424         part=&msgPattern.getPart(++i);
1425         int32_t argNumber = part->getValue();  // ARG_NUMBER
1426         UnicodeString key;
1427         ++i;
1428         const Format* formatter = NULL;
1429         Formattable& argResult = resultArray[argNumber];
1430 
1431         if(cachedFormatters!=NULL && (formatter = getCachedFormatter(i - 2))!=NULL) {
1432             // Just parse using the formatter.
1433             tempStatus.setIndex(sourceOffset);
1434             formatter->parseObject(source, argResult, tempStatus);
1435             if (tempStatus.getIndex() == sourceOffset) {
1436                 pos.setErrorIndex(sourceOffset);
1437                 return NULL; // leave index as is to signal error
1438             }
1439             sourceOffset = tempStatus.getIndex();
1440             haveArgResult = true;
1441         } else if(
1442             argType==UMSGPAT_ARG_TYPE_NONE || (cachedFormatters && uhash_iget(cachedFormatters, i -2))) {
1443             // We arrive here if getCachedFormatter returned NULL, but there was actually an element in the hash table.
1444             // This can only happen if the hash table contained a DummyFormat, so the if statement above is a check
1445             // for the hash table containing DummyFormat.
1446 
1447             // Match as a string.
1448             // if at end, use longest possible match
1449             // otherwise uses first match to intervening string
1450             // does NOT recursively try all possibilities
1451             UnicodeString stringAfterArgument = getLiteralStringUntilNextArgument(argLimit);
1452             int32_t next;
1453             if (!stringAfterArgument.isEmpty()) {
1454                 next = source.indexOf(stringAfterArgument, sourceOffset);
1455             } else {
1456                 next = source.length();
1457             }
1458             if (next < 0) {
1459                 pos.setErrorIndex(sourceOffset);
1460                 return NULL; // leave index as is to signal error
1461             } else {
1462                 UnicodeString strValue(source.tempSubString(sourceOffset, next - sourceOffset));
1463                 UnicodeString compValue;
1464                 compValue.append(LEFT_CURLY_BRACE);
1465                 itos(argNumber, compValue);
1466                 compValue.append(RIGHT_CURLY_BRACE);
1467                 if (0 != strValue.compare(compValue)) {
1468                     argResult.setString(strValue);
1469                     haveArgResult = true;
1470                 }
1471                 sourceOffset = next;
1472             }
1473         } else if(argType==UMSGPAT_ARG_TYPE_CHOICE) {
1474             tempStatus.setIndex(sourceOffset);
1475             double choiceResult = ChoiceFormat::parseArgument(msgPattern, i, source, tempStatus);
1476             if (tempStatus.getIndex() == sourceOffset) {
1477                 pos.setErrorIndex(sourceOffset);
1478                 return NULL; // leave index as is to signal error
1479             }
1480             argResult.setDouble(choiceResult);
1481             haveArgResult = true;
1482             sourceOffset = tempStatus.getIndex();
1483         } else if(UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType) || argType==UMSGPAT_ARG_TYPE_SELECT) {
1484             // Parsing not supported.
1485             ec = U_UNSUPPORTED_ERROR;
1486             return NULL;
1487         } else {
1488             // This should never happen.
1489             ec = U_INTERNAL_PROGRAM_ERROR;
1490             return NULL;
1491         }
1492         if (haveArgResult && count <= argNumber) {
1493             count = argNumber + 1;
1494         }
1495         prevIndex=msgPattern.getPart(argLimit).getLimit();
1496         i=argLimit;
1497     }
1498 }
1499 // -------------------------------------
1500 // Parses the source pattern and returns the Formattable objects array,
1501 // the array count and the ending parse position.  The caller of this method
1502 // owns the array.
1503 
1504 Formattable*
parse(const UnicodeString & source,ParsePosition & pos,int32_t & count) const1505 MessageFormat::parse(const UnicodeString& source,
1506                      ParsePosition& pos,
1507                      int32_t& count) const {
1508     UErrorCode ec = U_ZERO_ERROR;
1509     return parse(0, source, pos, count, ec);
1510 }
1511 
1512 // -------------------------------------
1513 // Parses the source string and returns the array of
1514 // Formattable objects and the array count.  The caller
1515 // owns the returned array.
1516 
1517 Formattable*
parse(const UnicodeString & source,int32_t & cnt,UErrorCode & success) const1518 MessageFormat::parse(const UnicodeString& source,
1519                      int32_t& cnt,
1520                      UErrorCode& success) const
1521 {
1522     if (msgPattern.hasNamedArguments()) {
1523         success = U_ARGUMENT_TYPE_MISMATCH;
1524         return NULL;
1525     }
1526     ParsePosition status(0);
1527     // Calls the actual implementation method and starts
1528     // from zero offset of the source text.
1529     Formattable* result = parse(source, status, cnt);
1530     if (status.getIndex() == 0) {
1531         success = U_MESSAGE_PARSE_ERROR;
1532         delete[] result;
1533         return NULL;
1534     }
1535     return result;
1536 }
1537 
1538 // -------------------------------------
1539 // Parses the source text and copy into the result buffer.
1540 
1541 void
parseObject(const UnicodeString & source,Formattable & result,ParsePosition & status) const1542 MessageFormat::parseObject( const UnicodeString& source,
1543                             Formattable& result,
1544                             ParsePosition& status) const
1545 {
1546     int32_t cnt = 0;
1547     Formattable* tmpResult = parse(source, status, cnt);
1548     if (tmpResult != NULL)
1549         result.adoptArray(tmpResult, cnt);
1550 }
1551 
1552 UnicodeString
autoQuoteApostrophe(const UnicodeString & pattern,UErrorCode & status)1553 MessageFormat::autoQuoteApostrophe(const UnicodeString& pattern, UErrorCode& status) {
1554     UnicodeString result;
1555     if (U_SUCCESS(status)) {
1556         int32_t plen = pattern.length();
1557         const UChar* pat = pattern.getBuffer();
1558         int32_t blen = plen * 2 + 1; // space for null termination, convenience
1559         UChar* buf = result.getBuffer(blen);
1560         if (buf == NULL) {
1561             status = U_MEMORY_ALLOCATION_ERROR;
1562         } else {
1563             int32_t len = umsg_autoQuoteApostrophe(pat, plen, buf, blen, &status);
1564             result.releaseBuffer(U_SUCCESS(status) ? len : 0);
1565         }
1566     }
1567     if (U_FAILURE(status)) {
1568         result.setToBogus();
1569     }
1570     return result;
1571 }
1572 
1573 // -------------------------------------
1574 
makeRBNF(URBNFRuleSetTag tag,const Locale & locale,const UnicodeString & defaultRuleSet,UErrorCode & ec)1575 static Format* makeRBNF(URBNFRuleSetTag tag, const Locale& locale, const UnicodeString& defaultRuleSet, UErrorCode& ec) {
1576     RuleBasedNumberFormat* fmt = new RuleBasedNumberFormat(tag, locale, ec);
1577     if (fmt == NULL) {
1578         ec = U_MEMORY_ALLOCATION_ERROR;
1579     } else if (U_SUCCESS(ec) && defaultRuleSet.length() > 0) {
1580         UErrorCode localStatus = U_ZERO_ERROR; // ignore unrecognized default rule set
1581         fmt->setDefaultRuleSet(defaultRuleSet, localStatus);
1582     }
1583     return fmt;
1584 }
1585 
cacheExplicitFormats(UErrorCode & status)1586 void MessageFormat::cacheExplicitFormats(UErrorCode& status) {
1587     if (U_FAILURE(status)) {
1588         return;
1589     }
1590 
1591     if (cachedFormatters != NULL) {
1592         uhash_removeAll(cachedFormatters);
1593     }
1594     if (customFormatArgStarts != NULL) {
1595         uhash_removeAll(customFormatArgStarts);
1596     }
1597 
1598     // The last two "parts" can at most be ARG_LIMIT and MSG_LIMIT
1599     // which we need not examine.
1600     int32_t limit = msgPattern.countParts() - 2;
1601     argTypeCount = 0;
1602     // We also need not look at the first two "parts"
1603     // (at most MSG_START and ARG_START) in this loop.
1604     // We determine the argTypeCount first so that we can allocateArgTypes
1605     // so that the next loop can set argTypes[argNumber].
1606     // (This is for the C API which needs the argTypes to read its va_arg list.)
1607     for (int32_t i = 2; i < limit && U_SUCCESS(status); ++i) {
1608         const MessagePattern::Part& part = msgPattern.getPart(i);
1609         if (part.getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) {
1610             const int argNumber = part.getValue();
1611             if (argNumber >= argTypeCount) {
1612                 argTypeCount = argNumber + 1;
1613             }
1614         }
1615     }
1616     if (!allocateArgTypes(argTypeCount, status)) {
1617         return;
1618     }
1619     // Set all argTypes to kObject, as a "none" value, for lack of any better value.
1620     // We never use kObject for real arguments.
1621     // We use it as "no argument yet" for the check for hasArgTypeConflicts.
1622     for (int32_t i = 0; i < argTypeCount; ++i) {
1623         argTypes[i] = Formattable::kObject;
1624     }
1625     hasArgTypeConflicts = false;
1626 
1627     // This loop starts at part index 1 because we do need to examine
1628     // ARG_START parts. (But we can ignore the MSG_START.)
1629     for (int32_t i = 1; i < limit && U_SUCCESS(status); ++i) {
1630         const MessagePattern::Part* part = &msgPattern.getPart(i);
1631         if (part->getType() != UMSGPAT_PART_TYPE_ARG_START) {
1632             continue;
1633         }
1634         UMessagePatternArgType argType = part->getArgType();
1635 
1636         int32_t argNumber = -1;
1637         part = &msgPattern.getPart(i + 1);
1638         if (part->getType() == UMSGPAT_PART_TYPE_ARG_NUMBER) {
1639             argNumber = part->getValue();
1640         }
1641         Formattable::Type formattableType;
1642 
1643         switch (argType) {
1644         case UMSGPAT_ARG_TYPE_NONE:
1645             formattableType = Formattable::kString;
1646             break;
1647         case UMSGPAT_ARG_TYPE_SIMPLE: {
1648             int32_t index = i;
1649             i += 2;
1650             UnicodeString explicitType = msgPattern.getSubstring(msgPattern.getPart(i++));
1651             UnicodeString style;
1652             if ((part = &msgPattern.getPart(i))->getType() == UMSGPAT_PART_TYPE_ARG_STYLE) {
1653                 style = msgPattern.getSubstring(*part);
1654                 ++i;
1655             }
1656             UParseError parseError;
1657             Format* formatter = createAppropriateFormat(explicitType, style, formattableType, parseError, status);
1658             setArgStartFormat(index, formatter, status);
1659             break;
1660         }
1661         case UMSGPAT_ARG_TYPE_CHOICE:
1662         case UMSGPAT_ARG_TYPE_PLURAL:
1663         case UMSGPAT_ARG_TYPE_SELECTORDINAL:
1664             formattableType = Formattable::kDouble;
1665             break;
1666         case UMSGPAT_ARG_TYPE_SELECT:
1667             formattableType = Formattable::kString;
1668             break;
1669         default:
1670             status = U_INTERNAL_PROGRAM_ERROR;  // Should be unreachable.
1671             formattableType = Formattable::kString;
1672             break;
1673         }
1674         if (argNumber != -1) {
1675             if (argTypes[argNumber] != Formattable::kObject && argTypes[argNumber] != formattableType) {
1676                 hasArgTypeConflicts = true;
1677             }
1678             argTypes[argNumber] = formattableType;
1679         }
1680     }
1681 }
1682 
createAppropriateFormat(UnicodeString & type,UnicodeString & style,Formattable::Type & formattableType,UParseError & parseError,UErrorCode & ec)1683 Format* MessageFormat::createAppropriateFormat(UnicodeString& type, UnicodeString& style,
1684                                                Formattable::Type& formattableType, UParseError& parseError,
1685                                                UErrorCode& ec) {
1686     if (U_FAILURE(ec)) {
1687         return NULL;
1688     }
1689     Format* fmt = NULL;
1690     int32_t typeID, styleID;
1691     DateFormat::EStyle date_style;
1692     int32_t firstNonSpace;
1693 
1694     switch (typeID = findKeyword(type, TYPE_IDS)) {
1695     case 0: // number
1696         formattableType = Formattable::kDouble;
1697         switch (findKeyword(style, NUMBER_STYLE_IDS)) {
1698         case 0: // default
1699             fmt = NumberFormat::createInstance(fLocale, ec);
1700             break;
1701         case 1: // currency
1702             fmt = NumberFormat::createCurrencyInstance(fLocale, ec);
1703             break;
1704         case 2: // percent
1705             fmt = NumberFormat::createPercentInstance(fLocale, ec);
1706             break;
1707         case 3: // integer
1708             formattableType = Formattable::kLong;
1709             fmt = createIntegerFormat(fLocale, ec);
1710             break;
1711         default: // pattern or skeleton
1712             firstNonSpace = PatternProps::skipWhiteSpace(style, 0);
1713             if (style.compare(firstNonSpace, 2, u"::", 0, 2) == 0) {
1714                 // Skeleton
1715                 UnicodeString skeleton = style.tempSubString(firstNonSpace + 2);
1716                 fmt = number::NumberFormatter::forSkeleton(skeleton, ec).locale(fLocale).toFormat(ec);
1717             } else {
1718                 // Pattern
1719                 fmt = NumberFormat::createInstance(fLocale, ec);
1720                 if (fmt) {
1721                     auto* decfmt = dynamic_cast<DecimalFormat*>(fmt);
1722                     if (decfmt != nullptr) {
1723                         decfmt->applyPattern(style, parseError, ec);
1724                     }
1725                 }
1726             }
1727             break;
1728         }
1729         break;
1730 
1731     case 1: // date
1732     case 2: // time
1733         formattableType = Formattable::kDate;
1734         firstNonSpace = PatternProps::skipWhiteSpace(style, 0);
1735         if (style.compare(firstNonSpace, 2, u"::", 0, 2) == 0) {
1736             // Skeleton
1737             UnicodeString skeleton = style.tempSubString(firstNonSpace + 2);
1738             fmt = DateFormat::createInstanceForSkeleton(skeleton, fLocale, ec);
1739         } else {
1740             // Pattern
1741             styleID = findKeyword(style, DATE_STYLE_IDS);
1742             date_style = (styleID >= 0) ? DATE_STYLES[styleID] : DateFormat::kDefault;
1743 
1744             if (typeID == 1) {
1745                 fmt = DateFormat::createDateInstance(date_style, fLocale);
1746             } else {
1747                 fmt = DateFormat::createTimeInstance(date_style, fLocale);
1748             }
1749 
1750             if (styleID < 0 && fmt != NULL) {
1751                 SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(fmt);
1752                 if (sdtfmt != NULL) {
1753                     sdtfmt->applyPattern(style);
1754                 }
1755             }
1756         }
1757         break;
1758 
1759     case 3: // spellout
1760         formattableType = Formattable::kDouble;
1761         fmt = makeRBNF(URBNF_SPELLOUT, fLocale, style, ec);
1762         break;
1763     case 4: // ordinal
1764         formattableType = Formattable::kDouble;
1765         fmt = makeRBNF(URBNF_ORDINAL, fLocale, style, ec);
1766         break;
1767     case 5: // duration
1768         formattableType = Formattable::kDouble;
1769         fmt = makeRBNF(URBNF_DURATION, fLocale, style, ec);
1770         break;
1771     default:
1772         formattableType = Formattable::kString;
1773         ec = U_ILLEGAL_ARGUMENT_ERROR;
1774         break;
1775     }
1776 
1777     return fmt;
1778 }
1779 
1780 
1781 //-------------------------------------
1782 // Finds the string, s, in the string array, list.
findKeyword(const UnicodeString & s,const UChar * const * list)1783 int32_t MessageFormat::findKeyword(const UnicodeString& s,
1784                                    const UChar * const *list)
1785 {
1786     if (s.isEmpty()) {
1787         return 0; // default
1788     }
1789 
1790     int32_t length = s.length();
1791     const UChar *ps = PatternProps::trimWhiteSpace(s.getBuffer(), length);
1792     UnicodeString buffer(false, ps, length);
1793     // Trims the space characters and turns all characters
1794     // in s to lower case.
1795     buffer.toLower("");
1796     for (int32_t i = 0; list[i]; ++i) {
1797         if (!buffer.compare(list[i], u_strlen(list[i]))) {
1798             return i;
1799         }
1800     }
1801     return -1;
1802 }
1803 
1804 /**
1805  * Convenience method that ought to be in NumberFormat
1806  */
1807 NumberFormat*
createIntegerFormat(const Locale & locale,UErrorCode & status) const1808 MessageFormat::createIntegerFormat(const Locale& locale, UErrorCode& status) const {
1809     NumberFormat *temp = NumberFormat::createInstance(locale, status);
1810     DecimalFormat *temp2;
1811     if (temp != NULL && (temp2 = dynamic_cast<DecimalFormat*>(temp)) != NULL) {
1812         temp2->setMaximumFractionDigits(0);
1813         temp2->setDecimalSeparatorAlwaysShown(false);
1814         temp2->setParseIntegerOnly(true);
1815     }
1816 
1817     return temp;
1818 }
1819 
1820 /**
1821  * Return the default number format.  Used to format a numeric
1822  * argument when subformats[i].format is NULL.  Returns NULL
1823  * on failure.
1824  *
1825  * Semantically const but may modify *this.
1826  */
getDefaultNumberFormat(UErrorCode & ec) const1827 const NumberFormat* MessageFormat::getDefaultNumberFormat(UErrorCode& ec) const {
1828     if (defaultNumberFormat == NULL) {
1829         MessageFormat* t = (MessageFormat*) this;
1830         t->defaultNumberFormat = NumberFormat::createInstance(fLocale, ec);
1831         if (U_FAILURE(ec)) {
1832             delete t->defaultNumberFormat;
1833             t->defaultNumberFormat = NULL;
1834         } else if (t->defaultNumberFormat == NULL) {
1835             ec = U_MEMORY_ALLOCATION_ERROR;
1836         }
1837     }
1838     return defaultNumberFormat;
1839 }
1840 
1841 /**
1842  * Return the default date format.  Used to format a date
1843  * argument when subformats[i].format is NULL.  Returns NULL
1844  * on failure.
1845  *
1846  * Semantically const but may modify *this.
1847  */
getDefaultDateFormat(UErrorCode & ec) const1848 const DateFormat* MessageFormat::getDefaultDateFormat(UErrorCode& ec) const {
1849     if (defaultDateFormat == NULL) {
1850         MessageFormat* t = (MessageFormat*) this;
1851         t->defaultDateFormat = DateFormat::createDateTimeInstance(DateFormat::kShort, DateFormat::kShort, fLocale);
1852         if (t->defaultDateFormat == NULL) {
1853             ec = U_MEMORY_ALLOCATION_ERROR;
1854         }
1855     }
1856     return defaultDateFormat;
1857 }
1858 
1859 UBool
usesNamedArguments() const1860 MessageFormat::usesNamedArguments() const {
1861     return msgPattern.hasNamedArguments();
1862 }
1863 
1864 int32_t
getArgTypeCount() const1865 MessageFormat::getArgTypeCount() const {
1866     return argTypeCount;
1867 }
1868 
equalFormats(const void * left,const void * right)1869 UBool MessageFormat::equalFormats(const void* left, const void* right) {
1870     return *(const Format*)left==*(const Format*)right;
1871 }
1872 
1873 
operator ==(const Format &) const1874 bool MessageFormat::DummyFormat::operator==(const Format&) const {
1875     return true;
1876 }
1877 
clone() const1878 MessageFormat::DummyFormat* MessageFormat::DummyFormat::clone() const {
1879     return new DummyFormat();
1880 }
1881 
format(const Formattable &,UnicodeString & appendTo,UErrorCode & status) const1882 UnicodeString& MessageFormat::DummyFormat::format(const Formattable&,
1883                           UnicodeString& appendTo,
1884                           UErrorCode& status) const {
1885     if (U_SUCCESS(status)) {
1886         status = U_UNSUPPORTED_ERROR;
1887     }
1888     return appendTo;
1889 }
1890 
format(const Formattable &,UnicodeString & appendTo,FieldPosition &,UErrorCode & status) const1891 UnicodeString& MessageFormat::DummyFormat::format(const Formattable&,
1892                           UnicodeString& appendTo,
1893                           FieldPosition&,
1894                           UErrorCode& status) const {
1895     if (U_SUCCESS(status)) {
1896         status = U_UNSUPPORTED_ERROR;
1897     }
1898     return appendTo;
1899 }
1900 
format(const Formattable &,UnicodeString & appendTo,FieldPositionIterator *,UErrorCode & status) const1901 UnicodeString& MessageFormat::DummyFormat::format(const Formattable&,
1902                           UnicodeString& appendTo,
1903                           FieldPositionIterator*,
1904                           UErrorCode& status) const {
1905     if (U_SUCCESS(status)) {
1906         status = U_UNSUPPORTED_ERROR;
1907     }
1908     return appendTo;
1909 }
1910 
parseObject(const UnicodeString &,Formattable &,ParsePosition &) const1911 void MessageFormat::DummyFormat::parseObject(const UnicodeString&,
1912                                                      Formattable&,
1913                                                      ParsePosition& ) const {
1914 }
1915 
1916 
FormatNameEnumeration(LocalPointer<UVector> nameList,UErrorCode &)1917 FormatNameEnumeration::FormatNameEnumeration(LocalPointer<UVector> nameList, UErrorCode& /*status*/) {
1918     pos=0;
1919     fFormatNames = std::move(nameList);
1920 }
1921 
1922 const UnicodeString*
snext(UErrorCode & status)1923 FormatNameEnumeration::snext(UErrorCode& status) {
1924     if (U_SUCCESS(status) && pos < fFormatNames->size()) {
1925         return (const UnicodeString*)fFormatNames->elementAt(pos++);
1926     }
1927     return NULL;
1928 }
1929 
1930 void
reset(UErrorCode &)1931 FormatNameEnumeration::reset(UErrorCode& /*status*/) {
1932     pos=0;
1933 }
1934 
1935 int32_t
count(UErrorCode &) const1936 FormatNameEnumeration::count(UErrorCode& /*status*/) const {
1937     return (fFormatNames==NULL) ? 0 : fFormatNames->size();
1938 }
1939 
~FormatNameEnumeration()1940 FormatNameEnumeration::~FormatNameEnumeration() {
1941 }
1942 
PluralSelectorProvider(const MessageFormat & mf,UPluralType t)1943 MessageFormat::PluralSelectorProvider::PluralSelectorProvider(const MessageFormat &mf, UPluralType t)
1944         : msgFormat(mf), rules(NULL), type(t) {
1945 }
1946 
~PluralSelectorProvider()1947 MessageFormat::PluralSelectorProvider::~PluralSelectorProvider() {
1948     delete rules;
1949 }
1950 
select(void * ctx,double number,UErrorCode & ec) const1951 UnicodeString MessageFormat::PluralSelectorProvider::select(void *ctx, double number,
1952                                                             UErrorCode& ec) const {
1953     if (U_FAILURE(ec)) {
1954         return UnicodeString(false, OTHER_STRING, 5);
1955     }
1956     MessageFormat::PluralSelectorProvider* t = const_cast<MessageFormat::PluralSelectorProvider*>(this);
1957     if(rules == NULL) {
1958         t->rules = PluralRules::forLocale(msgFormat.fLocale, type, ec);
1959         if (U_FAILURE(ec)) {
1960             return UnicodeString(false, OTHER_STRING, 5);
1961         }
1962     }
1963     // Select a sub-message according to how the number is formatted,
1964     // which is specified in the selected sub-message.
1965     // We avoid this circle by looking at how
1966     // the number is formatted in the "other" sub-message
1967     // which must always be present and usually contains the number.
1968     // Message authors should be consistent across sub-messages.
1969     PluralSelectorContext &context = *static_cast<PluralSelectorContext *>(ctx);
1970     int32_t otherIndex = msgFormat.findOtherSubMessage(context.startIndex);
1971     context.numberArgIndex = msgFormat.findFirstPluralNumberArg(otherIndex, context.argName);
1972     if(context.numberArgIndex > 0 && msgFormat.cachedFormatters != NULL) {
1973         context.formatter =
1974             (const Format*)uhash_iget(msgFormat.cachedFormatters, context.numberArgIndex);
1975     }
1976     if(context.formatter == NULL) {
1977         context.formatter = msgFormat.getDefaultNumberFormat(ec);
1978         context.forReplaceNumber = true;
1979     }
1980     if (context.number.getDouble(ec) != number) {
1981         ec = U_INTERNAL_PROGRAM_ERROR;
1982         return UnicodeString(false, OTHER_STRING, 5);
1983     }
1984     context.formatter->format(context.number, context.numberString, ec);
1985     auto* decFmt = dynamic_cast<const DecimalFormat *>(context.formatter);
1986     if(decFmt != NULL) {
1987         number::impl::DecimalQuantity dq;
1988         decFmt->formatToDecimalQuantity(context.number, dq, ec);
1989         if (U_FAILURE(ec)) {
1990             return UnicodeString(false, OTHER_STRING, 5);
1991         }
1992         return rules->select(dq);
1993     } else {
1994         return rules->select(number);
1995     }
1996 }
1997 
reset()1998 void MessageFormat::PluralSelectorProvider::reset() {
1999     delete rules;
2000     rules = NULL;
2001 }
2002 
2003 
2004 U_NAMESPACE_END
2005 
2006 #endif /* #if !UCONFIG_NO_FORMATTING */
2007 
2008 //eof
2009