1/*
2*******************************************************************************
3* Copyright (C) 1997-2012, International Business Machines Corporation and    *
4* others. All Rights Reserved.                                                *
5*******************************************************************************
6*
7* File COMPACTDECIMALFORMAT.CPP
8*
9********************************************************************************
10*/
11#include "unicode/utypes.h"
12
13#if !UCONFIG_NO_FORMATTING
14
15#include "charstr.h"
16#include "cstring.h"
17#include "digitlst.h"
18#include "mutex.h"
19#include "unicode/compactdecimalformat.h"
20#include "unicode/numsys.h"
21#include "unicode/plurrule.h"
22#include "unicode/ures.h"
23#include "ucln_in.h"
24#include "uhash.h"
25#include "umutex.h"
26#include "unicode/ures.h"
27#include "uresimp.h"
28
29#define LENGTHOF(array) (int32_t)(sizeof(array) / sizeof((array)[0]))
30
31// Maps locale name to CDFLocaleData struct.
32static UHashtable* gCompactDecimalData = NULL;
33static UMutex gCompactDecimalMetaLock = U_MUTEX_INITIALIZER;
34
35U_NAMESPACE_BEGIN
36
37static const int32_t MAX_DIGITS = 15;
38static const char gOther[] = "other";
39static const char gLatnTag[] = "latn";
40static const char gNumberElementsTag[] = "NumberElements";
41static const char gDecimalFormatTag[] = "decimalFormat";
42static const char gPatternsShort[] = "patternsShort";
43static const char gPatternsLong[] = "patternsLong";
44static const char gRoot[] = "root";
45
46static const UChar u_0 = 0x30;
47static const UChar u_apos = 0x27;
48
49static const UChar kZero[] = {u_0};
50
51// Used to unescape single quotes.
52enum QuoteState {
53  OUTSIDE,
54  INSIDE_EMPTY,
55  INSIDE_FULL
56};
57
58enum FallbackFlags {
59  ANY = 0,
60  MUST = 1,
61  NOT_ROOT = 2
62  // Next one will be 4 then 6 etc.
63};
64
65
66// CDFUnit represents a prefix-suffix pair for a particular variant
67// and log10 value.
68struct CDFUnit : public UMemory {
69  UnicodeString prefix;
70  UnicodeString suffix;
71  inline CDFUnit() : prefix(), suffix() {
72    prefix.setToBogus();
73  }
74  inline ~CDFUnit() {}
75  inline UBool isSet() const {
76    return !prefix.isBogus();
77  }
78  inline void markAsSet() {
79    prefix.remove();
80  }
81};
82
83// CDFLocaleStyleData contains formatting data for a particular locale
84// and style.
85class CDFLocaleStyleData : public UMemory {
86 public:
87  // What to divide by for each log10 value when formatting. These values
88  // will be powers of 10. For English, would be:
89  // 1, 1, 1, 1000, 1000, 1000, 1000000, 1000000, 1000000, 1000000000 ...
90  double divisors[MAX_DIGITS];
91  // Maps plural variants to CDFUnit[MAX_DIGITS] arrays.
92  // To format a number x,
93  // first compute log10(x). Compute displayNum = (x / divisors[log10(x)]).
94  // Compute the plural variant for displayNum
95  // (e.g zero, one, two, few, many, other).
96  // Compute cdfUnits = unitsByVariant[pluralVariant].
97  // Prefix and suffix to use at cdfUnits[log10(x)]
98  UHashtable* unitsByVariant;
99  inline CDFLocaleStyleData() : unitsByVariant(NULL) {}
100  ~CDFLocaleStyleData();
101  // Init initializes this object.
102  void Init(UErrorCode& status);
103  inline UBool isBogus() const {
104    return unitsByVariant == NULL;
105  }
106  void setToBogus();
107 private:
108  CDFLocaleStyleData(const CDFLocaleStyleData&);
109  CDFLocaleStyleData& operator=(const CDFLocaleStyleData&);
110};
111
112// CDFLocaleData contains formatting data for a particular locale.
113struct CDFLocaleData : public UMemory {
114  CDFLocaleStyleData shortData;
115  CDFLocaleStyleData longData;
116  inline CDFLocaleData() : shortData(), longData() { }
117  inline ~CDFLocaleData() { }
118  // Init initializes this object.
119  void Init(UErrorCode& status);
120};
121
122U_NAMESPACE_END
123
124U_CDECL_BEGIN
125
126static UBool U_CALLCONV cdf_cleanup(void) {
127  if (gCompactDecimalData != NULL) {
128    uhash_close(gCompactDecimalData);
129    gCompactDecimalData = NULL;
130  }
131  return TRUE;
132}
133
134static void U_CALLCONV deleteCDFUnits(void* ptr) {
135  delete [] (icu::CDFUnit*) ptr;
136}
137
138static void U_CALLCONV deleteCDFLocaleData(void* ptr) {
139  delete (icu::CDFLocaleData*) ptr;
140}
141
142U_CDECL_END
143
144U_NAMESPACE_BEGIN
145
146static UBool divisors_equal(const double* lhs, const double* rhs);
147static const CDFLocaleStyleData* getCDFLocaleStyleData(const Locale& inLocale, UNumberCompactStyle style, UErrorCode& status);
148
149static const CDFLocaleStyleData* extractDataByStyleEnum(const CDFLocaleData& data, UNumberCompactStyle style, UErrorCode& status);
150static CDFLocaleData* loadCDFLocaleData(const Locale& inLocale, UErrorCode& status);
151static void initCDFLocaleData(const Locale& inLocale, CDFLocaleData* result, UErrorCode& status);
152static UResourceBundle* tryGetDecimalFallback(const UResourceBundle* numberSystemResource, const char* style, UResourceBundle** fillIn, FallbackFlags flags, UErrorCode& status);
153static UResourceBundle* tryGetByKeyWithFallback(const UResourceBundle* rb, const char* path, UResourceBundle** fillIn, FallbackFlags flags, UErrorCode& status);
154static UBool isRoot(const UResourceBundle* rb, UErrorCode& status);
155static void initCDFLocaleStyleData(const UResourceBundle* decimalFormatBundle, CDFLocaleStyleData* result, UErrorCode& status);
156static void populatePower10(const UResourceBundle* power10Bundle, CDFLocaleStyleData* result, UErrorCode& status);
157static int32_t populatePrefixSuffix(const char* variant, int32_t log10Value, const UnicodeString& formatStr, UHashtable* result, UErrorCode& status);
158static UBool onlySpaces(UnicodeString u);
159static void fixQuotes(UnicodeString& s);
160static void fillInMissing(CDFLocaleStyleData* result);
161static int32_t computeLog10(double x, UBool inRange);
162static CDFUnit* createCDFUnit(const char* variant, int32_t log10Value, UHashtable* table, UErrorCode& status);
163static const CDFUnit* getCDFUnitFallback(const UHashtable* table, const UnicodeString& variant, int32_t log10Value);
164
165UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CompactDecimalFormat)
166
167CompactDecimalFormat::CompactDecimalFormat(
168    const DecimalFormat& decimalFormat,
169    const UHashtable* unitsByVariant,
170    const double* divisors,
171    PluralRules* pluralRules)
172  : DecimalFormat(decimalFormat), _unitsByVariant(unitsByVariant), _divisors(divisors), _pluralRules(pluralRules) {
173}
174
175CompactDecimalFormat::CompactDecimalFormat(const CompactDecimalFormat& source)
176    : DecimalFormat(source), _unitsByVariant(source._unitsByVariant), _divisors(source._divisors), _pluralRules(source._pluralRules->clone()) {
177}
178
179CompactDecimalFormat* U_EXPORT2
180CompactDecimalFormat::createInstance(
181    const Locale& inLocale, UNumberCompactStyle style, UErrorCode& status) {
182  LocalPointer<DecimalFormat> decfmt((DecimalFormat*) NumberFormat::makeInstance(inLocale, UNUM_DECIMAL, TRUE, status));
183  if (U_FAILURE(status)) {
184    return NULL;
185  }
186  LocalPointer<PluralRules> pluralRules(PluralRules::forLocale(inLocale, status));
187  if (U_FAILURE(status)) {
188    return NULL;
189  }
190  const CDFLocaleStyleData* data = getCDFLocaleStyleData(inLocale, style, status);
191  if (U_FAILURE(status)) {
192    return NULL;
193  }
194  CompactDecimalFormat* result =
195      new CompactDecimalFormat(*decfmt, data->unitsByVariant, data->divisors, pluralRules.getAlias());
196  if (result == NULL) {
197    status = U_MEMORY_ALLOCATION_ERROR;
198    return NULL;
199  }
200  pluralRules.orphan();
201  result->setMaximumSignificantDigits(3);
202  result->setSignificantDigitsUsed(TRUE);
203  result->setGroupingUsed(FALSE);
204  return result;
205}
206
207CompactDecimalFormat&
208CompactDecimalFormat::operator=(const CompactDecimalFormat& rhs) {
209  if (this != &rhs) {
210    DecimalFormat::operator=(rhs);
211    _unitsByVariant = rhs._unitsByVariant;
212    _divisors = rhs._divisors;
213    delete _pluralRules;
214    _pluralRules = rhs._pluralRules->clone();
215  }
216  return *this;
217}
218
219CompactDecimalFormat::~CompactDecimalFormat() {
220  delete _pluralRules;
221}
222
223
224Format*
225CompactDecimalFormat::clone(void) const {
226  return new CompactDecimalFormat(*this);
227}
228
229UBool
230CompactDecimalFormat::operator==(const Format& that) const {
231  if (this == &that) {
232    return TRUE;
233  }
234  return (DecimalFormat::operator==(that) && eqHelper((const CompactDecimalFormat&) that));
235}
236
237UBool
238CompactDecimalFormat::eqHelper(const CompactDecimalFormat& that) const {
239  return uhash_equals(_unitsByVariant, that._unitsByVariant) && divisors_equal(_divisors, that._divisors) && (*_pluralRules == *that._pluralRules);
240}
241
242UnicodeString&
243CompactDecimalFormat::format(
244    double number,
245    UnicodeString& appendTo,
246    FieldPosition& pos) const {
247  DigitList orig, rounded;
248  orig.set(number);
249  UBool isNegative;
250  UErrorCode status = U_ZERO_ERROR;
251  _round(orig, rounded, isNegative, status);
252  if (U_FAILURE(status)) {
253    return appendTo;
254  }
255  double roundedDouble = rounded.getDouble();
256  if (isNegative) {
257    roundedDouble = -roundedDouble;
258  }
259  int32_t baseIdx = computeLog10(roundedDouble, TRUE);
260  double numberToFormat = roundedDouble / _divisors[baseIdx];
261  UnicodeString variant = _pluralRules->select(numberToFormat);
262  if (isNegative) {
263    numberToFormat = -numberToFormat;
264  }
265  const CDFUnit* unit = getCDFUnitFallback(_unitsByVariant, variant, baseIdx);
266  appendTo += unit->prefix;
267  DecimalFormat::format(numberToFormat, appendTo, pos);
268  appendTo += unit->suffix;
269  return appendTo;
270}
271
272UnicodeString&
273CompactDecimalFormat::format(
274    double /* number */,
275    UnicodeString& appendTo,
276    FieldPositionIterator* /* posIter */,
277    UErrorCode& status) const {
278  status = U_UNSUPPORTED_ERROR;
279  return appendTo;
280}
281
282UnicodeString&
283CompactDecimalFormat::format(
284    int64_t number,
285    UnicodeString& appendTo,
286    FieldPosition& pos) const {
287  return format((double) number, appendTo, pos);
288}
289
290UnicodeString&
291CompactDecimalFormat::format(
292    int64_t /* number */,
293    UnicodeString& appendTo,
294    FieldPositionIterator* /* posIter */,
295    UErrorCode& status) const {
296  status = U_UNSUPPORTED_ERROR;
297  return appendTo;
298}
299
300UnicodeString&
301CompactDecimalFormat::format(
302    const StringPiece& /* number */,
303    UnicodeString& appendTo,
304    FieldPositionIterator* /* posIter */,
305    UErrorCode& status) const {
306  status = U_UNSUPPORTED_ERROR;
307  return appendTo;
308}
309
310UnicodeString&
311CompactDecimalFormat::format(
312    const DigitList& /* number */,
313    UnicodeString& appendTo,
314    FieldPositionIterator* /* posIter */,
315    UErrorCode& status) const {
316  status = U_UNSUPPORTED_ERROR;
317  return appendTo;
318}
319
320UnicodeString&
321CompactDecimalFormat::format(const DigitList& /* number */,
322                             UnicodeString& appendTo,
323                             FieldPosition& /* pos */,
324                             UErrorCode& status) const {
325  status = U_UNSUPPORTED_ERROR;
326  return appendTo;
327}
328
329void
330CompactDecimalFormat::parse(
331    const UnicodeString& /* text */,
332    Formattable& /* result */,
333    ParsePosition& /* parsePosition */) const {
334}
335
336void
337CompactDecimalFormat::parse(
338    const UnicodeString& /* text */,
339    Formattable& /* result */,
340    UErrorCode& status) const {
341  status = U_UNSUPPORTED_ERROR;
342}
343
344CurrencyAmount*
345CompactDecimalFormat::parseCurrency(
346    const UnicodeString& /* text */,
347    ParsePosition& /* pos */) const {
348  return NULL;
349}
350
351void CDFLocaleStyleData::Init(UErrorCode& status) {
352  if (unitsByVariant != NULL) {
353    return;
354  }
355  unitsByVariant = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
356  if (U_FAILURE(status)) {
357    return;
358  }
359  uhash_setKeyDeleter(unitsByVariant, uprv_free);
360  uhash_setValueDeleter(unitsByVariant, deleteCDFUnits);
361}
362
363CDFLocaleStyleData::~CDFLocaleStyleData() {
364  setToBogus();
365}
366
367void CDFLocaleStyleData::setToBogus() {
368  if (unitsByVariant != NULL) {
369    uhash_close(unitsByVariant);
370    unitsByVariant = NULL;
371  }
372}
373
374void CDFLocaleData::Init(UErrorCode& status) {
375  shortData.Init(status);
376  if (U_FAILURE(status)) {
377    return;
378  }
379  longData.Init(status);
380}
381
382// Helper method for operator=
383static UBool divisors_equal(const double* lhs, const double* rhs) {
384  for (int32_t i = 0; i < MAX_DIGITS; ++i) {
385    if (lhs[i] != rhs[i]) {
386      return FALSE;
387    }
388  }
389  return TRUE;
390}
391
392// getCDFLocaleStyleData returns pointer to formatting data for given locale and
393// style within the global cache. On cache miss, getCDFLocaleStyleData loads
394// the data from CLDR into the global cache before returning the pointer. If a
395// UNUM_LONG data is requested for a locale, and that locale does not have
396// UNUM_LONG data, getCDFLocaleStyleData will fall back to UNUM_SHORT data for
397// that locale.
398static const CDFLocaleStyleData* getCDFLocaleStyleData(const Locale& inLocale, UNumberCompactStyle style, UErrorCode& status) {
399  if (U_FAILURE(status)) {
400    return NULL;
401  }
402  CDFLocaleData* result = NULL;
403  const char* key = inLocale.getName();
404  {
405    Mutex lock(&gCompactDecimalMetaLock);
406    if (gCompactDecimalData == NULL) {
407      gCompactDecimalData = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
408      if (U_FAILURE(status)) {
409        return NULL;
410      }
411      uhash_setKeyDeleter(gCompactDecimalData, uprv_free);
412      uhash_setValueDeleter(gCompactDecimalData, deleteCDFLocaleData);
413      ucln_i18n_registerCleanup(UCLN_I18N_CDFINFO, cdf_cleanup);
414    } else {
415      result = (CDFLocaleData*) uhash_get(gCompactDecimalData, key);
416    }
417  }
418  if (result != NULL) {
419    return extractDataByStyleEnum(*result, style, status);
420  }
421
422  result = loadCDFLocaleData(inLocale, status);
423  if (U_FAILURE(status)) {
424    return NULL;
425  }
426
427  {
428    Mutex lock(&gCompactDecimalMetaLock);
429    CDFLocaleData* temp = (CDFLocaleData*) uhash_get(gCompactDecimalData, key);
430    if (temp != NULL) {
431      delete result;
432      result = temp;
433    } else {
434      uhash_put(gCompactDecimalData, uprv_strdup(key), (void*) result, &status);
435      if (U_FAILURE(status)) {
436        return NULL;
437      }
438    }
439  }
440  return extractDataByStyleEnum(*result, style, status);
441}
442
443static const CDFLocaleStyleData* extractDataByStyleEnum(const CDFLocaleData& data, UNumberCompactStyle style, UErrorCode& status) {
444  switch (style) {
445    case UNUM_SHORT:
446      return &data.shortData;
447    case UNUM_LONG:
448      if (!data.longData.isBogus()) {
449        return &data.longData;
450      }
451      return &data.shortData;
452    default:
453      status = U_ILLEGAL_ARGUMENT_ERROR;
454      return NULL;
455  }
456}
457
458// loadCDFLocaleData loads formatting data from CLDR for a given locale. The
459// caller owns the returned pointer.
460static CDFLocaleData* loadCDFLocaleData(const Locale& inLocale, UErrorCode& status) {
461  if (U_FAILURE(status)) {
462    return NULL;
463  }
464  CDFLocaleData* result = new CDFLocaleData;
465  if (result == NULL) {
466    status = U_MEMORY_ALLOCATION_ERROR;
467    return NULL;
468  }
469  result->Init(status);
470  if (U_FAILURE(status)) {
471    delete result;
472    return NULL;
473  }
474
475  initCDFLocaleData(inLocale, result, status);
476  if (U_FAILURE(status)) {
477    delete result;
478    return NULL;
479  }
480  return result;
481}
482
483// initCDFLocaleData initializes result with data from CLDR.
484// inLocale is the locale, the CLDR data is stored in result.
485// We load the UNUM_SHORT  and UNUM_LONG data looking first in local numbering
486// system and not including root locale in fallback. Next we try in the latn
487// numbering system where we fallback all the way to root. If we don't find
488// UNUM_SHORT data in these three places, we report an error. If we find
489// UNUM_SHORT data before finding UNUM_LONG data we make UNUM_LONG data fall
490// back to UNUM_SHORT data.
491static void initCDFLocaleData(const Locale& inLocale, CDFLocaleData* result, UErrorCode& status) {
492  LocalPointer<NumberingSystem> ns(NumberingSystem::createInstance(inLocale, status));
493  if (U_FAILURE(status)) {
494    return;
495  }
496  const char* numberingSystemName = ns->getName();
497  UResourceBundle* rb = ures_open(NULL, inLocale.getName(), &status);
498  rb = ures_getByKeyWithFallback(rb, gNumberElementsTag, rb, &status);
499  if (U_FAILURE(status)) {
500    ures_close(rb);
501    return;
502  }
503  UResourceBundle* shortDataFillIn = NULL;
504  UResourceBundle* longDataFillIn = NULL;
505  UResourceBundle* shortData = NULL;
506  UResourceBundle* longData = NULL;
507
508  if (uprv_strcmp(numberingSystemName, gLatnTag) != 0) {
509    LocalUResourceBundlePointer localResource(
510        tryGetByKeyWithFallback(rb, numberingSystemName, NULL, NOT_ROOT, status));
511    shortData = tryGetDecimalFallback(
512        localResource.getAlias(), gPatternsShort, &shortDataFillIn, NOT_ROOT, status);
513    longData = tryGetDecimalFallback(
514        localResource.getAlias(), gPatternsLong, &longDataFillIn, NOT_ROOT, status);
515  }
516  if (U_FAILURE(status)) {
517    ures_close(shortDataFillIn);
518    ures_close(longDataFillIn);
519    ures_close(rb);
520    return;
521  }
522
523  // If we haven't found UNUM_SHORT look in latn numbering system. We must
524  // succeed at finding UNUM_SHORT here.
525  if (shortData == NULL) {
526    LocalUResourceBundlePointer latnResource(tryGetByKeyWithFallback(rb, gLatnTag, NULL, MUST, status));
527    shortData = tryGetDecimalFallback(latnResource.getAlias(), gPatternsShort, &shortDataFillIn, MUST, status);
528    if (longData == NULL) {
529      longData = tryGetDecimalFallback(latnResource.getAlias(), gPatternsLong, &longDataFillIn, ANY, status);
530      if (longData != NULL && isRoot(longData, status) && !isRoot(shortData, status)) {
531        longData = NULL;
532      }
533    }
534  }
535  initCDFLocaleStyleData(shortData, &result->shortData, status);
536  ures_close(shortDataFillIn);
537  if (U_FAILURE(status)) {
538    ures_close(longDataFillIn);
539    ures_close(rb);
540  }
541
542  if (longData == NULL) {
543    result->longData.setToBogus();
544  } else {
545    initCDFLocaleStyleData(longData, &result->longData, status);
546  }
547  ures_close(longDataFillIn);
548  ures_close(rb);
549}
550
551/**
552 * tryGetDecimalFallback attempts to fetch the "decimalFormat" resource bundle
553 * with a particular style. style is either "patternsShort" or "patternsLong."
554 * FillIn, flags, and status work in the same way as in tryGetByKeyWithFallback.
555 */
556static UResourceBundle* tryGetDecimalFallback(const UResourceBundle* numberSystemResource, const char* style, UResourceBundle** fillIn, FallbackFlags flags, UErrorCode& status) {
557  UResourceBundle* first = tryGetByKeyWithFallback(numberSystemResource, style, fillIn, flags, status);
558  UResourceBundle* second = tryGetByKeyWithFallback(first, gDecimalFormatTag, fillIn, flags, status);
559  if (fillIn == NULL) {
560    ures_close(first);
561  }
562  return second;
563}
564
565// tryGetByKeyWithFallback returns a sub-resource bundle that matches given
566// criteria or NULL if none found. rb is the resource bundle that we are
567// searching. If rb == NULL then this function behaves as if no sub-resource
568// is found; path is the key of the sub-resource,
569// (i.e "foo" but not "foo/bar"); If fillIn is NULL, caller must always call
570// ures_close() on returned resource. See below for example when fillIn is
571// not NULL. flags is ANY or NOT_ROOT. Optionally, these values
572// can be ored with MUST. MUST by itself is the same as ANY | MUST.
573// The locale of the returned sub-resource will either match the
574// flags or the returned sub-resouce will be NULL. If MUST is included in
575// flags, and not suitable sub-resource is found then in addition to returning
576// NULL, this function also sets status to U_MISSING_RESOURCE_ERROR. If MUST
577// is not included in flags, then this function just returns NULL if no
578// such sub-resource is found and will never set status to
579// U_MISSING_RESOURCE_ERROR.
580//
581// Example: This code first searches for "foo/bar" sub-resource without falling
582// back to ROOT. Then searches for "baz" sub-resource as last resort.
583//
584// UResourcebundle* fillIn = NULL;
585// UResourceBundle* data = tryGetByKeyWithFallback(rb, "foo", &fillIn, NON_ROOT, status);
586// data = tryGetByKeyWithFallback(data, "bar", &fillIn, NON_ROOT, status);
587// if (!data) {
588//   data = tryGetbyKeyWithFallback(rb, "baz", &fillIn, MUST,  status);
589// }
590// if (U_FAILURE(status)) {
591//   ures_close(fillIn);
592//   return;
593// }
594// doStuffWithNonNullSubresource(data);
595//
596// /* Wrong! don't do the following as it can leak memory if fillIn gets set
597// to NULL. */
598// fillIn = tryGetByKeyWithFallback(rb, "wrong", &fillIn, ANY, status);
599//
600// ures_close(fillIn);
601//
602static UResourceBundle* tryGetByKeyWithFallback(const UResourceBundle* rb, const char* path, UResourceBundle** fillIn, FallbackFlags flags, UErrorCode& status) {
603  if (U_FAILURE(status)) {
604    return NULL;
605  }
606  UBool must = (flags & MUST);
607  if (rb == NULL) {
608    if (must) {
609      status = U_MISSING_RESOURCE_ERROR;
610    }
611    return NULL;
612  }
613  UResourceBundle* result = NULL;
614  UResourceBundle* ownedByUs = NULL;
615  if (fillIn == NULL) {
616    ownedByUs = ures_getByKeyWithFallback(rb, path, NULL, &status);
617    result = ownedByUs;
618  } else {
619    *fillIn = ures_getByKeyWithFallback(rb, path, *fillIn, &status);
620    result = *fillIn;
621  }
622  if (U_FAILURE(status)) {
623    ures_close(ownedByUs);
624    if (status == U_MISSING_RESOURCE_ERROR && !must) {
625      status = U_ZERO_ERROR;
626    }
627    return NULL;
628  }
629  flags = (FallbackFlags) (flags & ~MUST);
630  switch (flags) {
631    case NOT_ROOT:
632      {
633        UBool bRoot = isRoot(result, status);
634        if (bRoot || U_FAILURE(status)) {
635          ures_close(ownedByUs);
636          if (must && (status == U_ZERO_ERROR)) {
637            status = U_MISSING_RESOURCE_ERROR;
638          }
639          return NULL;
640        }
641        return result;
642      }
643    case ANY:
644      return result;
645    default:
646      ures_close(ownedByUs);
647      status = U_ILLEGAL_ARGUMENT_ERROR;
648      return NULL;
649  }
650}
651
652static UBool isRoot(const UResourceBundle* rb, UErrorCode& status) {
653  const char* actualLocale = ures_getLocaleByType(
654      rb, ULOC_ACTUAL_LOCALE, &status);
655  if (U_FAILURE(status)) {
656    return FALSE;
657  }
658  return uprv_strcmp(actualLocale, gRoot) == 0;
659}
660
661
662// initCDFLocaleStyleData loads formatting data for a particular style.
663// decimalFormatBundle is the "decimalFormat" resource bundle in CLDR.
664// Loaded data stored in result.
665static void initCDFLocaleStyleData(const UResourceBundle* decimalFormatBundle, CDFLocaleStyleData* result, UErrorCode& status) {
666  if (U_FAILURE(status)) {
667    return;
668  }
669  // Iterate through all the powers of 10.
670  int32_t size = ures_getSize(decimalFormatBundle);
671  UResourceBundle* power10 = NULL;
672  for (int32_t i = 0; i < size; ++i) {
673    power10 = ures_getByIndex(decimalFormatBundle, i, power10, &status);
674    if (U_FAILURE(status)) {
675      ures_close(power10);
676      return;
677    }
678    populatePower10(power10, result, status);
679    if (U_FAILURE(status)) {
680      ures_close(power10);
681      return;
682    }
683  }
684  ures_close(power10);
685  fillInMissing(result);
686}
687
688// populatePower10 grabs data for a particular power of 10 from CLDR.
689// The loaded data is stored in result.
690static void populatePower10(const UResourceBundle* power10Bundle, CDFLocaleStyleData* result, UErrorCode& status) {
691  if (U_FAILURE(status)) {
692    return;
693  }
694  char* endPtr = NULL;
695  double power10 = uprv_strtod(ures_getKey(power10Bundle), &endPtr);
696  if (*endPtr != 0) {
697    status = U_INTERNAL_PROGRAM_ERROR;
698    return;
699  }
700  int32_t log10Value = computeLog10(power10, FALSE);
701  // Silently ignore divisors that are too big.
702  if (log10Value == MAX_DIGITS) {
703    return;
704  }
705  int32_t size = ures_getSize(power10Bundle);
706  int32_t numZeros = 0;
707  UBool otherVariantDefined = FALSE;
708  UResourceBundle* variantBundle = NULL;
709  // Iterate over all the plural variants for the power of 10
710  for (int32_t i = 0; i < size; ++i) {
711    variantBundle = ures_getByIndex(power10Bundle, i, variantBundle, &status);
712    if (U_FAILURE(status)) {
713      ures_close(variantBundle);
714      return;
715    }
716    const char* variant = ures_getKey(variantBundle);
717    int32_t resLen;
718    const UChar* formatStrP = ures_getString(variantBundle, &resLen, &status);
719    if (U_FAILURE(status)) {
720      ures_close(variantBundle);
721      return;
722    }
723    UnicodeString formatStr(false, formatStrP, resLen);
724    if (uprv_strcmp(variant, gOther) == 0) {
725      otherVariantDefined = TRUE;
726    }
727    int32_t nz = populatePrefixSuffix(
728        variant, log10Value, formatStr, result->unitsByVariant, status);
729    if (U_FAILURE(status)) {
730      ures_close(variantBundle);
731      return;
732    }
733    if (nz != numZeros) {
734      // We expect all format strings to have the same number of 0's
735      // left of the decimal point.
736      if (numZeros != 0) {
737        status = U_INTERNAL_PROGRAM_ERROR;
738        ures_close(variantBundle);
739        return;
740      }
741      numZeros = nz;
742    }
743  }
744  ures_close(variantBundle);
745  // We expect to find an OTHER variant for each power of 10.
746  if (!otherVariantDefined) {
747    status = U_INTERNAL_PROGRAM_ERROR;
748    return;
749  }
750  double divisor = power10;
751  for (int32_t i = 1; i < numZeros; ++i) {
752    divisor /= 10.0;
753  }
754  result->divisors[log10Value] = divisor;
755}
756
757// populatePrefixSuffix Adds a specific prefix-suffix pair to result for a
758// given variant and log10 value.
759// variant is 'zero', 'one', 'two', 'few', 'many', or 'other'.
760// formatStr is the format string from which the prefix and suffix are
761// extracted. It is usually of form 'Pefix 000 suffix'.
762// populatePrefixSuffix returns the number of 0's found in formatStr
763// before the decimal point.
764// In the special case that formatStr contains only spaces for prefix
765// and suffix, populatePrefixSuffix returns log10Value + 1.
766static int32_t populatePrefixSuffix(
767    const char* variant, int32_t log10Value, const UnicodeString& formatStr, UHashtable* result, UErrorCode& status) {
768  if (U_FAILURE(status)) {
769    return 0;
770  }
771  int32_t firstIdx = formatStr.indexOf(kZero, LENGTHOF(kZero), 0);
772  // We must have 0's in format string.
773  if (firstIdx == -1) {
774    status = U_INTERNAL_PROGRAM_ERROR;
775    return 0;
776  }
777  int32_t lastIdx = formatStr.lastIndexOf(kZero, LENGTHOF(kZero), firstIdx);
778  CDFUnit* unit = createCDFUnit(variant, log10Value, result, status);
779  if (U_FAILURE(status)) {
780    return 0;
781  }
782  // Everything up to first 0 is the prefix
783  unit->prefix = formatStr.tempSubString(0, firstIdx);
784  fixQuotes(unit->prefix);
785  // Everything beyond the last 0 is the suffix
786  unit->suffix = formatStr.tempSubString(lastIdx + 1);
787  fixQuotes(unit->suffix);
788
789  // If there is effectively no prefix or suffix, ignore the actual number of
790  // 0's and act as if the number of 0's matches the size of the number.
791  if (onlySpaces(unit->prefix) && onlySpaces(unit->suffix)) {
792    return log10Value + 1;
793  }
794
795  // Calculate number of zeros before decimal point
796  int32_t idx = firstIdx + 1;
797  while (idx <= lastIdx && formatStr.charAt(idx) == u_0) {
798    ++idx;
799  }
800  return (idx - firstIdx);
801}
802
803static UBool onlySpaces(UnicodeString u) {
804  return u.trim().length() == 0;
805}
806
807// fixQuotes unescapes single quotes. Don''t -> Don't. Letter 'j' -> Letter j.
808// Modifies s in place.
809static void fixQuotes(UnicodeString& s) {
810  QuoteState state = OUTSIDE;
811  int32_t len = s.length();
812  int32_t dest = 0;
813  for (int32_t i = 0; i < len; ++i) {
814    UChar ch = s.charAt(i);
815    if (ch == u_apos) {
816      if (state == INSIDE_EMPTY) {
817        s.setCharAt(dest, ch);
818        ++dest;
819      }
820    } else {
821      s.setCharAt(dest, ch);
822      ++dest;
823    }
824
825    // Update state
826    switch (state) {
827      case OUTSIDE:
828        state = ch == u_apos ? INSIDE_EMPTY : OUTSIDE;
829        break;
830      case INSIDE_EMPTY:
831      case INSIDE_FULL:
832        state = ch == u_apos ? OUTSIDE : INSIDE_FULL;
833        break;
834      default:
835        break;
836    }
837  }
838  s.truncate(dest);
839}
840
841// fillInMissing ensures that the data in result is complete.
842// result data is complete if for each variant in result, there exists
843// a prefix-suffix pair for each log10 value and there also exists
844// a divisor for each log10 value.
845//
846// First this function figures out for which log10 values, the other
847// variant already had data. These are the same log10 values defined
848// in CLDR.
849//
850// For each log10 value not defined in CLDR, it uses the divisor for
851// the last defined log10 value or 1.
852//
853// Then for each variant, it does the following. For each log10
854// value not defined in CLDR, copy the prefix-suffix pair from the
855// previous log10 value. If log10 value is defined in CLDR but is
856// missing from given variant, copy the prefix-suffix pair for that
857// log10 value from the 'other' variant.
858static void fillInMissing(CDFLocaleStyleData* result) {
859  const CDFUnit* otherUnits =
860      (const CDFUnit*) uhash_get(result->unitsByVariant, gOther);
861  UBool definedInCLDR[MAX_DIGITS];
862  double lastDivisor = 1.0;
863  for (int32_t i = 0; i < MAX_DIGITS; ++i) {
864    if (!otherUnits[i].isSet()) {
865      result->divisors[i] = lastDivisor;
866      definedInCLDR[i] = FALSE;
867    } else {
868      lastDivisor = result->divisors[i];
869      definedInCLDR[i] = TRUE;
870    }
871  }
872  // Iterate over each variant.
873  int32_t pos = -1;
874  const UHashElement* element = uhash_nextElement(result->unitsByVariant, &pos);
875  for (;element != NULL; element = uhash_nextElement(result->unitsByVariant, &pos)) {
876    CDFUnit* units = (CDFUnit*) element->value.pointer;
877    for (int32_t i = 0; i < MAX_DIGITS; ++i) {
878      if (definedInCLDR[i]) {
879        if (!units[i].isSet()) {
880          units[i] = otherUnits[i];
881        }
882      } else {
883        if (i == 0) {
884          units[0].markAsSet();
885        } else {
886          units[i] = units[i - 1];
887        }
888      }
889    }
890  }
891}
892
893// computeLog10 computes floor(log10(x)). If inRange is TRUE, the biggest
894// value computeLog10 will return MAX_DIGITS -1 even for
895// numbers > 10^MAX_DIGITS. If inRange is FALSE, computeLog10 will return
896// up to MAX_DIGITS.
897static int32_t computeLog10(double x, UBool inRange) {
898  int32_t result = 0;
899  int32_t max = inRange ? MAX_DIGITS - 1 : MAX_DIGITS;
900  while (x >= 10.0) {
901    x /= 10.0;
902    ++result;
903    if (result == max) {
904      break;
905    }
906  }
907  return result;
908}
909
910// createCDFUnit returns a pointer to the prefix-suffix pair for a given
911// variant and log10 value within table. If no such prefix-suffix pair is
912// stored in table, one is created within table before returning pointer.
913static CDFUnit* createCDFUnit(const char* variant, int32_t log10Value, UHashtable* table, UErrorCode& status) {
914  if (U_FAILURE(status)) {
915    return NULL;
916  }
917  CDFUnit *cdfUnit = (CDFUnit*) uhash_get(table, variant);
918  if (cdfUnit == NULL) {
919    cdfUnit = new CDFUnit[MAX_DIGITS];
920    if (cdfUnit == NULL) {
921      status = U_MEMORY_ALLOCATION_ERROR;
922      return NULL;
923    }
924    uhash_put(table, uprv_strdup(variant), cdfUnit, &status);
925    if (U_FAILURE(status)) {
926      return NULL;
927    }
928  }
929  CDFUnit* result = &cdfUnit[log10Value];
930  result->markAsSet();
931  return result;
932}
933
934// getCDFUnitFallback returns a pointer to the prefix-suffix pair for a given
935// variant and log10 value within table. If the given variant doesn't exist, it
936// falls back to the OTHER variant. Therefore, this method will always return
937// some non-NULL value.
938static const CDFUnit* getCDFUnitFallback(const UHashtable* table, const UnicodeString& variant, int32_t log10Value) {
939  CharString cvariant;
940  UErrorCode status = U_ZERO_ERROR;
941  const CDFUnit *cdfUnit = NULL;
942  cvariant.appendInvariantChars(variant, status);
943  if (!U_FAILURE(status)) {
944    cdfUnit = (const CDFUnit*) uhash_get(table, cvariant.data());
945  }
946  if (cdfUnit == NULL) {
947    cdfUnit = (const CDFUnit*) uhash_get(table, gOther);
948  }
949  return &cdfUnit[log10Value];
950}
951
952U_NAMESPACE_END
953#endif
954