Coverage Report

Created: 2026-08-14 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/icu/icu4c/source/common/messagepattern.cpp
Line
Count
Source
1
// © 2016 and later: Unicode, Inc. and others.
2
// License & terms of use: http://www.unicode.org/copyright.html
3
/*
4
*******************************************************************************
5
*   Copyright (C) 2011-2012, International Business Machines
6
*   Corporation and others.  All Rights Reserved.
7
*******************************************************************************
8
*   file name:  messagepattern.cpp
9
*   encoding:   UTF-8
10
*   tab size:   8 (not used)
11
*   indentation:4
12
*
13
*   created on: 2011mar14
14
*   created by: Markus W. Scherer
15
*/
16
17
#include "unicode/utypes.h"
18
19
#if !UCONFIG_NO_FORMATTING
20
21
#include "unicode/messagepattern.h"
22
#include "unicode/unistr.h"
23
#include "unicode/utf16.h"
24
#include "cmemory.h"
25
#include "cstring.h"
26
#include "messageimpl.h"
27
#include "patternprops.h"
28
#include "putilimp.h"
29
#include "uassert.h"
30
31
U_NAMESPACE_BEGIN
32
33
// Unicode character/code point constants ---------------------------------- ***
34
35
static const char16_t u_pound=0x23;
36
static const char16_t u_apos=0x27;
37
static const char16_t u_plus=0x2B;
38
static const char16_t u_comma=0x2C;
39
static const char16_t u_minus=0x2D;
40
static const char16_t u_dot=0x2E;
41
static const char16_t u_colon=0x3A;
42
static const char16_t u_lessThan=0x3C;
43
static const char16_t u_equal=0x3D;
44
static const char16_t u_A=0x41;
45
static const char16_t u_C=0x43;
46
static const char16_t u_D=0x44;
47
static const char16_t u_E=0x45;
48
static const char16_t u_H=0x48;
49
static const char16_t u_I=0x49;
50
static const char16_t u_L=0x4C;
51
static const char16_t u_N=0x4E;
52
static const char16_t u_O=0x4F;
53
static const char16_t u_P=0x50;
54
static const char16_t u_R=0x52;
55
static const char16_t u_S=0x53;
56
static const char16_t u_T=0x54;
57
static const char16_t u_U=0x55;
58
static const char16_t u_Z=0x5A;
59
static const char16_t u_a=0x61;
60
static const char16_t u_c=0x63;
61
static const char16_t u_d=0x64;
62
static const char16_t u_e=0x65;
63
static const char16_t u_f=0x66;
64
static const char16_t u_h=0x68;
65
static const char16_t u_i=0x69;
66
static const char16_t u_l=0x6C;
67
static const char16_t u_n=0x6E;
68
static const char16_t u_o=0x6F;
69
static const char16_t u_p=0x70;
70
static const char16_t u_r=0x72;
71
static const char16_t u_s=0x73;
72
static const char16_t u_t=0x74;
73
static const char16_t u_u=0x75;
74
static const char16_t u_z=0x7A;
75
static const char16_t u_leftCurlyBrace=0x7B;
76
static const char16_t u_pipe=0x7C;
77
static const char16_t u_rightCurlyBrace=0x7D;
78
static const char16_t u_lessOrEqual=0x2264;  // U+2264 is <=
79
80
static const char16_t kOffsetColon[]={  // "offset:"
81
    u_o, u_f, u_f, u_s, u_e, u_t, u_colon
82
};
83
84
static const char16_t kOther[]={  // "other"
85
    u_o, u_t, u_h, u_e, u_r
86
};
87
88
// MessagePatternList ------------------------------------------------------ ***
89
90
template<typename T, int32_t stackCapacity>
91
class MessagePatternList : public UMemory {
92
public:
93
39.1k
    MessagePatternList() {}
icu_79::MessagePatternList<icu_79::MessagePattern::Part, 32>::MessagePatternList()
Line
Count
Source
93
38.7k
    MessagePatternList() {}
icu_79::MessagePatternList<double, 8>::MessagePatternList()
Line
Count
Source
93
366
    MessagePatternList() {}
94
    void copyFrom(const MessagePatternList<T, stackCapacity> &other,
95
                  int32_t length,
96
                  UErrorCode &errorCode);
97
    UBool ensureCapacityForOneMore(int32_t oldLength, UErrorCode &errorCode);
98
0
    UBool equals(const MessagePatternList<T, stackCapacity> &other, int32_t length) const {
99
0
        for(int32_t i=0; i<length; ++i) {
100
0
            if(a[i]!=other.a[i]) { return false; }
101
0
        }
102
0
        return true;
103
0
    }
104
105
    MaybeStackArray<T, stackCapacity> a;
106
};
107
108
template<typename T, int32_t stackCapacity>
109
void
110
MessagePatternList<T, stackCapacity>::copyFrom(
111
        const MessagePatternList<T, stackCapacity> &other,
112
        int32_t length,
113
0
        UErrorCode &errorCode) {
114
0
    if(U_SUCCESS(errorCode) && length>0) {
115
0
        if(length>a.getCapacity() && nullptr==a.resize(length)) {
116
0
            errorCode=U_MEMORY_ALLOCATION_ERROR;
117
0
            return;
118
0
        }
119
0
        uprv_memcpy(a.getAlias(), other.a.getAlias(), (size_t)length*sizeof(T));
120
0
    }
121
0
}
Unexecuted instantiation: icu_79::MessagePatternList<icu_79::MessagePattern::Part, 32>::copyFrom(icu_79::MessagePatternList<icu_79::MessagePattern::Part, 32> const&, int, UErrorCode&)
Unexecuted instantiation: icu_79::MessagePatternList<double, 8>::copyFrom(icu_79::MessagePatternList<double, 8> const&, int, UErrorCode&)
122
123
template<typename T, int32_t stackCapacity>
124
UBool
125
7.62M
MessagePatternList<T, stackCapacity>::ensureCapacityForOneMore(int32_t oldLength, UErrorCode &errorCode) {
126
7.62M
    if(U_FAILURE(errorCode)) {
127
68.7k
        return false;
128
68.7k
    }
129
7.56M
    if(a.getCapacity()>oldLength || a.resize(2*oldLength, oldLength)!=nullptr) {
130
7.56M
        return true;
131
7.56M
    }
132
0
    errorCode=U_MEMORY_ALLOCATION_ERROR;
133
0
    return false;
134
7.56M
}
icu_79::MessagePatternList<icu_79::MessagePattern::Part, 32>::ensureCapacityForOneMore(int, UErrorCode&)
Line
Count
Source
125
6.92M
MessagePatternList<T, stackCapacity>::ensureCapacityForOneMore(int32_t oldLength, UErrorCode &errorCode) {
126
6.92M
    if(U_FAILURE(errorCode)) {
127
68.7k
        return false;
128
68.7k
    }
129
6.86M
    if(a.getCapacity()>oldLength || a.resize(2*oldLength, oldLength)!=nullptr) {
130
6.86M
        return true;
131
6.86M
    }
132
0
    errorCode=U_MEMORY_ALLOCATION_ERROR;
133
0
    return false;
134
6.86M
}
icu_79::MessagePatternList<double, 8>::ensureCapacityForOneMore(int, UErrorCode&)
Line
Count
Source
125
700k
MessagePatternList<T, stackCapacity>::ensureCapacityForOneMore(int32_t oldLength, UErrorCode &errorCode) {
126
700k
    if(U_FAILURE(errorCode)) {
127
0
        return false;
128
0
    }
129
700k
    if(a.getCapacity()>oldLength || a.resize(2*oldLength, oldLength)!=nullptr) {
130
700k
        return true;
131
700k
    }
132
0
    errorCode=U_MEMORY_ALLOCATION_ERROR;
133
0
    return false;
134
700k
}
135
136
// MessagePatternList specializations -------------------------------------- ***
137
138
class MessagePatternDoubleList : public MessagePatternList<double, 8> {
139
};
140
141
class MessagePatternPartsList : public MessagePatternList<MessagePattern::Part, 32> {
142
};
143
144
// MessagePattern constructors etc. ---------------------------------------- ***
145
146
MessagePattern::MessagePattern(UErrorCode &errorCode)
147
30.4k
        : aposMode(UCONFIG_MSGPAT_DEFAULT_APOSTROPHE_MODE),
148
30.4k
          partsList(nullptr), parts(nullptr), partsLength(0),
149
30.4k
          numericValuesList(nullptr), numericValues(nullptr), numericValuesLength(0),
150
30.4k
          hasArgNames(false), hasArgNumbers(false), needsAutoQuoting(false) {
151
30.4k
    init(errorCode);
152
30.4k
}
153
154
MessagePattern::MessagePattern(UMessagePatternApostropheMode mode, UErrorCode &errorCode)
155
0
        : aposMode(mode),
156
0
          partsList(nullptr), parts(nullptr), partsLength(0),
157
0
          numericValuesList(nullptr), numericValues(nullptr), numericValuesLength(0),
158
0
          hasArgNames(false), hasArgNumbers(false), needsAutoQuoting(false) {
159
0
    init(errorCode);
160
0
}
161
162
MessagePattern::MessagePattern(const UnicodeString &pattern, UParseError *parseError, UErrorCode &errorCode)
163
8.36k
        : aposMode(UCONFIG_MSGPAT_DEFAULT_APOSTROPHE_MODE),
164
8.36k
          partsList(nullptr), parts(nullptr), partsLength(0),
165
8.36k
          numericValuesList(nullptr), numericValues(nullptr), numericValuesLength(0),
166
8.36k
          hasArgNames(false), hasArgNumbers(false), needsAutoQuoting(false) {
167
8.36k
    if(init(errorCode)) {
168
8.36k
        parse(pattern, parseError, errorCode);
169
8.36k
    }
170
8.36k
}
171
172
UBool
173
38.7k
MessagePattern::init(UErrorCode &errorCode) {
174
38.7k
    if(U_FAILURE(errorCode)) {
175
0
        return false;
176
0
    }
177
38.7k
    partsList=new MessagePatternPartsList();
178
38.7k
    if(partsList==nullptr) {
179
0
        errorCode=U_MEMORY_ALLOCATION_ERROR;
180
0
        return false;
181
0
    }
182
38.7k
    parts=partsList->a.getAlias();
183
38.7k
    return true;
184
38.7k
}
185
186
MessagePattern::MessagePattern(const MessagePattern &other)
187
0
        : UObject(other), aposMode(other.aposMode), msg(other.msg),
188
0
          partsList(nullptr), parts(nullptr), partsLength(0),
189
0
          numericValuesList(nullptr), numericValues(nullptr), numericValuesLength(0),
190
0
          hasArgNames(other.hasArgNames), hasArgNumbers(other.hasArgNumbers),
191
0
          needsAutoQuoting(other.needsAutoQuoting) {
192
0
    UErrorCode errorCode=U_ZERO_ERROR;
193
0
    if(!copyStorage(other, errorCode)) {
194
0
        clear();
195
0
    }
196
0
}
197
198
MessagePattern &
199
0
MessagePattern::operator=(const MessagePattern &other) {
200
0
    if(this==&other) {
201
0
        return *this;
202
0
    }
203
0
    aposMode=other.aposMode;
204
0
    msg=other.msg;
205
0
    hasArgNames=other.hasArgNames;
206
0
    hasArgNumbers=other.hasArgNumbers;
207
0
    needsAutoQuoting=other.needsAutoQuoting;
208
0
    UErrorCode errorCode=U_ZERO_ERROR;
209
0
    if(!copyStorage(other, errorCode)) {
210
0
        clear();
211
0
    }
212
0
    return *this;
213
0
}
214
215
UBool
216
0
MessagePattern::copyStorage(const MessagePattern &other, UErrorCode &errorCode) {
217
0
    if(U_FAILURE(errorCode)) {
218
0
        return false;
219
0
    }
220
0
    parts=nullptr;
221
0
    partsLength=0;
222
0
    numericValues=nullptr;
223
0
    numericValuesLength=0;
224
0
    if(partsList==nullptr) {
225
0
        partsList=new MessagePatternPartsList();
226
0
        if(partsList==nullptr) {
227
0
            errorCode=U_MEMORY_ALLOCATION_ERROR;
228
0
            return false;
229
0
        }
230
0
        parts=partsList->a.getAlias();
231
0
    }
232
0
    if(other.partsLength>0) {
233
0
        partsList->copyFrom(*other.partsList, other.partsLength, errorCode);
234
0
        if(U_FAILURE(errorCode)) {
235
0
            return false;
236
0
        }
237
0
        parts=partsList->a.getAlias();
238
0
        partsLength=other.partsLength;
239
0
    }
240
0
    if(other.numericValuesLength>0) {
241
0
        if(numericValuesList==nullptr) {
242
0
            numericValuesList=new MessagePatternDoubleList();
243
0
            if(numericValuesList==nullptr) {
244
0
                errorCode=U_MEMORY_ALLOCATION_ERROR;
245
0
                return false;
246
0
            }
247
0
            numericValues=numericValuesList->a.getAlias();
248
0
        }
249
0
        numericValuesList->copyFrom(
250
0
            *other.numericValuesList, other.numericValuesLength, errorCode);
251
0
        if(U_FAILURE(errorCode)) {
252
0
            return false;
253
0
        }
254
0
        numericValues=numericValuesList->a.getAlias();
255
0
        numericValuesLength=other.numericValuesLength;
256
0
    }
257
0
    return true;
258
0
}
259
260
38.7k
MessagePattern::~MessagePattern() {
261
38.7k
    delete partsList;
262
38.7k
    delete numericValuesList;
263
38.7k
}
264
265
// MessagePattern API ------------------------------------------------------ ***
266
267
MessagePattern &
268
16.7k
MessagePattern::parse(const UnicodeString &pattern, UParseError *parseError, UErrorCode &errorCode) {
269
16.7k
    preParse(pattern, parseError, errorCode);
270
16.7k
    parseMessage(0, 0, 0, UMSGPAT_ARG_TYPE_NONE, parseError, errorCode);
271
16.7k
    postParse();
272
16.7k
    return *this;
273
16.7k
}
274
275
MessagePattern &
276
MessagePattern::parseChoiceStyle(const UnicodeString &pattern,
277
0
                                 UParseError *parseError, UErrorCode &errorCode) {
278
0
    preParse(pattern, parseError, errorCode);
279
0
    parseChoiceStyle(0, 0, parseError, errorCode);
280
0
    postParse();
281
0
    return *this;
282
0
}
283
284
MessagePattern &
285
MessagePattern::parsePluralStyle(const UnicodeString &pattern,
286
22.0k
                                 UParseError *parseError, UErrorCode &errorCode) {
287
22.0k
    preParse(pattern, parseError, errorCode);
288
22.0k
    parsePluralOrSelectStyle(UMSGPAT_ARG_TYPE_PLURAL, 0, 0, parseError, errorCode);
289
22.0k
    postParse();
290
22.0k
    return *this;
291
22.0k
}
292
293
MessagePattern &
294
MessagePattern::parseSelectStyle(const UnicodeString &pattern,
295
0
                                 UParseError *parseError, UErrorCode &errorCode) {
296
0
    preParse(pattern, parseError, errorCode);
297
0
    parsePluralOrSelectStyle(UMSGPAT_ARG_TYPE_SELECT, 0, 0, parseError, errorCode);
298
0
    postParse();
299
0
    return *this;
300
0
}
301
302
void
303
4.60k
MessagePattern::clear() {
304
    // Mostly the same as preParse().
305
4.60k
    msg.remove();
306
4.60k
    hasArgNames=hasArgNumbers=false;
307
4.60k
    needsAutoQuoting=false;
308
4.60k
    partsLength=0;
309
4.60k
    numericValuesLength=0;
310
4.60k
}
311
312
bool
313
0
MessagePattern::operator==(const MessagePattern &other) const {
314
0
    if(this==&other) {
315
0
        return true;
316
0
    }
317
0
    return
318
0
        aposMode==other.aposMode &&
319
0
        msg==other.msg &&
320
        // parts.equals(o.parts)
321
0
        partsLength==other.partsLength &&
322
0
        (partsLength==0 || partsList->equals(*other.partsList, partsLength));
323
    // No need to compare numericValues if msg and parts are the same.
324
0
}
325
326
int32_t
327
0
MessagePattern::hashCode() const {
328
0
    int32_t hash=(aposMode*37+msg.hashCode())*37+partsLength;
329
0
    for(int32_t i=0; i<partsLength; ++i) {
330
0
        hash=hash*37+parts[i].hashCode();
331
0
    }
332
0
    return hash;
333
0
}
334
335
int32_t
336
0
MessagePattern::validateArgumentName(const UnicodeString &name) {
337
0
    if(!PatternProps::isIdentifier(name.getBuffer(), name.length())) {
338
0
        return UMSGPAT_ARG_NAME_NOT_VALID;
339
0
    }
340
0
    return parseArgNumber(name, 0, name.length());
341
0
}
342
343
UnicodeString
344
0
MessagePattern::autoQuoteApostropheDeep() const {
345
0
    if(!needsAutoQuoting) {
346
0
        return msg;
347
0
    }
348
0
    UnicodeString modified(msg);
349
    // Iterate backward so that the insertion indexes do not change.
350
0
    int32_t count=countParts();
351
0
    for(int32_t i=count; i>0;) {
352
0
        const Part &part=getPart(--i);
353
0
        if(part.getType()==UMSGPAT_PART_TYPE_INSERT_CHAR) {
354
0
           modified.insert(part.index, static_cast<char16_t>(part.value));
355
0
        }
356
0
    }
357
0
    return modified;
358
0
}
359
360
double
361
0
MessagePattern::getNumericValue(const Part &part) const {
362
0
    UMessagePatternPartType type=part.type;
363
0
    if(type==UMSGPAT_PART_TYPE_ARG_INT) {
364
0
        return part.value;
365
0
    } else if(type==UMSGPAT_PART_TYPE_ARG_DOUBLE) {
366
0
        return numericValues[part.value];
367
0
    } else {
368
0
        return UMSGPAT_NO_NUMERIC_VALUE;
369
0
    }
370
0
}
371
372
/**
373
  * Returns the "offset:" value of a PluralFormat argument, or 0 if none is specified.
374
  * @param pluralStart the index of the first PluralFormat argument style part. (0..countParts()-1)
375
  * @return the "offset:" value.
376
  * @draft ICU 4.8
377
  */
378
double
379
22.0k
MessagePattern::getPluralOffset(int32_t pluralStart) const {
380
22.0k
    const Part &part=getPart(pluralStart);
381
22.0k
    if(Part::hasNumericValue(part.type)) {
382
0
        return getNumericValue(part);
383
22.0k
    } else {
384
22.0k
        return 0;
385
22.0k
    }
386
22.0k
}
387
388
// MessagePattern::Part ---------------------------------------------------- ***
389
390
bool
391
0
MessagePattern::Part::operator==(const Part &other) const {
392
0
    if(this==&other) {
393
0
        return true;
394
0
    }
395
0
    return
396
0
        type==other.type &&
397
0
        index==other.index &&
398
0
        length==other.length &&
399
0
        value==other.value &&
400
0
        limitPartIndex==other.limitPartIndex;
401
0
}
402
403
// MessagePattern parser --------------------------------------------------- ***
404
405
void
406
38.7k
MessagePattern::preParse(const UnicodeString &pattern, UParseError *parseError, UErrorCode &errorCode) {
407
38.7k
    if(U_FAILURE(errorCode)) {
408
0
        return;
409
0
    }
410
38.7k
    if(parseError!=nullptr) {
411
16.7k
        parseError->line=0;
412
16.7k
        parseError->offset=0;
413
16.7k
        parseError->preContext[0]=0;
414
16.7k
        parseError->postContext[0]=0;
415
16.7k
    }
416
38.7k
    msg=pattern;
417
38.7k
    hasArgNames=hasArgNumbers=false;
418
38.7k
    needsAutoQuoting=false;
419
38.7k
    partsLength=0;
420
38.7k
    numericValuesLength=0;
421
38.7k
}
422
423
void
424
38.7k
MessagePattern::postParse() {
425
38.7k
    if(partsList!=nullptr) {
426
38.7k
        parts=partsList->a.getAlias();
427
38.7k
    }
428
38.7k
    if(numericValuesList!=nullptr) {
429
366
        numericValues=numericValuesList->a.getAlias();
430
366
    }
431
38.7k
}
432
433
int32_t
434
MessagePattern::parseMessage(int32_t index, int32_t msgStartLength,
435
                             int32_t nestingLevel, UMessagePatternArgType parentType,
436
925k
                             UParseError *parseError, UErrorCode &errorCode) {
437
925k
    if(U_FAILURE(errorCode)) {
438
0
        return 0;
439
0
    }
440
925k
    if(nestingLevel>Part::MAX_NESTED_LEVELS) {
441
2
        errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
442
2
        return 0;
443
2
    }
444
925k
    int32_t msgStart=partsLength;
445
925k
    addPart(UMSGPAT_PART_TYPE_MSG_START, index, msgStartLength, nestingLevel, errorCode);
446
925k
    index+=msgStartLength;
447
107M
    for(;;) {  // while(index<msg.length()) with U_FAILURE(errorCode) check
448
107M
        if(U_FAILURE(errorCode)) {
449
75.2k
            return 0;
450
75.2k
        }
451
107M
        if(index>=msg.length()) {
452
8.54k
            break;
453
8.54k
        }
454
107M
        char16_t c=msg.charAt(index++);
455
107M
        if(c==u_apos) {
456
648k
            if(index==msg.length()) {
457
                // The apostrophe is the last character in the pattern. 
458
                // Add a Part for auto-quoting.
459
26
                addPart(UMSGPAT_PART_TYPE_INSERT_CHAR, index, 0,
460
26
                        u_apos, errorCode);  // value=char to be inserted
461
26
                needsAutoQuoting=true;
462
648k
            } else {
463
648k
                c=msg.charAt(index);
464
648k
                if(c==u_apos) {
465
                    // double apostrophe, skip the second one
466
31.7k
                    addPart(UMSGPAT_PART_TYPE_SKIP_SYNTAX, index++, 1, 0, errorCode);
467
616k
                } else if(
468
616k
                    aposMode==UMSGPAT_APOS_DOUBLE_REQUIRED ||
469
616k
                    c==u_leftCurlyBrace || c==u_rightCurlyBrace ||
470
577k
                    (parentType==UMSGPAT_ARG_TYPE_CHOICE && c==u_pipe) ||
471
576k
                    (UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(parentType) && c==u_pound)
472
616k
                ) {
473
                    // skip the quote-starting apostrophe
474
44.5k
                    addPart(UMSGPAT_PART_TYPE_SKIP_SYNTAX, index-1, 1, 0, errorCode);
475
                    // find the end of the quoted literal text
476
49.2k
                    for(;;) {
477
49.2k
                        index=msg.indexOf(u_apos, index+1);
478
49.2k
                        if(index>=0) {
479
49.1k
                            if(/*(index+1)<msg.length() &&*/ msg.charAt(index+1)==u_apos) {
480
                                // double apostrophe inside quoted literal text
481
                                // still encodes a single apostrophe, skip the second one
482
4.77k
                                addPart(UMSGPAT_PART_TYPE_SKIP_SYNTAX, ++index, 1, 0, errorCode);
483
44.3k
                            } else {
484
                                // skip the quote-ending apostrophe
485
44.3k
                                addPart(UMSGPAT_PART_TYPE_SKIP_SYNTAX, index++, 1, 0, errorCode);
486
44.3k
                                break;
487
44.3k
                            }
488
49.1k
                        } else {
489
                            // The quoted text reaches to the end of the of the message.
490
184
                            index=msg.length();
491
                            // Add a Part for auto-quoting.
492
184
                            addPart(UMSGPAT_PART_TYPE_INSERT_CHAR, index, 0,
493
184
                                    u_apos, errorCode);  // value=char to be inserted
494
184
                            needsAutoQuoting=true;
495
184
                            break;
496
184
                        }
497
49.2k
                    }
498
571k
                } else {
499
                    // Interpret the apostrophe as literal text.
500
                    // Add a Part for auto-quoting.
501
571k
                    addPart(UMSGPAT_PART_TYPE_INSERT_CHAR, index, 0,
502
571k
                            u_apos, errorCode);  // value=char to be inserted
503
571k
                    needsAutoQuoting=true;
504
571k
                }
505
648k
            }
506
106M
        } else if(UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(parentType) && c==u_pound) {
507
            // The unquoted # in a plural message fragment will be replaced
508
            // with the (number-offset).
509
3.22k
            addPart(UMSGPAT_PART_TYPE_REPLACE_NUMBER, index-1, 1, 0, errorCode);
510
106M
        } else if(c==u_leftCurlyBrace) {
511
821k
            index=parseArg(index-1, 1, nestingLevel, parseError, errorCode);
512
106M
        } else if((nestingLevel>0 && c==u_rightCurlyBrace) ||
513
106M
                  (parentType==UMSGPAT_ARG_TYPE_CHOICE && c==u_pipe)) {
514
            // Finish the message before the terminator.
515
            // In a choice style, report the "}" substring only for the following ARG_LIMIT,
516
            // not for this MSG_LIMIT.
517
841k
            int32_t limitLength=(parentType==UMSGPAT_ARG_TYPE_CHOICE && c==u_rightCurlyBrace) ? 0 : 1;
518
841k
            addLimitPart(msgStart, UMSGPAT_PART_TYPE_MSG_LIMIT, index-1, limitLength,
519
841k
                         nestingLevel, errorCode);
520
841k
            if(parentType==UMSGPAT_ARG_TYPE_CHOICE) {
521
                // Let the choice style parser see the '}' or '|'.
522
751k
                return index-1;
523
751k
            } else {
524
                // continue parsing after the '}'
525
90.1k
                return index;
526
90.1k
            }
527
841k
        }  // else: c is part of literal text
528
107M
    }
529
8.54k
    if(nestingLevel>0 && !inTopLevelChoiceMessage(nestingLevel, parentType)) {
530
372
        setParseError(parseError, 0);  // Unmatched '{' braces in message.
531
372
        errorCode=U_UNMATCHED_BRACES;
532
372
        return 0;
533
372
    }
534
8.17k
    addLimitPart(msgStart, UMSGPAT_PART_TYPE_MSG_LIMIT, index, 0, nestingLevel, errorCode);
535
8.17k
    return index;
536
8.54k
}
537
538
int32_t
539
MessagePattern::parseArg(int32_t index, int32_t argStartLength, int32_t nestingLevel,
540
821k
                         UParseError *parseError, UErrorCode &errorCode) {
541
821k
    int32_t argStart=partsLength;
542
821k
    UMessagePatternArgType argType=UMSGPAT_ARG_TYPE_NONE;
543
821k
    addPart(UMSGPAT_PART_TYPE_ARG_START, index, argStartLength, argType, errorCode);
544
821k
    if(U_FAILURE(errorCode)) {
545
0
        return 0;
546
0
    }
547
821k
    int32_t nameIndex=index=skipWhiteSpace(index+argStartLength);
548
821k
    if(index==msg.length()) {
549
224
        setParseError(parseError, 0);  // Unmatched '{' braces in message.
550
224
        errorCode=U_UNMATCHED_BRACES;
551
224
        return 0;
552
224
    }
553
    // parse argument name or number
554
821k
    index=skipIdentifier(index);
555
821k
    int32_t number=parseArgNumber(nameIndex, index);
556
821k
    if(number>=0) {
557
504k
        int32_t length=index-nameIndex;
558
504k
        if(length>Part::MAX_LENGTH || number>Part::MAX_VALUE) {
559
62
            setParseError(parseError, nameIndex);  // Argument number too large.
560
62
            errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
561
62
            return 0;
562
62
        }
563
504k
        hasArgNumbers=true;
564
504k
        addPart(UMSGPAT_PART_TYPE_ARG_NUMBER, nameIndex, length, number, errorCode);
565
504k
    } else if(number==UMSGPAT_ARG_NAME_NOT_NUMBER) {
566
311k
        int32_t length=index-nameIndex;
567
311k
        if(length>Part::MAX_LENGTH) {
568
10
            setParseError(parseError, nameIndex);  // Argument name too long.
569
10
            errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
570
10
            return 0;
571
10
        }
572
311k
        hasArgNames=true;
573
311k
        addPart(UMSGPAT_PART_TYPE_ARG_NAME, nameIndex, length, 0, errorCode);
574
311k
    } else {  // number<-1 (ARG_NAME_NOT_VALID)
575
5.02k
        setParseError(parseError, nameIndex);  // Bad argument syntax.
576
5.02k
        errorCode=U_PATTERN_SYNTAX_ERROR;
577
5.02k
        return 0;
578
5.02k
    }
579
816k
    index=skipWhiteSpace(index);
580
816k
    if(index==msg.length()) {
581
640
        setParseError(parseError, 0);  // Unmatched '{' braces in message.
582
640
        errorCode=U_UNMATCHED_BRACES;
583
640
        return 0;
584
640
    }
585
815k
    char16_t c=msg.charAt(index);
586
815k
    if(c==u_rightCurlyBrace) {
587
        // all done
588
543k
    } else if(c!=u_comma) {
589
266
        setParseError(parseError, nameIndex);  // Bad argument syntax.
590
266
        errorCode=U_PATTERN_SYNTAX_ERROR;
591
266
        return 0;
592
272k
    } else /* ',' */ {
593
        // parse argument type: case-sensitive a-zA-Z
594
272k
        int32_t typeIndex=index=skipWhiteSpace(index+1);
595
3.15M
        while(index<msg.length() && isArgTypeChar(msg.charAt(index))) {
596
2.88M
            ++index;
597
2.88M
        }
598
272k
        int32_t length=index-typeIndex;
599
272k
        index=skipWhiteSpace(index);
600
272k
        if(index==msg.length()) {
601
94
            setParseError(parseError, 0);  // Unmatched '{' braces in message.
602
94
            errorCode=U_UNMATCHED_BRACES;
603
94
            return 0;
604
94
        }
605
272k
        if(length==0 || ((c=msg.charAt(index))!=u_comma && c!=u_rightCurlyBrace)) {
606
242
            setParseError(parseError, nameIndex);  // Bad argument syntax.
607
242
            errorCode=U_PATTERN_SYNTAX_ERROR;
608
242
            return 0;
609
242
        }
610
271k
        if(length>Part::MAX_LENGTH) {
611
2
            setParseError(parseError, nameIndex);  // Argument type name too long.
612
2
            errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
613
2
            return 0;
614
2
        }
615
271k
        argType=UMSGPAT_ARG_TYPE_SIMPLE;
616
271k
        if(length==6) {
617
            // case-insensitive comparisons for complex-type names
618
79.5k
            if(isChoice(typeIndex)) {
619
25.6k
                argType=UMSGPAT_ARG_TYPE_CHOICE;
620
53.9k
            } else if(isPlural(typeIndex)) {
621
44.4k
                argType=UMSGPAT_ARG_TYPE_PLURAL;
622
44.4k
            } else if(isSelect(typeIndex)) {
623
5.18k
                argType=UMSGPAT_ARG_TYPE_SELECT;
624
5.18k
            }
625
192k
        } else if(length==13) {
626
13.9k
            if(isSelect(typeIndex) && isOrdinal(typeIndex+6)) {
627
826
                argType=UMSGPAT_ARG_TYPE_SELECTORDINAL;
628
826
            }
629
13.9k
        }
630
        // change the ARG_START type from NONE to argType
631
271k
        partsList->a[argStart].value = static_cast<int16_t>(argType);
632
271k
        if(argType==UMSGPAT_ARG_TYPE_SIMPLE) {
633
195k
            addPart(UMSGPAT_PART_TYPE_ARG_TYPE, typeIndex, length, 0, errorCode);
634
195k
        }
635
        // look for an argument style (pattern)
636
271k
        if(c==u_rightCurlyBrace) {
637
73.1k
            if(argType!=UMSGPAT_ARG_TYPE_SIMPLE) {
638
4
                setParseError(parseError, nameIndex);  // No style field for complex argument.
639
4
                errorCode=U_PATTERN_SYNTAX_ERROR;
640
4
                return 0;
641
4
            }
642
198k
        } else /* ',' */ {
643
198k
            ++index;
644
198k
            if(argType==UMSGPAT_ARG_TYPE_SIMPLE) {
645
122k
                index=parseSimpleStyle(index, parseError, errorCode);
646
122k
            } else if(argType==UMSGPAT_ARG_TYPE_CHOICE) {
647
25.6k
                index=parseChoiceStyle(index, nestingLevel, parseError, errorCode);
648
50.4k
            } else {
649
50.4k
                index=parsePluralOrSelectStyle(argType, index, nestingLevel, parseError, errorCode);
650
50.4k
            }
651
198k
        }
652
271k
    }
653
    // Argument parsing stopped on the '}'.
654
815k
    addLimitPart(argStart, UMSGPAT_PART_TYPE_ARG_LIMIT, index, 1, argType, errorCode);
655
815k
    return index+1;
656
815k
}
657
658
int32_t
659
122k
MessagePattern::parseSimpleStyle(int32_t index, UParseError *parseError, UErrorCode &errorCode) {
660
122k
    if(U_FAILURE(errorCode)) {
661
0
        return 0;
662
0
    }
663
122k
    int32_t start=index;
664
122k
    int32_t nestedBraces=0;
665
33.7M
    while(index<msg.length()) {
666
33.7M
        char16_t c=msg.charAt(index++);
667
33.7M
        if(c==u_apos) {
668
            // Treat apostrophe as quoting but include it in the style part.
669
            // Find the end of the quoted literal text.
670
45.6k
            index=msg.indexOf(u_apos, index);
671
45.6k
            if(index<0) {
672
                // Quoted literal argument style text reaches to the end of the message.
673
32
                setParseError(parseError, start);
674
32
                errorCode=U_PATTERN_SYNTAX_ERROR;
675
32
                return 0;
676
32
            }
677
            // skip the quote-ending apostrophe
678
45.6k
            ++index;
679
33.7M
        } else if(c==u_leftCurlyBrace) {
680
31.8k
            ++nestedBraces;
681
33.6M
        } else if(c==u_rightCurlyBrace) {
682
146k
            if(nestedBraces>0) {
683
24.2k
                --nestedBraces;
684
122k
            } else {
685
122k
                int32_t length=--index-start;
686
122k
                if(length>Part::MAX_LENGTH) {
687
4
                    setParseError(parseError, start);  // Argument style text too long.
688
4
                    errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
689
4
                    return 0;
690
4
                }
691
122k
                addPart(UMSGPAT_PART_TYPE_ARG_STYLE, start, length, 0, errorCode);
692
122k
                return index;
693
122k
            }
694
146k
        }  // c is part of literal text
695
33.7M
    }
696
368
    setParseError(parseError, 0);  // Unmatched '{' braces in message.
697
368
    errorCode=U_UNMATCHED_BRACES;
698
368
    return 0;
699
122k
}
700
701
int32_t
702
MessagePattern::parseChoiceStyle(int32_t index, int32_t nestingLevel,
703
25.6k
                                 UParseError *parseError, UErrorCode &errorCode) {
704
25.6k
    if(U_FAILURE(errorCode)) {
705
0
        return 0;
706
0
    }
707
25.6k
    int32_t start=index;
708
25.6k
    index=skipWhiteSpace(index);
709
25.6k
    if(index==msg.length() || msg.charAt(index)==u_rightCurlyBrace) {
710
12
        setParseError(parseError, 0);  // Missing choice argument pattern.
711
12
        errorCode=U_PATTERN_SYNTAX_ERROR;
712
12
        return 0;
713
12
    }
714
769k
    for(;;) {
715
        // The choice argument style contains |-separated (number, separator, message) triples.
716
        // Parse the number.
717
769k
        int32_t numberIndex=index;
718
769k
        index=skipDouble(index);
719
769k
        int32_t length=index-numberIndex;
720
769k
        if(length==0) {
721
110
            setParseError(parseError, start);  // Bad choice pattern syntax.
722
110
            errorCode=U_PATTERN_SYNTAX_ERROR;
723
110
            return 0;
724
110
        }
725
769k
        if(length>Part::MAX_LENGTH) {
726
8
            setParseError(parseError, numberIndex);  // Choice number too long.
727
8
            errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
728
8
            return 0;
729
8
        }
730
769k
        parseDouble(numberIndex, index, true, parseError, errorCode);  // adds ARG_INT or ARG_DOUBLE
731
769k
        if(U_FAILURE(errorCode)) {
732
210
            return 0;
733
210
        }
734
        // Parse the separator.
735
769k
        index=skipWhiteSpace(index);
736
769k
        if(index==msg.length()) {
737
196
            setParseError(parseError, start);  // Bad choice pattern syntax.
738
196
            errorCode=U_PATTERN_SYNTAX_ERROR;
739
196
            return 0;
740
196
        }
741
768k
        char16_t c=msg.charAt(index);
742
768k
        if(!(c==u_pound || c==u_lessThan || c==u_lessOrEqual)) {  // U+2264 is <=
743
92
            setParseError(parseError, start);  // Expected choice separator (#<\u2264) instead of c.
744
92
            errorCode=U_PATTERN_SYNTAX_ERROR;
745
92
            return 0;
746
92
        }
747
768k
        addPart(UMSGPAT_PART_TYPE_ARG_SELECTOR, index, 1, 0, errorCode);
748
        // Parse the message fragment.
749
768k
        index=parseMessage(++index, 0, nestingLevel+1, UMSGPAT_ARG_TYPE_CHOICE, parseError, errorCode);
750
768k
        if(U_FAILURE(errorCode)) {
751
17.2k
            return 0;
752
17.2k
        }
753
        // parseMessage(..., CHOICE) returns the index of the terminator, or msg.length().
754
751k
        if(index==msg.length()) {
755
0
            return index;
756
0
        }
757
751k
        if(msg.charAt(index)==u_rightCurlyBrace) {
758
7.76k
            if(!inMessageFormatPattern(nestingLevel)) {
759
0
                setParseError(parseError, start);  // Bad choice pattern syntax.
760
0
                errorCode=U_PATTERN_SYNTAX_ERROR;
761
0
                return 0;
762
0
            }
763
7.76k
            return index;
764
7.76k
        }  // else the terminator is '|'
765
743k
        index=skipWhiteSpace(index+1);
766
743k
    }
767
25.6k
}
768
769
int32_t
770
MessagePattern::parsePluralOrSelectStyle(UMessagePatternArgType argType,
771
                                         int32_t index, int32_t nestingLevel,
772
72.5k
                                         UParseError *parseError, UErrorCode &errorCode) {
773
72.5k
    if(U_FAILURE(errorCode)) {
774
0
        return 0;
775
0
    }
776
72.5k
    int32_t start=index;
777
72.5k
    UBool isEmpty=true;
778
72.5k
    UBool hasOther=false;
779
162k
    for(;;) {
780
        // First, collect the selector looking for a small set of terminators.
781
        // It would be a little faster to consider the syntax of each possible
782
        // token right here, but that makes the code too complicated.
783
162k
        index=skipWhiteSpace(index);
784
162k
        UBool eos=index==msg.length();
785
162k
        if(eos || msg.charAt(index)==u_rightCurlyBrace) {
786
22.1k
            if(eos==inMessageFormatPattern(nestingLevel)) {
787
52
                setParseError(parseError, start);  // Bad plural/select pattern syntax.
788
52
                errorCode=U_PATTERN_SYNTAX_ERROR;
789
52
                return 0;
790
52
            }
791
22.0k
            if(!hasOther) {
792
2
                setParseError(parseError, 0);  // Missing 'other' keyword in plural/select pattern.
793
2
                errorCode=U_DEFAULT_KEYWORD_MISSING;
794
2
                return 0;
795
2
            }
796
22.0k
            return index;
797
22.0k
        }
798
140k
        int32_t selectorIndex=index;
799
140k
        if(UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType) && msg.charAt(selectorIndex)==u_equal) {
800
            // explicit-value plural selector: =double
801
3.23k
            index=skipDouble(index+1);
802
3.23k
            int32_t length=index-selectorIndex;
803
3.23k
            if(length==1) {
804
84
                setParseError(parseError, start);  // Bad plural/select pattern syntax.
805
84
                errorCode=U_PATTERN_SYNTAX_ERROR;
806
84
                return 0;
807
84
            }
808
3.15k
            if(length>Part::MAX_LENGTH) {
809
4
                setParseError(parseError, selectorIndex);  // Argument selector too long.
810
4
                errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
811
4
                return 0;
812
4
            }
813
3.15k
            addPart(UMSGPAT_PART_TYPE_ARG_SELECTOR, selectorIndex, length, 0, errorCode);
814
3.15k
            parseDouble(selectorIndex+1, index, false,
815
3.15k
                        parseError, errorCode);  // adds ARG_INT or ARG_DOUBLE
816
137k
        } else {
817
137k
            index=skipIdentifier(index);
818
137k
            int32_t length=index-selectorIndex;
819
137k
            if(length==0) {
820
30
                setParseError(parseError, start);  // Bad plural/select pattern syntax.
821
30
                errorCode=U_PATTERN_SYNTAX_ERROR;
822
30
                return 0;
823
30
            }
824
            // Note: The ':' in "offset:" is just beyond the skipIdentifier() range.
825
137k
            if( UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType) && length==6 && index<msg.length() &&
826
1.20k
                0==msg.compare(selectorIndex, 7, kOffsetColon, 0, 7)
827
137k
            ) {
828
                // plural offset, not a selector
829
0
                if(!isEmpty) {
830
                    // Plural argument 'offset:' (if present) must precede key-message pairs.
831
0
                    setParseError(parseError, start);
832
0
                    errorCode=U_PATTERN_SYNTAX_ERROR;
833
0
                    return 0;
834
0
                }
835
                // allow whitespace between offset: and its value
836
0
                int32_t valueIndex=skipWhiteSpace(index+1);  // The ':' is at index.
837
0
                index=skipDouble(valueIndex);
838
0
                if(index==valueIndex) {
839
0
                    setParseError(parseError, start);  // Missing value for plural 'offset:'.
840
0
                    errorCode=U_PATTERN_SYNTAX_ERROR;
841
0
                    return 0;
842
0
                }
843
0
                if((index-valueIndex)>Part::MAX_LENGTH) {
844
0
                    setParseError(parseError, valueIndex);  // Plural offset value too long.
845
0
                    errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
846
0
                    return 0;
847
0
                }
848
0
                parseDouble(valueIndex, index, false,
849
0
                            parseError, errorCode);  // adds ARG_INT or ARG_DOUBLE
850
0
                if(U_FAILURE(errorCode)) {
851
0
                    return 0;
852
0
                }
853
0
                isEmpty=false;
854
0
                continue;  // no message fragment after the offset
855
137k
            } else {
856
                // normal selector word
857
137k
                if(length>Part::MAX_LENGTH) {
858
10
                    setParseError(parseError, selectorIndex);  // Argument selector too long.
859
10
                    errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
860
10
                    return 0;
861
10
                }
862
137k
                addPart(UMSGPAT_PART_TYPE_ARG_SELECTOR, selectorIndex, length, 0, errorCode);
863
137k
                if(0==msg.compare(selectorIndex, length, kOther, 0, 5)) {
864
22.0k
                    hasOther=true;
865
22.0k
                }
866
137k
            }
867
137k
        }
868
140k
        if(U_FAILURE(errorCode)) {
869
118
            return 0;
870
118
        }
871
872
        // parse the message fragment following the selector
873
140k
        index=skipWhiteSpace(index);
874
140k
        if(index==msg.length() || msg.charAt(index)!=u_leftCurlyBrace) {
875
290
            setParseError(parseError, selectorIndex);  // No message fragment after plural/select selector.
876
290
            errorCode=U_PATTERN_SYNTAX_ERROR;
877
290
            return 0;
878
290
        }
879
139k
        index=parseMessage(index, 1, nestingLevel+1, argType, parseError, errorCode);
880
139k
        if(U_FAILURE(errorCode)) {
881
49.8k
            return 0;
882
49.8k
        }
883
90.1k
        isEmpty=false;
884
90.1k
    }
885
72.5k
}
886
887
int32_t
888
821k
MessagePattern::parseArgNumber(const UnicodeString &s, int32_t start, int32_t limit) {
889
    // If the identifier contains only ASCII digits, then it is an argument _number_
890
    // and must not have leading zeros (except "0" itself).
891
    // Otherwise it is an argument _name_.
892
821k
    if(start>=limit) {
893
4.98k
        return UMSGPAT_ARG_NAME_NOT_VALID;
894
4.98k
    }
895
816k
    int32_t number;
896
    // Defer numeric errors until we know there are only digits.
897
816k
    UBool badNumber;
898
816k
    char16_t c=s.charAt(start++);
899
816k
    if(c==0x30) {
900
500k
        if(start==limit) {
901
499k
            return 0;
902
499k
        } else {
903
1.52k
            number=0;
904
1.52k
            badNumber=true;  // leading zero
905
1.52k
        }
906
500k
    } else if(0x31<=c && c<=0x39) {
907
6.64k
        number=c-0x30;
908
6.64k
        badNumber=false;
909
309k
    } else {
910
309k
        return UMSGPAT_ARG_NAME_NOT_NUMBER;
911
309k
    }
912
11.6k
    while(start<limit) {
913
5.76k
        c=s.charAt(start++);
914
5.76k
        if(0x30<=c && c<=0x39) {
915
3.46k
            if(number>=INT32_MAX/10) {
916
696
                badNumber=true;  // overflow
917
2.76k
            } else {
918
2.76k
                number=number*10+(c-0x30);
919
2.76k
            }
920
3.46k
        } else {
921
2.30k
            return UMSGPAT_ARG_NAME_NOT_NUMBER;
922
2.30k
        }
923
5.76k
    }
924
    // There are only ASCII digits.
925
5.85k
    if(badNumber) {
926
36
        return UMSGPAT_ARG_NAME_NOT_VALID;
927
5.82k
    } else {
928
5.82k
        return number;
929
5.82k
    }
930
5.85k
}
931
932
void
933
MessagePattern::parseDouble(int32_t start, int32_t limit, UBool allowInfinity,
934
772k
                            UParseError *parseError, UErrorCode &errorCode) {
935
772k
    if(U_FAILURE(errorCode)) {
936
0
        return;
937
0
    }
938
772k
    U_ASSERT(start<limit);
939
    // fake loop for easy exit and single throw statement
940
772k
    for(;;) { /*loop doesn't iterate*/
941
        // fast path for small integers and infinity
942
772k
        int32_t value=0;
943
772k
        int32_t isNegative=0;  // not boolean so that we can easily add it to value
944
772k
        int32_t index=start;
945
772k
        char16_t c=msg.charAt(index++);
946
772k
        if(c==u_minus) {
947
25.1k
            isNegative=1;
948
25.1k
            if(index==limit) {
949
14
                break;  // no number
950
14
            }
951
25.1k
            c=msg.charAt(index++);
952
747k
        } else if(c==u_plus) {
953
3.76k
            if(index==limit) {
954
18
                break;  // no number
955
18
            }
956
3.75k
            c=msg.charAt(index++);
957
3.75k
        }
958
772k
        if(c==0x221e) {  // infinity
959
504
            if(allowInfinity && index==limit) {
960
456
                double infinity=uprv_getInfinity();
961
456
                addArgDoublePart(
962
456
                    isNegative!=0 ? -infinity : infinity,
963
456
                    start, limit-start, errorCode);
964
456
                return;
965
456
            } else {
966
48
                break;
967
48
            }
968
504
        }
969
        // try to parse the number as a small integer but fall back to a double
970
817k
        while('0'<=c && c<='9') {
971
121k
            value=value*10+(c-'0');
972
121k
            if(value>(Part::MAX_VALUE+isNegative)) {
973
5.08k
                break;  // not a small-enough integer
974
5.08k
            }
975
116k
            if(index==limit) {
976
71.0k
                addPart(UMSGPAT_PART_TYPE_ARG_INT, start, limit-start,
977
71.0k
                        isNegative!=0 ? -value : value, errorCode);
978
71.0k
                return;
979
71.0k
            }
980
45.6k
            c=msg.charAt(index++);
981
45.6k
        }
982
        // Let Double.parseDouble() throw a NumberFormatException.
983
700k
        char numberChars[128];
984
700k
        int32_t capacity = static_cast<int32_t>(sizeof(numberChars));
985
700k
        int32_t length=limit-start;
986
700k
        if(length>=capacity) {
987
26
            break;  // number too long
988
26
        }
989
700k
        msg.extract(start, length, numberChars, capacity, US_INV);
990
700k
        if (static_cast<int32_t>(uprv_strlen(numberChars)) < length) {
991
26
            break;  // contains non-invariant character that was turned into NUL
992
26
        }
993
700k
        char *end;
994
700k
        double numericValue=uprv_strtod(numberChars, &end);
995
700k
        if(end!=(numberChars+length)) {
996
194
            break;  // parsing error
997
194
        }
998
700k
        addArgDoublePart(numericValue, start, length, errorCode);
999
700k
        return;
1000
700k
    }
1001
326
    setParseError(parseError, start /*, limit*/);  // Bad syntax for numeric value.
1002
326
    errorCode=U_PATTERN_SYNTAX_ERROR;
1003
326
}
1004
1005
int32_t
1006
4.02M
MessagePattern::skipWhiteSpace(int32_t index) {
1007
4.02M
    const char16_t *s=msg.getBuffer();
1008
4.02M
    int32_t msgLength=msg.length();
1009
4.02M
    const char16_t *t=PatternProps::skipWhiteSpace(s+index, msgLength-index);
1010
4.02M
    return static_cast<int32_t>(t - s);
1011
4.02M
}
1012
1013
int32_t
1014
958k
MessagePattern::skipIdentifier(int32_t index) {
1015
958k
    const char16_t *s=msg.getBuffer();
1016
958k
    int32_t msgLength=msg.length();
1017
958k
    const char16_t *t=PatternProps::skipIdentifier(s+index, msgLength-index);
1018
958k
    return static_cast<int32_t>(t - s);
1019
958k
}
1020
1021
int32_t
1022
772k
MessagePattern::skipDouble(int32_t index) {
1023
772k
    int32_t msgLength=msg.length();
1024
4.45M
    while(index<msgLength) {
1025
4.45M
        char16_t c=msg.charAt(index);
1026
        // U+221E: Allow the infinity symbol, for ChoiceFormat patterns.
1027
4.45M
        if((c<0x30 && c!=u_plus && c!=u_minus && c!=u_dot) || (c>0x39 && c!=u_e && c!=u_E && c!=0x221e)) {
1028
772k
            break;
1029
772k
        }
1030
3.68M
        ++index;
1031
3.68M
    }
1032
772k
    return index;
1033
772k
}
1034
1035
UBool
1036
3.15M
MessagePattern::isArgTypeChar(UChar32 c) {
1037
3.15M
    return (u_a<=c && c<=u_z) || (u_A<=c && c<=u_Z);
1038
3.15M
}
1039
1040
UBool
1041
79.5k
MessagePattern::isChoice(int32_t index) {
1042
79.5k
    char16_t c;
1043
79.5k
    return
1044
79.5k
        ((c=msg.charAt(index++))==u_c || c==u_C) &&
1045
26.6k
        ((c=msg.charAt(index++))==u_h || c==u_H) &&
1046
26.4k
        ((c=msg.charAt(index++))==u_o || c==u_O) &&
1047
26.2k
        ((c=msg.charAt(index++))==u_i || c==u_I) &&
1048
26.0k
        ((c=msg.charAt(index++))==u_c || c==u_C) &&
1049
25.8k
        ((c=msg.charAt(index))==u_e || c==u_E);
1050
79.5k
}
1051
1052
UBool
1053
53.9k
MessagePattern::isPlural(int32_t index) {
1054
53.9k
    char16_t c;
1055
53.9k
    return
1056
53.9k
        ((c=msg.charAt(index++))==u_p || c==u_P) &&
1057
46.2k
        ((c=msg.charAt(index++))==u_l || c==u_L) &&
1058
45.9k
        ((c=msg.charAt(index++))==u_u || c==u_U) &&
1059
45.3k
        ((c=msg.charAt(index++))==u_r || c==u_R) &&
1060
44.9k
        ((c=msg.charAt(index++))==u_a || c==u_A) &&
1061
44.7k
        ((c=msg.charAt(index))==u_l || c==u_L);
1062
53.9k
}
1063
1064
UBool
1065
23.4k
MessagePattern::isSelect(int32_t index) {
1066
23.4k
    char16_t c;
1067
23.4k
    return
1068
23.4k
        ((c=msg.charAt(index++))==u_s || c==u_S) &&
1069
20.5k
        ((c=msg.charAt(index++))==u_e || c==u_E) &&
1070
20.3k
        ((c=msg.charAt(index++))==u_l || c==u_L) &&
1071
19.7k
        ((c=msg.charAt(index++))==u_e || c==u_E) &&
1072
19.4k
        ((c=msg.charAt(index++))==u_c || c==u_C) &&
1073
19.0k
        ((c=msg.charAt(index))==u_t || c==u_T);
1074
23.4k
}
1075
1076
UBool
1077
13.6k
MessagePattern::isOrdinal(int32_t index) {
1078
13.6k
    char16_t c;
1079
13.6k
    return
1080
13.6k
        ((c=msg.charAt(index++))==u_o || c==u_O) &&
1081
13.2k
        ((c=msg.charAt(index++))==u_r || c==u_R) &&
1082
12.7k
        ((c=msg.charAt(index++))==u_d || c==u_D) &&
1083
9.73k
        ((c=msg.charAt(index++))==u_i || c==u_I) &&
1084
9.51k
        ((c=msg.charAt(index++))==u_n || c==u_N) &&
1085
9.20k
        ((c=msg.charAt(index++))==u_a || c==u_A) &&
1086
6.31k
        ((c=msg.charAt(index))==u_l || c==u_L);
1087
13.6k
}
1088
1089
UBool
1090
29.8k
MessagePattern::inMessageFormatPattern(int32_t nestingLevel) {
1091
29.8k
    return nestingLevel>0 || partsList->a[0].type==UMSGPAT_PART_TYPE_MSG_START;
1092
29.8k
}
1093
1094
UBool
1095
372
MessagePattern::inTopLevelChoiceMessage(int32_t nestingLevel, UMessagePatternArgType parentType) {
1096
372
    return
1097
372
        nestingLevel==1 &&
1098
290
        parentType==UMSGPAT_ARG_TYPE_CHOICE &&
1099
160
        partsList->a[0].type!=UMSGPAT_PART_TYPE_MSG_START;
1100
372
}
1101
1102
void
1103
MessagePattern::addPart(UMessagePatternPartType type, int32_t index, int32_t length,
1104
6.92M
                        int32_t value, UErrorCode &errorCode) {
1105
6.92M
    if(partsList->ensureCapacityForOneMore(partsLength, errorCode)) {
1106
6.86M
        Part &part=partsList->a[partsLength++];
1107
6.86M
        part.type=type;
1108
6.86M
        part.index=index;
1109
6.86M
        part.length = static_cast<uint16_t>(length);
1110
6.86M
        part.value = static_cast<int16_t>(value);
1111
6.86M
        part.limitPartIndex=0;
1112
6.86M
    }
1113
6.92M
}
1114
1115
void
1116
MessagePattern::addLimitPart(int32_t start,
1117
                             UMessagePatternPartType type, int32_t index, int32_t length,
1118
1.66M
                             int32_t value, UErrorCode &errorCode) {
1119
1.66M
    partsList->a[start].limitPartIndex=partsLength;
1120
1.66M
    addPart(type, index, length, value, errorCode);
1121
1.66M
}
1122
1123
void
1124
MessagePattern::addArgDoublePart(double numericValue, int32_t start, int32_t length,
1125
701k
                                 UErrorCode &errorCode) {
1126
701k
    if(U_FAILURE(errorCode)) {
1127
0
        return;
1128
0
    }
1129
701k
    int32_t numericIndex=numericValuesLength;
1130
701k
    if(numericValuesList==nullptr) {
1131
366
        numericValuesList=new MessagePatternDoubleList();
1132
366
        if(numericValuesList==nullptr) {
1133
0
            errorCode=U_MEMORY_ALLOCATION_ERROR;
1134
0
            return;
1135
0
        }
1136
700k
    } else if(!numericValuesList->ensureCapacityForOneMore(numericValuesLength, errorCode)) {
1137
0
        return;
1138
700k
    } else {
1139
700k
        if(numericIndex>Part::MAX_VALUE) {
1140
2
            errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
1141
2
            return;
1142
2
        }
1143
700k
    }
1144
701k
    numericValuesList->a[numericValuesLength++]=numericValue;
1145
701k
    addPart(UMSGPAT_PART_TYPE_ARG_DOUBLE, start, length, numericIndex, errorCode);
1146
701k
}
1147
1148
void
1149
8.55k
MessagePattern::setParseError(UParseError *parseError, int32_t index) {
1150
8.55k
    if(parseError==nullptr) {
1151
0
        return;
1152
0
    }
1153
8.55k
    parseError->offset=index;
1154
1155
    // Set preContext to some of msg before index.
1156
    // Avoid splitting a surrogate pair.
1157
8.55k
    int32_t length=index;
1158
8.55k
    if(length>=U_PARSE_CONTEXT_LEN) {
1159
1.56k
        length=U_PARSE_CONTEXT_LEN-1;
1160
1.56k
        if(length>0 && U16_IS_TRAIL(msg[index-length])) {
1161
4
            --length;
1162
4
        }
1163
1.56k
    }
1164
8.55k
    msg.extract(index-length, length, parseError->preContext);
1165
8.55k
    parseError->preContext[length]=0;
1166
1167
    // Set postContext to some of msg starting at index.
1168
8.55k
    length=msg.length()-index;
1169
8.55k
    if(length>=U_PARSE_CONTEXT_LEN) {
1170
4.80k
        length=U_PARSE_CONTEXT_LEN-1;
1171
4.80k
        if(length>0 && U16_IS_LEAD(msg[index+length-1])) {
1172
98
            --length;
1173
98
        }
1174
4.80k
    }
1175
8.55k
    msg.extract(index, length, parseError->postContext);
1176
8.55k
    parseError->postContext[length]=0;
1177
8.55k
}
1178
1179
// MessageImpl ------------------------------------------------------------- ***
1180
1181
void
1182
MessageImpl::appendReducedApostrophes(const UnicodeString &s, int32_t start, int32_t limit,
1183
0
                                      UnicodeString &sb) {
1184
0
    int32_t doubleApos=-1;
1185
0
    for(;;) {
1186
0
        int32_t i=s.indexOf(u_apos, start);
1187
0
        if(i<0 || i>=limit) {
1188
0
            sb.append(s, start, limit-start);
1189
0
            break;
1190
0
        }
1191
0
        if(i==doubleApos) {
1192
            // Double apostrophe at start-1 and start==i, append one.
1193
0
            sb.append(u_apos);
1194
0
            ++start;
1195
0
            doubleApos=-1;
1196
0
        } else {
1197
            // Append text between apostrophes and skip this one.
1198
0
            sb.append(s, start, i-start);
1199
0
            doubleApos=start=i+1;
1200
0
        }
1201
0
    }
1202
0
}
1203
1204
// Ported from second half of ICU4J SelectFormat.format(String).
1205
UnicodeString &
1206
MessageImpl::appendSubMessageWithoutSkipSyntax(const MessagePattern &msgPattern,
1207
                                               int32_t msgStart,
1208
0
                                               UnicodeString &result) {
1209
0
    const UnicodeString &msgString=msgPattern.getPatternString();
1210
0
    int32_t prevIndex=msgPattern.getPart(msgStart).getLimit();
1211
0
    for(int32_t i=msgStart;;) {
1212
0
        const MessagePattern::Part &part=msgPattern.getPart(++i);
1213
0
        UMessagePatternPartType type=part.getType();
1214
0
        int32_t index=part.getIndex();
1215
0
        if(type==UMSGPAT_PART_TYPE_MSG_LIMIT) {
1216
0
            return result.append(msgString, prevIndex, index-prevIndex);
1217
0
        } else if(type==UMSGPAT_PART_TYPE_SKIP_SYNTAX) {
1218
0
            result.append(msgString, prevIndex, index-prevIndex);
1219
0
            prevIndex=part.getLimit();
1220
0
        } else if(type==UMSGPAT_PART_TYPE_ARG_START) {
1221
0
            result.append(msgString, prevIndex, index-prevIndex);
1222
0
            prevIndex=index;
1223
0
            i=msgPattern.getLimitPartIndex(i);
1224
0
            index=msgPattern.getPart(i).getLimit();
1225
0
            appendReducedApostrophes(msgString, prevIndex, index, result);
1226
0
            prevIndex=index;
1227
0
        }
1228
0
    }
1229
0
}
1230
1231
U_NAMESPACE_END
1232
1233
#endif  // !UCONFIG_NO_FORMATTING