#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "unicode/msgfmt.h"
#include "unicode/decimfmt.h"
#include "unicode/datefmt.h"
#include "unicode/smpdtfmt.h"
#include "unicode/choicfmt.h"
#include "unicode/ustring.h"
#include "unicode/ucnv_err.h"
#include "unicode/uchar.h"
#include "unicode/umsg.h"
#include "unicode/rbnf.h"
#include "ustrfmt.h"
#include "cmemory.h"
#include "util.h"
#include "uassert.h"
#define COMMA ((UChar)0x002C)
#define SINGLE_QUOTE ((UChar)0x0027)
#define LEFT_CURLY_BRACE ((UChar)0x007B)
#define RIGHT_CURLY_BRACE ((UChar)0x007D)
static const UChar ID_EMPTY[] = {
0
};
static const UChar ID_NUMBER[] = {
0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0
};
static const UChar ID_DATE[] = {
0x64, 0x61, 0x74, 0x65, 0
};
static const UChar ID_TIME[] = {
0x74, 0x69, 0x6D, 0x65, 0
};
static const UChar ID_CHOICE[] = {
0x63, 0x68, 0x6F, 0x69, 0x63, 0x65, 0
};
static const UChar ID_SPELLOUT[] = {
0x73, 0x70, 0x65, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0
};
static const UChar ID_ORDINAL[] = {
0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0
};
static const UChar ID_DURATION[] = {
0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0
};
static const UChar * const TYPE_IDS[] = {
ID_EMPTY,
ID_NUMBER,
ID_DATE,
ID_TIME,
ID_CHOICE,
ID_SPELLOUT,
ID_ORDINAL,
ID_DURATION,
NULL,
};
static const UChar ID_CURRENCY[] = {
0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x63, 0x79, 0
};
static const UChar ID_PERCENT[] = {
0x70, 0x65, 0x72, 0x63, 0x65, 0x6E, 0x74, 0
};
static const UChar ID_INTEGER[] = {
0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0
};
static const UChar * const NUMBER_STYLE_IDS[] = {
ID_EMPTY,
ID_CURRENCY,
ID_PERCENT,
ID_INTEGER,
NULL,
};
static const UChar ID_SHORT[] = {
0x73, 0x68, 0x6F, 0x72, 0x74, 0
};
static const UChar ID_MEDIUM[] = {
0x6D, 0x65, 0x64, 0x69, 0x75, 0x6D, 0
};
static const UChar ID_LONG[] = {
0x6C, 0x6F, 0x6E, 0x67, 0
};
static const UChar ID_FULL[] = {
0x66, 0x75, 0x6C, 0x6C, 0
};
static const UChar * const DATE_STYLE_IDS[] = {
ID_EMPTY,
ID_SHORT,
ID_MEDIUM,
ID_LONG,
ID_FULL,
NULL,
};
static const DateFormat::EStyle DATE_STYLES[] = {
DateFormat::kDefault,
DateFormat::kShort,
DateFormat::kMedium,
DateFormat::kLong,
DateFormat::kFull,
};
static const int32_t DEFAULT_INITIAL_CAPACITY = 10;
U_NAMESPACE_BEGIN
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MessageFormat)
static int32_t stou(const UnicodeString& string) {
int32_t n = 0;
int32_t count = 0;
UChar32 c;
for (int32_t i=0; i<string.length(); i+=U16_LENGTH(c)) {
c = string.char32At(i);
if (uprv_isRuleWhiteSpace(c)) {
continue;
}
int32_t d = u_digit(c, 10);
if (d < 0 || ++count > 10) {
return -1;
}
n = 10*n + d;
}
return n;
}
static UnicodeString& itos(int32_t i, UnicodeString& appendTo) {
UChar temp[16];
uprv_itou(temp,16,i,10,0); appendTo.append(temp);
return appendTo;
}
MessageFormat::MessageFormat(const UnicodeString& pattern,
UErrorCode& success)
: fLocale(Locale::getDefault()), formatAliases(NULL),
formatAliasesCapacity(0),
subformats(NULL),
subformatCount(0),
subformatCapacity(0),
argTypes(NULL),
argTypeCount(0),
argTypeCapacity(0),
defaultNumberFormat(NULL),
defaultDateFormat(NULL)
{
if (!allocateSubformats(DEFAULT_INITIAL_CAPACITY) ||
!allocateArgTypes(DEFAULT_INITIAL_CAPACITY)) {
success = U_MEMORY_ALLOCATION_ERROR;
return;
}
applyPattern(pattern, success);
setLocaleIDs(fLocale.getName(), fLocale.getName());
}
MessageFormat::MessageFormat(const UnicodeString& pattern,
const Locale& newLocale,
UErrorCode& success)
: fLocale(newLocale),
formatAliases(NULL),
formatAliasesCapacity(0),
subformats(NULL),
subformatCount(0),
subformatCapacity(0),
argTypes(NULL),
argTypeCount(0),
argTypeCapacity(0),
defaultNumberFormat(NULL),
defaultDateFormat(NULL)
{
if (!allocateSubformats(DEFAULT_INITIAL_CAPACITY) ||
!allocateArgTypes(DEFAULT_INITIAL_CAPACITY)) {
success = U_MEMORY_ALLOCATION_ERROR;
return;
}
applyPattern(pattern, success);
setLocaleIDs(fLocale.getName(), fLocale.getName());
}
MessageFormat::MessageFormat(const UnicodeString& pattern,
const Locale& newLocale,
UParseError& parseError,
UErrorCode& success)
: fLocale(newLocale),
formatAliases(NULL),
formatAliasesCapacity(0),
subformats(NULL),
subformatCount(0),
subformatCapacity(0),
argTypes(NULL),
argTypeCount(0),
argTypeCapacity(0),
defaultNumberFormat(NULL),
defaultDateFormat(NULL)
{
if (!allocateSubformats(DEFAULT_INITIAL_CAPACITY) ||
!allocateArgTypes(DEFAULT_INITIAL_CAPACITY)) {
success = U_MEMORY_ALLOCATION_ERROR;
return;
}
applyPattern(pattern, parseError, success);
setLocaleIDs(fLocale.getName(), fLocale.getName());
}
MessageFormat::MessageFormat(const MessageFormat& that)
: Format(that),
formatAliases(NULL),
formatAliasesCapacity(0),
subformats(NULL),
subformatCount(0),
subformatCapacity(0),
argTypes(NULL),
argTypeCount(0),
argTypeCapacity(0),
defaultNumberFormat(NULL),
defaultDateFormat(NULL)
{
*this = that;
}
MessageFormat::~MessageFormat()
{
int32_t idx;
for (idx = 0; idx < subformatCount; idx++) {
delete subformats[idx].format;
}
uprv_free(subformats);
subformats = NULL;
subformatCount = subformatCapacity = 0;
uprv_free(argTypes);
argTypes = NULL;
argTypeCount = argTypeCapacity = 0;
uprv_free(formatAliases);
delete defaultNumberFormat;
delete defaultDateFormat;
}
UBool MessageFormat::allocateSubformats(int32_t capacity) {
if (subformats == NULL) {
subformats = (Subformat*) uprv_malloc(sizeof(*subformats) * capacity);
subformatCapacity = capacity;
subformatCount = 0;
if (subformats == NULL) {
subformatCapacity = 0;
return FALSE;
}
} else if (subformatCapacity < capacity) {
if (capacity < 2*subformatCapacity) {
capacity = 2*subformatCapacity;
}
Subformat* a = (Subformat*)
uprv_realloc(subformats, sizeof(*subformats) * capacity);
if (a == NULL) {
return FALSE; }
subformats = a;
subformatCapacity = capacity;
}
return TRUE;
}
UBool MessageFormat::allocateArgTypes(int32_t capacity) {
if (argTypes == NULL) {
argTypes = (Formattable::Type*) uprv_malloc(sizeof(*argTypes) * capacity);
argTypeCount = 0;
argTypeCapacity = capacity;
if (argTypes == NULL) {
argTypeCapacity = 0;
return FALSE;
}
for (int32_t i=0; i<capacity; ++i) {
argTypes[i] = Formattable::kString;
}
} else if (argTypeCapacity < capacity) {
if (capacity < 2*argTypeCapacity) {
capacity = 2*argTypeCapacity;
}
Formattable::Type* a = (Formattable::Type*)
uprv_realloc(argTypes, sizeof(*argTypes) * capacity);
if (a == NULL) {
return FALSE; }
for (int32_t i=argTypeCapacity; i<capacity; ++i) {
a[i] = Formattable::kString;
}
argTypes = a;
argTypeCapacity = capacity;
}
return TRUE;
}
const MessageFormat&
MessageFormat::operator=(const MessageFormat& that)
{
if (this != &that &&
allocateSubformats(that.subformatCount) &&
allocateArgTypes(that.argTypeCount)) {
Format::operator=(that);
fPattern = that.fPattern;
setLocale(that.fLocale);
int32_t j;
for (j=0; j<subformatCount; ++j) {
delete subformats[j].format;
}
subformatCount = 0;
for (j=0; j<that.subformatCount; ++j) {
subformats[j] = that.subformats[j];
}
subformatCount = that.subformatCount;
for (j=0; j<that.argTypeCount; ++j) {
argTypes[j] = that.argTypes[j];
}
argTypeCount = that.argTypeCount;
}
return *this;
}
UBool
MessageFormat::operator==(const Format& rhs) const
{
if (this == &rhs) return TRUE;
MessageFormat& that = (MessageFormat&)rhs;
if (!Format::operator==(rhs) ||
fPattern != that.fPattern ||
fLocale != that.fLocale) {
return FALSE;
}
int32_t j;
for (j=0; j<subformatCount; ++j) {
if (subformats[j] != that.subformats[j]) {
return FALSE;
}
}
return TRUE;
}
Format*
MessageFormat::clone() const
{
return new MessageFormat(*this);
}
void
MessageFormat::setLocale(const Locale& theLocale)
{
if (fLocale != theLocale) {
delete defaultNumberFormat;
defaultNumberFormat = NULL;
delete defaultDateFormat;
defaultDateFormat = NULL;
}
fLocale = theLocale;
setLocaleIDs(fLocale.getName(), fLocale.getName());
}
const Locale&
MessageFormat::getLocale() const
{
return fLocale;
}
void
MessageFormat::applyPattern(const UnicodeString& newPattern,
UErrorCode& status)
{
UParseError parseError;
applyPattern(newPattern,parseError,status);
}
void
MessageFormat::applyPattern(const UnicodeString& pattern,
UParseError& parseError,
UErrorCode& ec)
{
if(U_FAILURE(ec)) {
return;
}
UnicodeString segments[4];
int32_t part = 0; int32_t formatNumber = 0;
UBool inQuote = FALSE;
int32_t braceStack = 0;
parseError.offset = -1;
parseError.preContext[0] = parseError.postContext[0] = (UChar)0;
int32_t patLen = pattern.length();
int32_t i;
for (i=0; i<subformatCount; ++i) {
delete subformats[i].format;
}
subformatCount = 0;
argTypeCount = 0;
for (i=0; i<patLen; ++i) {
UChar ch = pattern[i];
if (part == 0) {
if (ch == SINGLE_QUOTE) {
if (i+1 < patLen && pattern[i+1] == SINGLE_QUOTE) {
segments[0] += ch;
++i;
} else {
inQuote = !inQuote;
}
} else if (ch == LEFT_CURLY_BRACE && !inQuote) {
part = 1;
} else {
segments[0] += ch;
}
} else if (inQuote) {
segments[part] += ch;
if (ch == SINGLE_QUOTE) {
inQuote = FALSE;
}
} else {
switch (ch) {
case COMMA:
if (part < 3)
part += 1;
else
segments[3] += ch;
break;
case LEFT_CURLY_BRACE:
if (part != 3) {
ec = U_PATTERN_SYNTAX_ERROR;
goto SYNTAX_ERROR;
}
++braceStack;
segments[part] += ch;
break;
case RIGHT_CURLY_BRACE:
if (braceStack == 0) {
makeFormat(formatNumber, segments, parseError,ec);
if (U_FAILURE(ec)){
goto SYNTAX_ERROR;
}
formatNumber++;
segments[1].remove();
segments[2].remove();
segments[3].remove();
part = 0;
} else {
--braceStack;
segments[part] += ch;
}
break;
case SINGLE_QUOTE:
inQuote = TRUE;
default:
segments[part] += ch;
break;
}
}
}
if (braceStack != 0 || part != 0) {
ec = U_UNMATCHED_BRACES;
goto SYNTAX_ERROR;
}
fPattern = segments[0];
return;
SYNTAX_ERROR:
syntaxError(pattern, i, parseError);
for (i=0; i<subformatCount; ++i) {
delete subformats[i].format;
}
argTypeCount = subformatCount = 0;
}
UnicodeString&
MessageFormat::toPattern(UnicodeString& appendTo) const {
int32_t lastOffset = 0;
int32_t i;
for (i=0; i<subformatCount; ++i) {
copyAndFixQuotes(fPattern, lastOffset, subformats[i].offset, appendTo);
lastOffset = subformats[i].offset;
appendTo += LEFT_CURLY_BRACE;
itos(subformats[i].arg, appendTo);
Format* fmt = subformats[i].format;
if (fmt == NULL) {
}
else if (fmt->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
UErrorCode ec = U_ZERO_ERROR;
NumberFormat& formatAlias = *(NumberFormat*)fmt;
NumberFormat *defaultTemplate = NumberFormat::createInstance(fLocale, ec);
NumberFormat *currencyTemplate = NumberFormat::createCurrencyInstance(fLocale, ec);
NumberFormat *percentTemplate = NumberFormat::createPercentInstance(fLocale, ec);
NumberFormat *integerTemplate = createIntegerFormat(fLocale, ec);
appendTo += COMMA;
appendTo += ID_NUMBER;
if (formatAlias != *defaultTemplate) {
appendTo += COMMA;
if (formatAlias == *currencyTemplate) {
appendTo += ID_CURRENCY;
}
else if (formatAlias == *percentTemplate) {
appendTo += ID_PERCENT;
}
else if (formatAlias == *integerTemplate) {
appendTo += ID_INTEGER;
}
else {
UnicodeString buffer;
appendTo += ((DecimalFormat*)fmt)->toPattern(buffer);
}
}
delete defaultTemplate;
delete currencyTemplate;
delete percentTemplate;
delete integerTemplate;
}
else if (fmt->getDynamicClassID() == SimpleDateFormat::getStaticClassID()) {
DateFormat& formatAlias = *(DateFormat*)fmt;
DateFormat *defaultDateTemplate = DateFormat::createDateInstance(DateFormat::kDefault, fLocale);
DateFormat *shortDateTemplate = DateFormat::createDateInstance(DateFormat::kShort, fLocale);
DateFormat *longDateTemplate = DateFormat::createDateInstance(DateFormat::kLong, fLocale);
DateFormat *fullDateTemplate = DateFormat::createDateInstance(DateFormat::kFull, fLocale);
DateFormat *defaultTimeTemplate = DateFormat::createTimeInstance(DateFormat::kDefault, fLocale);
DateFormat *shortTimeTemplate = DateFormat::createTimeInstance(DateFormat::kShort, fLocale);
DateFormat *longTimeTemplate = DateFormat::createTimeInstance(DateFormat::kLong, fLocale);
DateFormat *fullTimeTemplate = DateFormat::createTimeInstance(DateFormat::kFull, fLocale);
appendTo += COMMA;
if (formatAlias == *defaultDateTemplate) {
appendTo += ID_DATE;
}
else if (formatAlias == *shortDateTemplate) {
appendTo += ID_DATE;
appendTo += COMMA;
appendTo += ID_SHORT;
}
else if (formatAlias == *defaultDateTemplate) {
appendTo += ID_DATE;
appendTo += COMMA;
appendTo += ID_MEDIUM;
}
else if (formatAlias == *longDateTemplate) {
appendTo += ID_DATE;
appendTo += COMMA;
appendTo += ID_LONG;
}
else if (formatAlias == *fullDateTemplate) {
appendTo += ID_DATE;
appendTo += COMMA;
appendTo += ID_FULL;
}
else if (formatAlias == *defaultTimeTemplate) {
appendTo += ID_TIME;
}
else if (formatAlias == *shortTimeTemplate) {
appendTo += ID_TIME;
appendTo += COMMA;
appendTo += ID_SHORT;
}
else if (formatAlias == *defaultTimeTemplate) {
appendTo += ID_TIME;
appendTo += COMMA;
appendTo += ID_MEDIUM;
}
else if (formatAlias == *longTimeTemplate) {
appendTo += ID_TIME;
appendTo += COMMA;
appendTo += ID_LONG;
}
else if (formatAlias == *fullTimeTemplate) {
appendTo += ID_TIME;
appendTo += COMMA;
appendTo += ID_FULL;
}
else {
UnicodeString buffer;
appendTo += ID_DATE;
appendTo += COMMA;
appendTo += ((SimpleDateFormat*)fmt)->toPattern(buffer);
}
delete defaultDateTemplate;
delete shortDateTemplate;
delete longDateTemplate;
delete fullDateTemplate;
delete defaultTimeTemplate;
delete shortTimeTemplate;
delete longTimeTemplate;
delete fullTimeTemplate;
}
else if (fmt->getDynamicClassID() == ChoiceFormat::getStaticClassID()) {
UnicodeString buffer;
appendTo += COMMA;
appendTo += ID_CHOICE;
appendTo += COMMA;
appendTo += ((ChoiceFormat*)fmt)->toPattern(buffer);
}
else {
}
appendTo += RIGHT_CURLY_BRACE;
}
copyAndFixQuotes(fPattern, lastOffset, fPattern.length(), appendTo);
return appendTo;
}
void
MessageFormat::adoptFormats(Format** newFormats,
int32_t count) {
if (newFormats == NULL || count < 0) {
return;
}
int32_t i;
if (allocateSubformats(count)) {
for (i=0; i<subformatCount; ++i) {
delete subformats[i].format;
}
for (i=0; i<count; ++i) {
subformats[i].format = newFormats[i];
}
subformatCount = count;
} else {
for (i=0; i<count; ++i) {
delete newFormats[i];
}
}
}
void
MessageFormat::setFormats(const Format** newFormats,
int32_t count) {
if (newFormats == NULL || count < 0) {
return;
}
if (allocateSubformats(count)) {
int32_t i;
for (i=0; i<subformatCount; ++i) {
delete subformats[i].format;
}
subformatCount = 0;
for (i=0; i<count; ++i) {
subformats[i].format = newFormats[i] ? newFormats[i]->clone() : NULL;
}
subformatCount = count;
}
}
void
MessageFormat::adoptFormat(int32_t n, Format *newFormat) {
if (n < 0 || n >= subformatCount) {
delete newFormat;
} else {
delete subformats[n].format;
subformats[n].format = newFormat;
}
}
void
MessageFormat::setFormat(int32_t n, const Format& newFormat) {
if (n >= 0 && n < subformatCount) {
delete subformats[n].format;
if (&newFormat == NULL) {
subformats[n].format = NULL;
} else {
subformats[n].format = newFormat.clone();
}
}
}
const Format**
MessageFormat::getFormats(int32_t& cnt) const
{
MessageFormat* t = (MessageFormat*) this;
cnt = 0;
if (formatAliases == NULL) {
t->formatAliasesCapacity = (subformatCount<10) ? 10 : subformatCount;
Format** a = (Format**)
uprv_malloc(sizeof(Format*) * formatAliasesCapacity);
if (a == NULL) {
return NULL;
}
t->formatAliases = a;
} else if (subformatCount > formatAliasesCapacity) {
Format** a = (Format**)
uprv_realloc(formatAliases, sizeof(Format*) * subformatCount);
if (a == NULL) {
return NULL;
}
t->formatAliases = a;
t->formatAliasesCapacity = subformatCount;
}
for (int32_t i=0; i<subformatCount; ++i) {
t->formatAliases[i] = subformats[i].format;
}
cnt = subformatCount;
return (const Format**)formatAliases;
}
UnicodeString&
MessageFormat::format(const Formattable* source,
int32_t cnt,
UnicodeString& appendTo,
FieldPosition& ignore,
UErrorCode& success) const
{
if (U_FAILURE(success))
return appendTo;
return format(source, cnt, appendTo, ignore, 0, success);
}
UnicodeString&
MessageFormat::format( const UnicodeString& pattern,
const Formattable* arguments,
int32_t cnt,
UnicodeString& appendTo,
UErrorCode& success)
{
MessageFormat temp(pattern, success);
FieldPosition ignore(0);
temp.format(arguments, cnt, appendTo, ignore, success);
return appendTo;
}
UnicodeString&
MessageFormat::format(const Formattable& source,
UnicodeString& appendTo,
FieldPosition& ignore,
UErrorCode& success) const
{
int32_t cnt;
if (U_FAILURE(success))
return appendTo;
if (source.getType() != Formattable::kArray) {
success = U_ILLEGAL_ARGUMENT_ERROR;
return appendTo;
}
const Formattable* tmpPtr = source.getArray(cnt);
return format(tmpPtr, cnt, appendTo, ignore, 0, success);
}
UnicodeString&
MessageFormat::format(const Formattable* arguments,
int32_t cnt,
UnicodeString& appendTo,
FieldPosition& status,
int32_t recursionProtection,
UErrorCode& success) const
{
if (cnt < 0 || (cnt && arguments == NULL)) {
success = U_ILLEGAL_ARGUMENT_ERROR;
return appendTo;
}
int32_t lastOffset = 0;
for (int32_t i=0; i<subformatCount; ++i) {
appendTo.append(fPattern, lastOffset, subformats[i].offset - lastOffset);
lastOffset = subformats[i].offset;
int32_t argumentNumber = subformats[i].arg;
if (argumentNumber >= cnt) {
appendTo += LEFT_CURLY_BRACE;
itos(argumentNumber, appendTo);
appendTo += RIGHT_CURLY_BRACE;
continue;
}
const Formattable *obj = arguments + argumentNumber;
Formattable::Type type = obj->getType();
Format* fmt = subformats[i].format;
if (fmt != NULL) {
UnicodeString arg;
fmt->format(*obj, arg, success);
if (fmt->getDynamicClassID() == ChoiceFormat::getStaticClassID() &&
arg.indexOf(LEFT_CURLY_BRACE) >= 0) {
MessageFormat temp(arg, fLocale, success);
temp.format(arguments, cnt, appendTo, status, recursionProtection, success);
if (U_FAILURE(success)) {
return appendTo;
}
}
else {
appendTo += arg;
}
}
else if ((type == Formattable::kDouble) ||
(type == Formattable::kLong) ||
(type == Formattable::kInt64)) {
const NumberFormat* nf = getDefaultNumberFormat(success);
if (nf == NULL) {
return appendTo;
}
if (type == Formattable::kDouble) {
nf->format(obj->getDouble(), appendTo);
} else if (type == Formattable::kLong) {
nf->format(obj->getLong(), appendTo);
} else {
nf->format(obj->getInt64(), appendTo);
}
}
else if (type == Formattable::kDate) {
const DateFormat* df = getDefaultDateFormat(success);
if (df == NULL) {
return appendTo;
}
df->format(obj->getDate(), appendTo);
}
else if (type == Formattable::kString) {
appendTo += obj->getString();
}
else {
success = U_ILLEGAL_ARGUMENT_ERROR;
return appendTo;
}
}
appendTo.append(fPattern, lastOffset, 0x7fffffff);
return appendTo;
}
Formattable*
MessageFormat::parse(const UnicodeString& source,
ParsePosition& pos,
int32_t& count) const
{
Formattable *resultArray = new Formattable[argTypeCount ? argTypeCount : 1];
int32_t patternOffset = 0;
int32_t sourceOffset = pos.getIndex();
ParsePosition tempPos(0);
count = 0; int32_t len;
for (int32_t i = 0; i < subformatCount; ++i) {
len = subformats[i].offset - patternOffset;
if (len == 0 ||
fPattern.compare(patternOffset, len, source, sourceOffset, len) == 0) {
sourceOffset += len;
patternOffset += len;
}
else {
goto PARSE_ERROR;
}
Format* fmt = subformats[i].format;
int32_t arg = subformats[i].arg;
if (fmt == NULL) { int32_t tempLength = (i+1<subformatCount) ?
subformats[i+1].offset : fPattern.length();
int32_t next;
if (patternOffset >= tempLength) {
next = source.length();
}
else {
UnicodeString buffer;
fPattern.extract(patternOffset,tempLength - patternOffset, buffer);
next = source.indexOf(buffer, sourceOffset);
}
if (next < 0) {
goto PARSE_ERROR;
}
else {
UnicodeString buffer;
source.extract(sourceOffset,next - sourceOffset, buffer);
UnicodeString strValue = buffer;
UnicodeString temp(LEFT_CURLY_BRACE);
itos(arg, temp);
temp += RIGHT_CURLY_BRACE;
if (strValue != temp) {
source.extract(sourceOffset,next - sourceOffset, buffer);
resultArray[arg].setString(buffer);
if ((arg + 1) > count) {
count = arg + 1;
}
}
sourceOffset = next;
}
}
else {
tempPos.setIndex(sourceOffset);
fmt->parseObject(source, resultArray[arg], tempPos);
if (tempPos.getIndex() == sourceOffset) {
goto PARSE_ERROR;
}
if ((arg + 1) > count) {
count = arg + 1;
}
sourceOffset = tempPos.getIndex(); }
}
len = fPattern.length() - patternOffset;
if (len == 0 ||
fPattern.compare(patternOffset, len, source, sourceOffset, len) == 0) {
pos.setIndex(sourceOffset + len);
return resultArray;
}
PARSE_ERROR:
pos.setErrorIndex(sourceOffset);
delete [] resultArray;
count = 0;
return NULL; }
Formattable*
MessageFormat::parse(const UnicodeString& source,
int32_t& cnt,
UErrorCode& success) const
{
ParsePosition status(0);
Formattable* result = parse(source, status, cnt);
if (status.getIndex() == 0) {
success = U_MESSAGE_PARSE_ERROR;
delete[] result;
return NULL;
}
return result;
}
void
MessageFormat::parseObject( const UnicodeString& source,
Formattable& result,
ParsePosition& status) const
{
int32_t cnt = 0;
Formattable* tmpResult = parse(source, status, cnt);
if (tmpResult != NULL)
result.adoptArray(tmpResult, cnt);
}
UnicodeString
MessageFormat::autoQuoteApostrophe(const UnicodeString& pattern, UErrorCode& status) {
UnicodeString result;
if (U_SUCCESS(status)) {
int32_t plen = pattern.length();
const UChar* pat = pattern.getBuffer();
int32_t blen = plen * 2 + 1; UChar* buf = result.getBuffer(blen);
if (buf == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
} else {
int32_t len = umsg_autoQuoteApostrophe(pat, plen, buf, blen, &status);
result.releaseBuffer(U_SUCCESS(status) ? len : 0);
}
}
if (U_FAILURE(status)) {
result.setToBogus();
}
return result;
}
static Format* makeRBNF(URBNFRuleSetTag tag, const Locale& locale, const UnicodeString& defaultRuleSet, UErrorCode& ec) {
RuleBasedNumberFormat* fmt = new RuleBasedNumberFormat(tag, locale, ec);
if (U_SUCCESS(ec) && defaultRuleSet.length() > 0) {
fmt->setDefaultRuleSet(defaultRuleSet, ec);
if (U_FAILURE(ec)) { ec = U_ZERO_ERROR;
}
}
return fmt;
}
void
MessageFormat::makeFormat(int32_t formatNumber,
UnicodeString* segments,
UParseError& parseError,
UErrorCode& ec) {
if (U_FAILURE(ec)) {
return;
}
int32_t argumentNumber = stou(segments[1]); if (argumentNumber < 0) {
ec = U_INVALID_FORMAT_ERROR;
return;
}
Formattable::Type argType;
Format *fmt = NULL;
int32_t typeID, styleID;
DateFormat::EStyle style;
switch (typeID = findKeyword(segments[2], TYPE_IDS)) {
case 0: argType = Formattable::kString;
break;
case 1: argType = Formattable::kDouble;
switch (findKeyword(segments[3], NUMBER_STYLE_IDS)) {
case 0: fmt = NumberFormat::createInstance(fLocale, ec);
break;
case 1: fmt = NumberFormat::createCurrencyInstance(fLocale, ec);
break;
case 2: fmt = NumberFormat::createPercentInstance(fLocale, ec);
break;
case 3: argType = Formattable::kLong;
fmt = createIntegerFormat(fLocale, ec);
break;
default: fmt = NumberFormat::createInstance(fLocale, ec);
if (fmt &&
fmt->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
((DecimalFormat*)fmt)->applyPattern(segments[3],parseError,ec);
}
break;
}
break;
case 2: case 3: argType = Formattable::kDate;
styleID = findKeyword(segments[3], DATE_STYLE_IDS);
style = (styleID >= 0) ? DATE_STYLES[styleID] : DateFormat::kDefault;
if (typeID == 2) {
fmt = DateFormat::createDateInstance(style, fLocale);
} else {
fmt = DateFormat::createTimeInstance(style, fLocale);
}
if (styleID < 0 &&
fmt != NULL &&
fmt->getDynamicClassID() == SimpleDateFormat::getStaticClassID()) {
((SimpleDateFormat*)fmt)->applyPattern(segments[3]);
}
break;
case 4: argType = Formattable::kDouble;
fmt = new ChoiceFormat(segments[3], parseError, ec);
break;
case 5: argType = Formattable::kDouble;
fmt = makeRBNF(URBNF_SPELLOUT, fLocale, segments[3], ec);
break;
case 6: argType = Formattable::kDouble;
fmt = makeRBNF(URBNF_ORDINAL, fLocale, segments[3], ec);
break;
case 7: argType = Formattable::kDouble;
fmt = makeRBNF(URBNF_DURATION, fLocale, segments[3], ec);
break;
default:
argType = Formattable::kString;
ec = U_ILLEGAL_ARGUMENT_ERROR;
break;
}
if (fmt==NULL && argType!=Formattable::kString && U_SUCCESS(ec)) {
ec = U_MEMORY_ALLOCATION_ERROR;
}
if (!allocateSubformats(formatNumber+1) ||
!allocateArgTypes(argumentNumber+1)) {
ec = U_MEMORY_ALLOCATION_ERROR;
}
if (U_FAILURE(ec)) {
delete fmt;
return;
}
subformats[formatNumber].format = fmt;
subformats[formatNumber].offset = segments[0].length();
subformats[formatNumber].arg = argumentNumber;
subformatCount = formatNumber+1;
argTypes[argumentNumber] = argType;
if (argumentNumber+1 > argTypeCount) {
argTypeCount = argumentNumber+1;
}
}
int32_t MessageFormat::findKeyword(const UnicodeString& s,
const UChar * const *list)
{
if (s.length() == 0)
return 0;
UnicodeString buffer = s;
buffer.trim().toLower("");
for (int32_t i = 0; list[i]; ++i) {
if (!buffer.compare(list[i], u_strlen(list[i]))) {
return i;
}
}
return -1;
}
void
MessageFormat::copyAndFixQuotes(const UnicodeString& source,
int32_t start,
int32_t end,
UnicodeString& appendTo)
{
UBool gotLB = FALSE;
for (int32_t i = start; i < end; ++i) {
UChar ch = source[i];
if (ch == LEFT_CURLY_BRACE) {
appendTo += SINGLE_QUOTE;
appendTo += LEFT_CURLY_BRACE;
appendTo += SINGLE_QUOTE;
gotLB = TRUE;
}
else if (ch == RIGHT_CURLY_BRACE) {
if(gotLB) {
appendTo += RIGHT_CURLY_BRACE;
gotLB = FALSE;
}
else {
appendTo += SINGLE_QUOTE;
appendTo += RIGHT_CURLY_BRACE;
appendTo += SINGLE_QUOTE;
}
}
else if (ch == SINGLE_QUOTE) {
appendTo += SINGLE_QUOTE;
appendTo += SINGLE_QUOTE;
}
else {
appendTo += ch;
}
}
}
NumberFormat*
MessageFormat::createIntegerFormat(const Locale& locale, UErrorCode& status) const {
NumberFormat *temp = NumberFormat::createInstance(locale, status);
if (temp != NULL && temp->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
DecimalFormat *temp2 = (DecimalFormat*) temp;
temp2->setMaximumFractionDigits(0);
temp2->setDecimalSeparatorAlwaysShown(FALSE);
temp2->setParseIntegerOnly(TRUE);
}
return temp;
}
const NumberFormat* MessageFormat::getDefaultNumberFormat(UErrorCode& ec) const {
if (defaultNumberFormat == NULL) {
MessageFormat* t = (MessageFormat*) this;
t->defaultNumberFormat = NumberFormat::createInstance(fLocale, ec);
if (U_FAILURE(ec)) {
delete t->defaultNumberFormat;
t->defaultNumberFormat = NULL;
} else if (t->defaultNumberFormat == NULL) {
ec = U_MEMORY_ALLOCATION_ERROR;
}
}
return defaultNumberFormat;
}
const DateFormat* MessageFormat::getDefaultDateFormat(UErrorCode& ec) const {
if (defaultDateFormat == NULL) {
MessageFormat* t = (MessageFormat*) this;
t->defaultDateFormat = DateFormat::createDateTimeInstance(DateFormat::kShort, DateFormat::kShort, fLocale);
if (t->defaultDateFormat == NULL) {
ec = U_MEMORY_ALLOCATION_ERROR;
}
}
return defaultDateFormat;
}
U_NAMESPACE_END
#endif