]> git.saurik.com Git - apple/icu.git/blob - icuSources/i18n/measfmt.cpp
ICU-62109.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / measfmt.cpp
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 **********************************************************************
5 * Copyright (c) 2004-2016, International Business Machines
6 * Corporation and others. All Rights Reserved.
7 **********************************************************************
8 * Author: Alan Liu
9 * Created: April 20, 2004
10 * Since: ICU 3.0
11 **********************************************************************
12 */
13 #include "utypeinfo.h" // for 'typeid' to work
14 #include "unicode/utypes.h"
15
16 #if !UCONFIG_NO_FORMATTING
17
18 #include "unicode/measfmt.h"
19 #include "unicode/numfmt.h"
20 #include "currfmt.h"
21 #include "unicode/localpointer.h"
22 #include "resource.h"
23 #include "unicode/simpleformatter.h"
24 #include "quantityformatter.h"
25 #include "unicode/plurrule.h"
26 #include "unicode/decimfmt.h"
27 #include "uresimp.h"
28 #include "unicode/ures.h"
29 #include "unicode/ustring.h"
30 #include "ureslocs.h"
31 #include "cstring.h"
32 #include "mutex.h"
33 #include "ucln_in.h"
34 #include "unicode/listformatter.h"
35 #include "charstr.h"
36 #include "unicode/putil.h"
37 #include "unicode/smpdtfmt.h"
38 #include "uassert.h"
39 #include "unicode/uameasureformat.h"
40 #include "fphdlimp.h"
41
42 #include "sharednumberformat.h"
43 #include "sharedpluralrules.h"
44 #include "standardplural.h"
45 #include "unifiedcache.h"
46
47
48 U_NAMESPACE_BEGIN
49
50 static constexpr int32_t PER_UNIT_INDEX = StandardPlural::COUNT;
51 static constexpr int32_t PATTERN_COUNT = PER_UNIT_INDEX + 1;
52 static constexpr int32_t MEAS_UNIT_COUNT = 138; // see assertion in MeasureFormatCacheData constructor
53 static constexpr int32_t WIDTH_INDEX_COUNT = UMEASFMT_WIDTH_NARROW + 1;
54
55 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MeasureFormat)
56
57 // Used to format durations like 5:47 or 21:35:42.
58 class NumericDateFormatters : public UMemory {
59 public:
60 // Formats like H:mm
61 SimpleDateFormat hourMinute;
62
63 // formats like M:ss
64 SimpleDateFormat minuteSecond;
65
66 // formats like H:mm:ss
67 SimpleDateFormat hourMinuteSecond;
68
69 // Constructor that takes the actual patterns for hour-minute,
70 // minute-second, and hour-minute-second respectively.
71 NumericDateFormatters(
72 const UnicodeString &hm,
73 const UnicodeString &ms,
74 const UnicodeString &hms,
75 UErrorCode &status) :
76 hourMinute(hm, status),
77 minuteSecond(ms, status),
78 hourMinuteSecond(hms, status) {
79 const TimeZone *gmt = TimeZone::getGMT();
80 hourMinute.setTimeZone(*gmt);
81 minuteSecond.setTimeZone(*gmt);
82 hourMinuteSecond.setTimeZone(*gmt);
83 }
84 private:
85 NumericDateFormatters(const NumericDateFormatters &other);
86 NumericDateFormatters &operator=(const NumericDateFormatters &other);
87 };
88
89 static UMeasureFormatWidth getRegularWidth(UMeasureFormatWidth width) {
90 if (width >= WIDTH_INDEX_COUNT) {
91 return UMEASFMT_WIDTH_NARROW;
92 }
93 return width;
94 }
95
96 /**
97 * Instances contain all MeasureFormat specific data for a particular locale.
98 * This data is cached. It is never copied, but is shared via shared pointers.
99 *
100 * Note: We might change the cache data to have an array[WIDTH_INDEX_COUNT] of
101 * complete sets of unit & per patterns,
102 * to correspond to the resource data and its aliases.
103 *
104 * TODO: Maybe store more sparsely in general, with pointers rather than potentially-empty objects.
105 */
106 class MeasureFormatCacheData : public SharedObject {
107 public:
108
109 /**
110 * Redirection data from root-bundle, top-level sideways aliases.
111 * - UMEASFMT_WIDTH_COUNT: initial value, just fall back to root
112 * - UMEASFMT_WIDTH_WIDE/SHORT/NARROW: sideways alias for missing data
113 */
114 UMeasureFormatWidth widthFallback[WIDTH_INDEX_COUNT];
115 /** Measure unit -> format width -> array of patterns ("{0} meters") (plurals + PER_UNIT_INDEX) */
116 SimpleFormatter* patterns[MEAS_UNIT_COUNT][WIDTH_INDEX_COUNT][PATTERN_COUNT];
117 const UChar* dnams[MEAS_UNIT_COUNT][WIDTH_INDEX_COUNT];
118 SimpleFormatter perFormatters[WIDTH_INDEX_COUNT];
119
120 MeasureFormatCacheData();
121 virtual ~MeasureFormatCacheData();
122
123 UBool hasPerFormatter(int32_t width) const {
124 // TODO: Create a more obvious way to test if the per-formatter has been set?
125 // Use pointers, check for NULL? Or add an isValid() method?
126 return perFormatters[width].getArgumentLimit() == 2;
127 }
128
129 void adoptCurrencyFormat(int32_t widthIndex, NumberFormat *nfToAdopt) {
130 delete currencyFormats[widthIndex];
131 currencyFormats[widthIndex] = nfToAdopt;
132 }
133 const NumberFormat *getCurrencyFormat(UMeasureFormatWidth width) const {
134 return currencyFormats[getRegularWidth(width)];
135 }
136 void adoptIntegerFormat(NumberFormat *nfToAdopt) {
137 delete integerFormat;
138 integerFormat = nfToAdopt;
139 }
140 const NumberFormat *getIntegerFormat() const {
141 return integerFormat;
142 }
143 void adoptNumericDateFormatters(NumericDateFormatters *formattersToAdopt) {
144 delete numericDateFormatters;
145 numericDateFormatters = formattersToAdopt;
146 }
147 const NumericDateFormatters *getNumericDateFormatters() const {
148 return numericDateFormatters;
149 }
150
151 private:
152 NumberFormat* currencyFormats[WIDTH_INDEX_COUNT];
153 NumberFormat* integerFormat;
154 NumericDateFormatters* numericDateFormatters;
155
156 MeasureFormatCacheData(const MeasureFormatCacheData &other);
157 MeasureFormatCacheData &operator=(const MeasureFormatCacheData &other);
158 };
159
160 MeasureFormatCacheData::MeasureFormatCacheData()
161 : integerFormat(nullptr), numericDateFormatters(nullptr) {
162 // Please update MEAS_UNIT_COUNT if it gets out of sync with the true count!
163 U_ASSERT(MEAS_UNIT_COUNT == MeasureUnit::getIndexCount());
164
165 for (int32_t i = 0; i < WIDTH_INDEX_COUNT; ++i) {
166 widthFallback[i] = UMEASFMT_WIDTH_COUNT;
167 }
168 memset(&patterns[0][0][0], 0, sizeof(patterns));
169 memset(&dnams[0][0], 0, sizeof(dnams));
170 memset(currencyFormats, 0, sizeof(currencyFormats));
171 }
172
173 MeasureFormatCacheData::~MeasureFormatCacheData() {
174 for (int32_t i = 0; i < UPRV_LENGTHOF(currencyFormats); ++i) {
175 delete currencyFormats[i];
176 }
177 for (int32_t i = 0; i < MEAS_UNIT_COUNT; ++i) {
178 for (int32_t j = 0; j < WIDTH_INDEX_COUNT; ++j) {
179 for (int32_t k = 0; k < PATTERN_COUNT; ++k) {
180 delete patterns[i][j][k];
181 }
182 }
183 }
184 // Note: the contents of 'dnams' are pointers into the resource bundle
185 delete integerFormat;
186 delete numericDateFormatters;
187 }
188
189 static UBool isCurrency(const MeasureUnit &unit) {
190 return (uprv_strcmp(unit.getType(), "currency") == 0);
191 }
192
193 static UBool getString(
194 const UResourceBundle *resource,
195 UnicodeString &result,
196 UErrorCode &status) {
197 int32_t len = 0;
198 const UChar *resStr = ures_getString(resource, &len, &status);
199 if (U_FAILURE(status)) {
200 return FALSE;
201 }
202 result.setTo(TRUE, resStr, len);
203 return TRUE;
204 }
205
206 namespace {
207
208 static const UChar g_LOCALE_units[] = {
209 0x2F, 0x4C, 0x4F, 0x43, 0x41, 0x4C, 0x45, 0x2F,
210 0x75, 0x6E, 0x69, 0x74, 0x73
211 };
212 static const UChar gShort[] = { 0x53, 0x68, 0x6F, 0x72, 0x74 };
213 static const UChar gNarrow[] = { 0x4E, 0x61, 0x72, 0x72, 0x6F, 0x77 };
214
215 /**
216 * Sink for enumerating all of the measurement unit display names.
217 * Contains inner sink classes, each one corresponding to a type of resource table.
218 * The outer sink handles the top-level units, unitsNarrow, and unitsShort tables.
219 *
220 * More specific bundles (en_GB) are enumerated before their parents (en_001, en, root):
221 * Only store a value if it is still missing, that is, it has not been overridden.
222 *
223 * C++: Each inner sink class has a reference to the main outer sink.
224 * Java: Use non-static inner classes instead.
225 */
226 struct UnitDataSink : public ResourceSink {
227
228 // Output data.
229 MeasureFormatCacheData &cacheData;
230
231 // Path to current data.
232 UMeasureFormatWidth width;
233 const char *type;
234 int32_t unitIndex;
235
236 UnitDataSink(MeasureFormatCacheData &outputData)
237 : cacheData(outputData),
238 width(UMEASFMT_WIDTH_COUNT), type(NULL), unitIndex(0) {}
239 ~UnitDataSink();
240
241 void setFormatterIfAbsent(int32_t index, const ResourceValue &value,
242 int32_t minPlaceholders, UErrorCode &errorCode) {
243 U_ASSERT(unitIndex < MEAS_UNIT_COUNT);
244 U_ASSERT(width < WIDTH_INDEX_COUNT);
245 U_ASSERT(index < PATTERN_COUNT);
246 SimpleFormatter **patterns = &cacheData.patterns[unitIndex][width][0];
247 if (U_SUCCESS(errorCode) && patterns[index] == NULL) {
248 if (minPlaceholders >= 0) {
249 patterns[index] = new SimpleFormatter(
250 value.getUnicodeString(errorCode), minPlaceholders, 1, errorCode);
251 }
252 if (U_SUCCESS(errorCode) && patterns[index] == NULL) {
253 errorCode = U_MEMORY_ALLOCATION_ERROR;
254 }
255 }
256 }
257
258 void setDnamIfAbsent(const ResourceValue &value, UErrorCode& errorCode) {
259 U_ASSERT(unitIndex < MEAS_UNIT_COUNT);
260 U_ASSERT(width < WIDTH_INDEX_COUNT);
261 if (cacheData.dnams[unitIndex][width] == NULL) {
262 int32_t length;
263 cacheData.dnams[unitIndex][width] = value.getString(length, errorCode);
264 }
265 }
266
267 /**
268 * Consume a display pattern. For example,
269 * unitsShort/duration/hour contains other{"{0} hrs"}.
270 */
271 void consumePattern(const char *key, const ResourceValue &value, UErrorCode &errorCode) {
272 if (U_FAILURE(errorCode)) { return; }
273 if (uprv_strcmp(key, "dnam") == 0) {
274 // The display name for the unit in the current width.
275 setDnamIfAbsent(value, errorCode);
276 } else if (uprv_strcmp(key, "per") == 0) {
277 // For example, "{0}/h".
278 setFormatterIfAbsent(PER_UNIT_INDEX, value, 1, errorCode);
279 } else {
280 // The key must be one of the plural form strings. For example:
281 // one{"{0} hr"}
282 // other{"{0} hrs"}
283 setFormatterIfAbsent(StandardPlural::indexFromString(key, errorCode), value, 0,
284 errorCode);
285 }
286 }
287
288 /**
289 * Consume a table of per-unit tables. For example,
290 * unitsShort/duration contains tables for duration-unit subtypes day & hour.
291 */
292 void consumeSubtypeTable(const char *key, ResourceValue &value, UErrorCode &errorCode) {
293 if (U_FAILURE(errorCode)) { return; }
294 unitIndex = MeasureUnit::internalGetIndexForTypeAndSubtype(type, key);
295 if (unitIndex < 0) {
296 // TODO: How to handle unexpected data?
297 // See http://bugs.icu-project.org/trac/ticket/12597
298 return;
299 }
300
301 // We no longer handle units like "coordinate" here (which do not have plural variants)
302 if (value.getType() == URES_TABLE) {
303 // Units that have plural variants
304 ResourceTable patternTableTable = value.getTable(errorCode);
305 if (U_FAILURE(errorCode)) { return; }
306 for (int i = 0; patternTableTable.getKeyAndValue(i, key, value); ++i) {
307 consumePattern(key, value, errorCode);
308 }
309 } else {
310 // TODO: How to handle unexpected data?
311 // See http://bugs.icu-project.org/trac/ticket/12597
312 return;
313 }
314 }
315
316 /**
317 * Consume compound x-per-y display pattern. For example,
318 * unitsShort/compound/per may be "{0}/{1}".
319 */
320 void consumeCompoundPattern(const char *key, const ResourceValue &value, UErrorCode &errorCode) {
321 if (U_SUCCESS(errorCode) && uprv_strcmp(key, "per") == 0) {
322 cacheData.perFormatters[width].
323 applyPatternMinMaxArguments(value.getUnicodeString(errorCode), 2, 2, errorCode);
324 }
325 }
326
327 /**
328 * Consume a table of unit type tables. For example,
329 * unitsShort contains tables for area & duration.
330 * It also contains a table for the compound/per pattern.
331 */
332 void consumeUnitTypesTable(const char *key, ResourceValue &value, UErrorCode &errorCode) {
333 if (U_FAILURE(errorCode)) { return; }
334 if (uprv_strcmp(key, "currency") == 0) {
335 // Skip.
336 } else if (uprv_strcmp(key, "compound") == 0) {
337 if (!cacheData.hasPerFormatter(width)) {
338 ResourceTable compoundTable = value.getTable(errorCode);
339 if (U_FAILURE(errorCode)) { return; }
340 for (int i = 0; compoundTable.getKeyAndValue(i, key, value); ++i) {
341 consumeCompoundPattern(key, value, errorCode);
342 }
343 }
344 } else if (uprv_strcmp(key, "coordinate") == 0) {
345 // special handling but we need to determine what that is
346 } else {
347 type = key;
348 ResourceTable subtypeTable = value.getTable(errorCode);
349 if (U_FAILURE(errorCode)) { return; }
350 for (int i = 0; subtypeTable.getKeyAndValue(i, key, value); ++i) {
351 consumeSubtypeTable(key, value, errorCode);
352 }
353 }
354 }
355
356 void consumeAlias(const char *key, const ResourceValue &value, UErrorCode &errorCode) {
357 // Handle aliases like
358 // units:alias{"/LOCALE/unitsShort"}
359 // which should only occur in the root bundle.
360 UMeasureFormatWidth sourceWidth = widthFromKey(key);
361 if (sourceWidth == UMEASFMT_WIDTH_COUNT) {
362 // Alias from something we don't care about.
363 return;
364 }
365 UMeasureFormatWidth targetWidth = widthFromAlias(value, errorCode);
366 if (targetWidth == UMEASFMT_WIDTH_COUNT) {
367 // We do not recognize what to fall back to.
368 errorCode = U_INVALID_FORMAT_ERROR;
369 return;
370 }
371 // Check that we do not fall back to another fallback.
372 if (cacheData.widthFallback[targetWidth] != UMEASFMT_WIDTH_COUNT) {
373 errorCode = U_INVALID_FORMAT_ERROR;
374 return;
375 }
376 cacheData.widthFallback[sourceWidth] = targetWidth;
377 }
378
379 void consumeTable(const char *key, ResourceValue &value, UErrorCode &errorCode) {
380 if (U_SUCCESS(errorCode) && (width = widthFromKey(key)) != UMEASFMT_WIDTH_COUNT) {
381 ResourceTable unitTypesTable = value.getTable(errorCode);
382 if (U_FAILURE(errorCode)) { return; }
383 for (int i = 0; unitTypesTable.getKeyAndValue(i, key, value); ++i) {
384 consumeUnitTypesTable(key, value, errorCode);
385 }
386 }
387 }
388
389 static UMeasureFormatWidth widthFromKey(const char *key) {
390 if (uprv_strncmp(key, "units", 5) == 0) {
391 key += 5;
392 if (*key == 0) {
393 return UMEASFMT_WIDTH_WIDE;
394 } else if (uprv_strcmp(key, "Short") == 0) {
395 return UMEASFMT_WIDTH_SHORT;
396 } else if (uprv_strcmp(key, "Narrow") == 0) {
397 return UMEASFMT_WIDTH_NARROW;
398 }
399 }
400 return UMEASFMT_WIDTH_COUNT;
401 }
402
403 static UMeasureFormatWidth widthFromAlias(const ResourceValue &value, UErrorCode &errorCode) {
404 int32_t length;
405 const UChar *s = value.getAliasString(length, errorCode);
406 // For example: "/LOCALE/unitsShort"
407 if (U_SUCCESS(errorCode) && length >= 13 && u_memcmp(s, g_LOCALE_units, 13) == 0) {
408 s += 13;
409 length -= 13;
410 if (*s == 0) {
411 return UMEASFMT_WIDTH_WIDE;
412 } else if (u_strCompare(s, length, gShort, 5, FALSE) == 0) {
413 return UMEASFMT_WIDTH_SHORT;
414 } else if (u_strCompare(s, length, gNarrow, 6, FALSE) == 0) {
415 return UMEASFMT_WIDTH_NARROW;
416 }
417 }
418 return UMEASFMT_WIDTH_COUNT;
419 }
420
421 virtual void put(const char *key, ResourceValue &value, UBool /*noFallback*/,
422 UErrorCode &errorCode) {
423 // Main entry point to sink
424 ResourceTable widthsTable = value.getTable(errorCode);
425 if (U_FAILURE(errorCode)) { return; }
426 for (int i = 0; widthsTable.getKeyAndValue(i, key, value); ++i) {
427 if (value.getType() == URES_ALIAS) {
428 consumeAlias(key, value, errorCode);
429 } else {
430 consumeTable(key, value, errorCode);
431 }
432 }
433 }
434 };
435
436 // Virtual destructors must be defined out of line.
437 UnitDataSink::~UnitDataSink() {}
438
439 } // namespace
440
441 static const UAMeasureUnit indexToUAMsasUnit[] = {
442 // UAMeasureUnit // UAMeasUnit vals # MeasUnit.getIndex()
443 UAMEASUNIT_ACCELERATION_G_FORCE, // (0 << 8) + 0, # 0
444 UAMEASUNIT_ACCELERATION_METER_PER_SECOND_SQUARED, // (0 << 8) + 1, # 1
445 UAMEASUNIT_ANGLE_ARC_MINUTE, // (1 << 8) + 1, # 2
446 UAMEASUNIT_ANGLE_ARC_SECOND, // (1 << 8) + 2, # 3
447 UAMEASUNIT_ANGLE_DEGREE, // (1 << 8) + 0, # 4
448 UAMEASUNIT_ANGLE_RADIAN, // (1 << 8) + 3, # 5
449 UAMEASUNIT_ANGLE_REVOLUTION, // (1 << 8) + 4, # 6
450 UAMEASUNIT_AREA_ACRE, // (2 << 8) + 4, # 7
451 UAMEASUNIT_AREA_HECTARE, // (2 << 8) + 5, # 8
452 UAMEASUNIT_AREA_SQUARE_CENTIMETER, // (2 << 8) + 6, # 9
453 UAMEASUNIT_AREA_SQUARE_FOOT, // (2 << 8) + 2, # 10
454 UAMEASUNIT_AREA_SQUARE_INCH, // (2 << 8) + 7, # 11
455 UAMEASUNIT_AREA_SQUARE_KILOMETER, // (2 << 8) + 1, # 12
456 UAMEASUNIT_AREA_SQUARE_METER, // (2 << 8) + 0, # 13
457 UAMEASUNIT_AREA_SQUARE_MILE, // (2 << 8) + 3, # 14
458 UAMEASUNIT_AREA_SQUARE_YARD, // (2 << 8) + 8, # 15
459 UAMEASUNIT_CONCENTRATION_KARAT, // (18 << 8) + 0, # 16
460 UAMEASUNIT_CONCENTRATION_MILLIGRAM_PER_DECILITER, // (18 << 8) + 1, # 17
461 UAMEASUNIT_CONCENTRATION_MILLIMOLE_PER_LITER, // (18 << 8) + 2, # 18
462 UAMEASUNIT_CONCENTRATION_PART_PER_MILLION, // (18 << 8) + 3, # 19
463 UAMEASUNIT_CONSUMPTION_LITER_PER_100_KILOMETERs, // (13 << 8) + 2, # 20
464 UAMEASUNIT_CONSUMPTION_LITER_PER_KILOMETER, // (13 << 8) + 0, # 21
465 UAMEASUNIT_CONSUMPTION_MILE_PER_GALLON, // (13 << 8) + 1, # 22
466 UAMEASUNIT_CONSUMPTION_MILE_PER_GALLON_IMPERIAL, // (13 << 8) + 3, # 23
467 UAMEASUNIT_DIGITAL_BIT, // (14 << 8) + 0, # 24
468 UAMEASUNIT_DIGITAL_BYTE, // (14 << 8) + 1, # 25
469 UAMEASUNIT_DIGITAL_GIGABIT, // (14 << 8) + 2, # 26
470 UAMEASUNIT_DIGITAL_GIGABYTE, // (14 << 8) + 3, # 27
471 UAMEASUNIT_DIGITAL_KILOBIT, // (14 << 8) + 4, # 28
472 UAMEASUNIT_DIGITAL_KILOBYTE, // (14 << 8) + 5, # 29
473 UAMEASUNIT_DIGITAL_MEGABIT, // (14 << 8) + 6, # 30
474 UAMEASUNIT_DIGITAL_MEGABYTE, // (14 << 8) + 7, # 31
475 UAMEASUNIT_DIGITAL_TERABIT, // (14 << 8) + 8, # 32
476 UAMEASUNIT_DIGITAL_TERABYTE, // (14 << 8) + 9, # 33
477 UAMEASUNIT_DURATION_CENTURY, // (4 << 8) + 10, # 34
478 UAMEASUNIT_DURATION_DAY, // (4 << 8) + 3, # 35
479 UAMEASUNIT_DURATION_HOUR, // (4 << 8) + 4, # 36
480 UAMEASUNIT_DURATION_MICROSECOND, // (4 << 8) + 8, # 37
481 UAMEASUNIT_DURATION_MILLISECOND, // (4 << 8) + 7, # 38
482 UAMEASUNIT_DURATION_MINUTE, // (4 << 8) + 5, # 39
483 UAMEASUNIT_DURATION_MONTH, // (4 << 8) + 1, # 40
484 UAMEASUNIT_DURATION_NANOSECOND, // (4 << 8) + 9, # 41
485 UAMEASUNIT_DURATION_SECOND, // (4 << 8) + 6, # 42
486 UAMEASUNIT_DURATION_WEEK, // (4 << 8) + 2, # 43
487 UAMEASUNIT_DURATION_YEAR, // (4 << 8) + 0, # 44
488 UAMEASUNIT_ELECTRIC_AMPERE, // (15 << 8) + 0, # 45
489 UAMEASUNIT_ELECTRIC_MILLIAMPERE, // (15 << 8) + 1, # 46
490 UAMEASUNIT_ELECTRIC_OHM, // (15 << 8) + 2, # 47
491 UAMEASUNIT_ELECTRIC_VOLT, // (15 << 8) + 3, # 48
492 UAMEASUNIT_ENERGY_CALORIE, // (12 << 8) + 0, # 49
493 UAMEASUNIT_ENERGY_FOODCALORIE, // (12 << 8) + 1, # 50
494 UAMEASUNIT_ENERGY_JOULE, // (12 << 8) + 2, # 51
495 UAMEASUNIT_ENERGY_KILOCALORIE, // (12 << 8) + 3, # 52
496 UAMEASUNIT_ENERGY_KILOJOULE, // (12 << 8) + 4, # 53
497 UAMEASUNIT_ENERGY_KILOWATT_HOUR, // (12 << 8) + 5, # 54
498 UAMEASUNIT_FREQUENCY_GIGAHERTZ, // (16 << 8) + 3, # 55
499 UAMEASUNIT_FREQUENCY_HERTZ, // (16 << 8) + 0, # 56
500 UAMEASUNIT_FREQUENCY_KILOHERTZ, // (16 << 8) + 1, # 57
501 UAMEASUNIT_FREQUENCY_MEGAHERTZ, // (16 << 8) + 2, # 58
502 UAMEASUNIT_LENGTH_ASTRONOMICAL_UNIT, // (5 << 8) + 16, # 59
503 UAMEASUNIT_LENGTH_CENTIMETER, // (5 << 8) + 1, # 60
504 UAMEASUNIT_LENGTH_DECIMETER, // (5 << 8) + 10, # 61
505 UAMEASUNIT_LENGTH_FATHOM, // (5 << 8) + 14, # 62
506 UAMEASUNIT_LENGTH_FOOT, // (5 << 8) + 5, # 63
507 UAMEASUNIT_LENGTH_FURLONG, // (5 << 8) + 15, # 64
508 UAMEASUNIT_LENGTH_INCH, // (5 << 8) + 6, # 65
509 UAMEASUNIT_LENGTH_KILOMETER, // (5 << 8) + 2, # 66
510 UAMEASUNIT_LENGTH_LIGHT_YEAR, // (5 << 8) + 9, # 67
511 UAMEASUNIT_LENGTH_METER, // (5 << 8) + 0, # 68
512 UAMEASUNIT_LENGTH_MICROMETER, // (5 << 8) + 11, # 69
513 UAMEASUNIT_LENGTH_MILE, // (5 << 8) + 7, # 70
514 UAMEASUNIT_LENGTH_MILE_SCANDINAVIAN, // (5 << 8) + 18, # 71
515 UAMEASUNIT_LENGTH_MILLIMETER, // (5 << 8) + 3, # 72
516 UAMEASUNIT_LENGTH_NANOMETER, // (5 << 8) + 12, # 73
517 UAMEASUNIT_LENGTH_NAUTICAL_MILE, // (5 << 8) + 13, # 74
518 UAMEASUNIT_LENGTH_PARSEC, // (5 << 8) + 17, # 75
519 UAMEASUNIT_LENGTH_PICOMETER, // (5 << 8) + 4, # 76
520 UAMEASUNIT_LENGTH_POINT, // (5 << 8) + 19, # 77
521 UAMEASUNIT_LENGTH_YARD, // (5 << 8) + 8, # 78
522 UAMEASUNIT_LIGHT_LUX, // (17 << 8) + 0, # 79
523 UAMEASUNIT_MASS_CARAT, // (6 << 8) + 9, # 80
524 UAMEASUNIT_MASS_GRAM, // (6 << 8) + 0, # 81
525 UAMEASUNIT_MASS_KILOGRAM, // (6 << 8) + 1, # 82
526 UAMEASUNIT_MASS_METRIC_TON, // (6 << 8) + 7, # 83
527 UAMEASUNIT_MASS_MICROGRAM, // (6 << 8) + 5, # 84
528 UAMEASUNIT_MASS_MILLIGRAM, // (6 << 8) + 6, # 85
529 UAMEASUNIT_MASS_OUNCE, // (6 << 8) + 2, # 86
530 UAMEASUNIT_MASS_OUNCE_TROY, // (6 << 8) + 10, # 87
531 UAMEASUNIT_MASS_POUND, // (6 << 8) + 3, # 88
532 UAMEASUNIT_MASS_STONE, // (6 << 8) + 4, # 89
533 UAMEASUNIT_MASS_TON, // (6 << 8) + 8, # 90
534 UAMEASUNIT_POWER_GIGAWATT, // (7 << 8) + 5, # 91
535 UAMEASUNIT_POWER_HORSEPOWER, // (7 << 8) + 2, # 92
536 UAMEASUNIT_POWER_KILOWATT, // (7 << 8) + 1, # 93
537 UAMEASUNIT_POWER_MEGAWATT, // (7 << 8) + 4, # 94
538 UAMEASUNIT_POWER_MILLIWATT, // (7 << 8) + 3, # 95
539 UAMEASUNIT_POWER_WATT, // (7 << 8) + 0, # 96
540 UAMEASUNIT_PRESSURE_HECTOPASCAL, // (8 << 8) + 0, # 97
541 UAMEASUNIT_PRESSURE_INCH_HG, // (8 << 8) + 1, # 98
542 UAMEASUNIT_PRESSURE_MILLIBAR, // (8 << 8) + 2, # 99
543 UAMEASUNIT_PRESSURE_MILLIMETER_OF_MERCURY, // (8 << 8) + 3, # 100
544 UAMEASUNIT_PRESSURE_POUND_PER_SQUARE_INCH, // (8 << 8) + 4, # 101
545 UAMEASUNIT_SPEED_KILOMETER_PER_HOUR, // (9 << 8) + 1, # 102
546 UAMEASUNIT_SPEED_KNOT, // (9 << 8) + 3, # 103
547 UAMEASUNIT_SPEED_METER_PER_SECOND, // (9 << 8) + 0, # 104
548 UAMEASUNIT_SPEED_MILE_PER_HOUR, // (9 << 8) + 2, # 105
549 UAMEASUNIT_TEMPERATURE_CELSIUS, // (10 << 8) + 0, # 106
550 UAMEASUNIT_TEMPERATURE_FAHRENHEIT, // (10 << 8) + 1, # 107
551 UAMEASUNIT_TEMPERATURE_GENERIC, // (10 << 8) + 3, # 108
552 UAMEASUNIT_TEMPERATURE_KELVIN, // (10 << 8) + 2, # 109
553 UAMEASUNIT_VOLUME_ACRE_FOOT, // (11 << 8) + 13, # 110
554 UAMEASUNIT_VOLUME_BUSHEL, // (11 << 8) + 14, # 111
555 UAMEASUNIT_VOLUME_CENTILITER, // (11 << 8) + 4, # 112
556 UAMEASUNIT_VOLUME_CUBIC_CENTIMETER, // (11 << 8) + 8, # 113
557 UAMEASUNIT_VOLUME_CUBIC_FOOT, // (11 << 8) + 11, # 114
558 UAMEASUNIT_VOLUME_CUBIC_INCH, // (11 << 8) + 10, # 115
559 UAMEASUNIT_VOLUME_CUBIC_KILOMETER, // (11 << 8) + 1, # 116
560 UAMEASUNIT_VOLUME_CUBIC_METER, // (11 << 8) + 9, # 117
561 UAMEASUNIT_VOLUME_CUBIC_MILE, // (11 << 8) + 2, # 118
562 UAMEASUNIT_VOLUME_CUBIC_YARD, // (11 << 8) + 12, # 119
563 UAMEASUNIT_VOLUME_CUP, // (11 << 8) + 18, # 120
564 UAMEASUNIT_VOLUME_CUP_METRIC, // (11 << 8) + 22, # 121
565 UAMEASUNIT_VOLUME_DECILITER, // (11 << 8) + 5, # 122
566 UAMEASUNIT_VOLUME_FLUID_OUNCE, // (11 << 8) + 17, # 123
567 UAMEASUNIT_VOLUME_GALLON, // (11 << 8) + 21, # 124
568 UAMEASUNIT_VOLUME_GALLON_IMPERIAL, // (11 << 8) + 24, # 125
569 UAMEASUNIT_VOLUME_HECTOLITER, // (11 << 8) + 6, # 126
570 UAMEASUNIT_VOLUME_LITER, // (11 << 8) + 0, # 127
571 UAMEASUNIT_VOLUME_MEGALITER, // (11 << 8) + 7, # 128
572 UAMEASUNIT_VOLUME_MILLILITER, // (11 << 8) + 3, # 129
573 UAMEASUNIT_VOLUME_PINT, // (11 << 8) + 19, # 130
574 UAMEASUNIT_VOLUME_PINT_METRIC, // (11 << 8) + 23, # 131
575 UAMEASUNIT_VOLUME_QUART, // (11 << 8) + 20, # 132
576 UAMEASUNIT_VOLUME_TABLESPOON, // (11 << 8) + 16, # 133
577 UAMEASUNIT_VOLUME_TEASPOON, // (11 << 8) + 15, # 134
578 };
579
580 static UBool loadMeasureUnitData(
581 const UResourceBundle *resource,
582 MeasureFormatCacheData &cacheData,
583 UErrorCode &status) {
584 UnitDataSink sink(cacheData);
585 ures_getAllItemsWithFallback(resource, "", sink, status);
586 return U_SUCCESS(status);
587 }
588
589 static UnicodeString loadNumericDateFormatterPattern(
590 const UResourceBundle *resource,
591 const char *pattern,
592 UErrorCode &status) {
593 UnicodeString result;
594 if (U_FAILURE(status)) {
595 return result;
596 }
597 CharString chs;
598 chs.append("durationUnits", status)
599 .append("/", status).append(pattern, status);
600 LocalUResourceBundlePointer patternBundle(
601 ures_getByKeyWithFallback(
602 resource,
603 chs.data(),
604 NULL,
605 &status));
606 if (U_FAILURE(status)) {
607 return result;
608 }
609 getString(patternBundle.getAlias(), result, status);
610 // Replace 'h' with 'H'
611 int32_t len = result.length();
612 UChar *buffer = result.getBuffer(len);
613 for (int32_t i = 0; i < len; ++i) {
614 if (buffer[i] == 0x68) { // 'h'
615 buffer[i] = 0x48; // 'H'
616 }
617 }
618 result.releaseBuffer(len);
619 return result;
620 }
621
622 static NumericDateFormatters *loadNumericDateFormatters(
623 const UResourceBundle *resource,
624 UErrorCode &status) {
625 if (U_FAILURE(status)) {
626 return NULL;
627 }
628 NumericDateFormatters *result = new NumericDateFormatters(
629 loadNumericDateFormatterPattern(resource, "hm", status),
630 loadNumericDateFormatterPattern(resource, "ms", status),
631 loadNumericDateFormatterPattern(resource, "hms", status),
632 status);
633 if (U_FAILURE(status)) {
634 delete result;
635 return NULL;
636 }
637 return result;
638 }
639
640 template<> U_I18N_API
641 const MeasureFormatCacheData *LocaleCacheKey<MeasureFormatCacheData>::createObject(
642 const void * /*unused*/, UErrorCode &status) const {
643 const char *localeId = fLoc.getName();
644 LocalUResourceBundlePointer unitsBundle(ures_open(U_ICUDATA_UNIT, localeId, &status));
645 static UNumberFormatStyle currencyStyles[] = {
646 UNUM_CURRENCY_PLURAL, UNUM_CURRENCY_ISO, UNUM_CURRENCY};
647 LocalPointer<MeasureFormatCacheData> result(new MeasureFormatCacheData(), status);
648 if (U_FAILURE(status)) {
649 return NULL;
650 }
651 if (!loadMeasureUnitData(
652 unitsBundle.getAlias(),
653 *result,
654 status)) {
655 return NULL;
656 }
657 result->adoptNumericDateFormatters(loadNumericDateFormatters(
658 unitsBundle.getAlias(), status));
659 if (U_FAILURE(status)) {
660 return NULL;
661 }
662
663 for (int32_t i = 0; i < WIDTH_INDEX_COUNT; ++i) {
664 // NumberFormat::createInstance can erase warning codes from status, so pass it
665 // a separate status instance
666 UErrorCode localStatus = U_ZERO_ERROR;
667 result->adoptCurrencyFormat(i, NumberFormat::createInstance(
668 localeId, currencyStyles[i], localStatus));
669 if (localStatus != U_ZERO_ERROR) {
670 status = localStatus;
671 }
672 if (U_FAILURE(status)) {
673 return NULL;
674 }
675 }
676 NumberFormat *inf = NumberFormat::createInstance(
677 localeId, UNUM_DECIMAL, status);
678 if (U_FAILURE(status)) {
679 return NULL;
680 }
681 inf->setMaximumFractionDigits(0);
682 DecimalFormat *decfmt = dynamic_cast<DecimalFormat *>(inf);
683 if (decfmt != NULL) {
684 decfmt->setRoundingMode(DecimalFormat::kRoundDown);
685 }
686 result->adoptIntegerFormat(inf);
687 result->addRef();
688 return result.orphan();
689 }
690
691 static UBool isTimeUnit(const MeasureUnit &mu, const char *tu) {
692 return uprv_strcmp(mu.getType(), "duration") == 0 &&
693 uprv_strcmp(mu.getSubtype(), tu) == 0;
694 }
695
696 // Converts a composite measure into hours-minutes-seconds and stores at hms
697 // array. [0] is hours; [1] is minutes; [2] is seconds. Returns a bit map of
698 // units found: 1=hours, 2=minutes, 4=seconds. For example, if measures
699 // contains hours-minutes, this function would return 3.
700 //
701 // If measures cannot be converted into hours, minutes, seconds or if amounts
702 // are negative, or if hours, minutes, seconds are out of order, returns 0.
703 static int32_t toHMS(
704 const Measure *measures,
705 int32_t measureCount,
706 Formattable *hms,
707 UErrorCode &status) {
708 if (U_FAILURE(status)) {
709 return 0;
710 }
711 int32_t result = 0;
712 if (U_FAILURE(status)) {
713 return 0;
714 }
715 // We use copy constructor to ensure that both sides of equality operator
716 // are instances of MeasureUnit base class and not a subclass. Otherwise,
717 // operator== will immediately return false.
718 for (int32_t i = 0; i < measureCount; ++i) {
719 if (isTimeUnit(measures[i].getUnit(), "hour")) {
720 // hour must come first
721 if (result >= 1) {
722 return 0;
723 }
724 hms[0] = measures[i].getNumber();
725 if (hms[0].getDouble() < 0.0) {
726 return 0;
727 }
728 result |= 1;
729 } else if (isTimeUnit(measures[i].getUnit(), "minute")) {
730 // minute must come after hour
731 if (result >= 2) {
732 return 0;
733 }
734 hms[1] = measures[i].getNumber();
735 if (hms[1].getDouble() < 0.0) {
736 return 0;
737 }
738 result |= 2;
739 } else if (isTimeUnit(measures[i].getUnit(), "second")) {
740 // second must come after hour and minute
741 if (result >= 4) {
742 return 0;
743 }
744 hms[2] = measures[i].getNumber();
745 if (hms[2].getDouble() < 0.0) {
746 return 0;
747 }
748 result |= 4;
749 } else {
750 return 0;
751 }
752 }
753 return result;
754 }
755
756
757 MeasureFormat::MeasureFormat(
758 const Locale &locale, UMeasureFormatWidth w, UErrorCode &status)
759 : cache(NULL),
760 numberFormat(NULL),
761 pluralRules(NULL),
762 width((w==UMEASFMT_WIDTH_SHORTER)? UMEASFMT_WIDTH_SHORT: w),
763 stripPatternSpaces(w==UMEASFMT_WIDTH_SHORTER),
764 listFormatter(NULL),
765 listFormatterStd(NULL) {
766 initMeasureFormat(locale, (w==UMEASFMT_WIDTH_SHORTER)? UMEASFMT_WIDTH_SHORT: w, NULL, status);
767 }
768
769 MeasureFormat::MeasureFormat(
770 const Locale &locale,
771 UMeasureFormatWidth w,
772 NumberFormat *nfToAdopt,
773 UErrorCode &status)
774 : cache(NULL),
775 numberFormat(NULL),
776 pluralRules(NULL),
777 width((w==UMEASFMT_WIDTH_SHORTER)? UMEASFMT_WIDTH_SHORT: w),
778 stripPatternSpaces(w==UMEASFMT_WIDTH_SHORTER),
779 listFormatter(NULL),
780 listFormatterStd(NULL) {
781 initMeasureFormat(locale, (w==UMEASFMT_WIDTH_SHORTER)? UMEASFMT_WIDTH_SHORT: w, nfToAdopt, status);
782 }
783
784 MeasureFormat::MeasureFormat(const MeasureFormat &other) :
785 Format(other),
786 cache(other.cache),
787 numberFormat(other.numberFormat),
788 pluralRules(other.pluralRules),
789 width(other.width),
790 stripPatternSpaces(other.stripPatternSpaces),
791 listFormatter(NULL),
792 listFormatterStd(NULL) {
793 cache->addRef();
794 numberFormat->addRef();
795 pluralRules->addRef();
796 if (other.listFormatter != NULL) {
797 listFormatter = new ListFormatter(*other.listFormatter);
798 }
799 if (other.listFormatterStd != NULL) {
800 listFormatterStd = new ListFormatter(*other.listFormatterStd);
801 }
802 }
803
804 MeasureFormat &MeasureFormat::operator=(const MeasureFormat &other) {
805 if (this == &other) {
806 return *this;
807 }
808 Format::operator=(other);
809 SharedObject::copyPtr(other.cache, cache);
810 SharedObject::copyPtr(other.numberFormat, numberFormat);
811 SharedObject::copyPtr(other.pluralRules, pluralRules);
812 width = other.width;
813 stripPatternSpaces = other.stripPatternSpaces;
814 delete listFormatter;
815 if (other.listFormatter != NULL) {
816 listFormatter = new ListFormatter(*other.listFormatter);
817 } else {
818 listFormatter = NULL;
819 }
820 delete listFormatterStd;
821 if (other.listFormatterStd != NULL) {
822 listFormatterStd = new ListFormatter(*other.listFormatterStd);
823 } else {
824 listFormatterStd = NULL;
825 }
826 return *this;
827 }
828
829 MeasureFormat::MeasureFormat() :
830 cache(NULL),
831 numberFormat(NULL),
832 pluralRules(NULL),
833 width(UMEASFMT_WIDTH_SHORT),
834 stripPatternSpaces(FALSE),
835 listFormatter(NULL),
836 listFormatterStd(NULL) {
837 }
838
839 MeasureFormat::~MeasureFormat() {
840 if (cache != NULL) {
841 cache->removeRef();
842 }
843 if (numberFormat != NULL) {
844 numberFormat->removeRef();
845 }
846 if (pluralRules != NULL) {
847 pluralRules->removeRef();
848 }
849 delete listFormatter;
850 delete listFormatterStd;
851 }
852
853 UBool MeasureFormat::operator==(const Format &other) const {
854 if (this == &other) { // Same object, equal
855 return TRUE;
856 }
857 if (!Format::operator==(other)) {
858 return FALSE;
859 }
860 const MeasureFormat &rhs = static_cast<const MeasureFormat &>(other);
861
862 // Note: Since the ListFormatter depends only on Locale and width, we
863 // don't have to check it here.
864
865 // differing widths aren't equivalent
866 if (width != rhs.width || stripPatternSpaces != rhs.stripPatternSpaces) {
867 return FALSE;
868 }
869 // Width the same check locales.
870 // We don't need to check locales if both objects have same cache.
871 if (cache != rhs.cache) {
872 UErrorCode status = U_ZERO_ERROR;
873 const char *localeId = getLocaleID(status);
874 const char *rhsLocaleId = rhs.getLocaleID(status);
875 if (U_FAILURE(status)) {
876 // On failure, assume not equal
877 return FALSE;
878 }
879 if (uprv_strcmp(localeId, rhsLocaleId) != 0) {
880 return FALSE;
881 }
882 }
883 // Locales same, check NumberFormat if shared data differs.
884 return (
885 numberFormat == rhs.numberFormat ||
886 **numberFormat == **rhs.numberFormat);
887 }
888
889 Format *MeasureFormat::clone() const {
890 return new MeasureFormat(*this);
891 }
892
893 UnicodeString &MeasureFormat::format(
894 const Formattable &obj,
895 UnicodeString &appendTo,
896 FieldPosition &pos,
897 UErrorCode &status) const {
898 if (U_FAILURE(status)) return appendTo;
899 if (obj.getType() == Formattable::kObject) {
900 const UObject* formatObj = obj.getObject();
901 const Measure* amount = dynamic_cast<const Measure*>(formatObj);
902 if (amount != NULL) {
903 return formatMeasure(
904 *amount, **numberFormat, appendTo, pos, status);
905 }
906 }
907 status = U_ILLEGAL_ARGUMENT_ERROR;
908 return appendTo;
909 }
910
911 void MeasureFormat::parseObject(
912 const UnicodeString & /*source*/,
913 Formattable & /*result*/,
914 ParsePosition& /*pos*/) const {
915 return;
916 }
917
918 UnicodeString &MeasureFormat::formatMeasurePerUnit(
919 const Measure &measure,
920 const MeasureUnit &perUnit,
921 UnicodeString &appendTo,
922 FieldPosition &pos,
923 UErrorCode &status) const {
924 if (U_FAILURE(status)) {
925 return appendTo;
926 }
927 bool isResolved = false;
928 MeasureUnit resolvedUnit =
929 MeasureUnit::resolveUnitPerUnit(measure.getUnit(), perUnit, &isResolved);
930 if (isResolved) {
931 Measure newMeasure(measure.getNumber(), new MeasureUnit(resolvedUnit), status);
932 return formatMeasure(
933 newMeasure, **numberFormat, appendTo, pos, status);
934 }
935 FieldPosition fpos(pos.getField());
936 UnicodeString result;
937 int32_t offset = withPerUnitAndAppend(
938 formatMeasure(
939 measure, **numberFormat, result, fpos, status),
940 perUnit,
941 appendTo,
942 status);
943 if (U_FAILURE(status)) {
944 return appendTo;
945 }
946 if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) {
947 pos.setBeginIndex(fpos.getBeginIndex() + offset);
948 pos.setEndIndex(fpos.getEndIndex() + offset);
949 }
950 return appendTo;
951 }
952
953 UnicodeString &MeasureFormat::formatMeasures(
954 const Measure *measures,
955 int32_t measureCount,
956 UnicodeString &appendTo,
957 FieldPosition &pos,
958 UErrorCode &status) const {
959 if (U_FAILURE(status)) {
960 return appendTo;
961 }
962 if (measureCount == 0) {
963 return appendTo;
964 }
965 if (measureCount == 1) {
966 return formatMeasure(measures[0], **numberFormat, appendTo, pos, status);
967 }
968 if (width == UMEASFMT_WIDTH_NUMERIC) {
969 Formattable hms[3];
970 int32_t bitMap = toHMS(measures, measureCount, hms, status);
971 if (bitMap > 0) {
972 FieldPositionIteratorHandler handler(NULL, status);
973 return formatNumeric(hms, bitMap, appendTo, handler, status);
974 }
975 }
976 if (pos.getField() != FieldPosition::DONT_CARE) {
977 return formatMeasuresSlowTrack(
978 measures, measureCount, appendTo, pos, status);
979 }
980 UnicodeString *results = new UnicodeString[measureCount];
981 if (results == NULL) {
982 status = U_MEMORY_ALLOCATION_ERROR;
983 return appendTo;
984 }
985 for (int32_t i = 0; i < measureCount; ++i) {
986 const NumberFormat *nf = cache->getIntegerFormat();
987 if (i == measureCount - 1) {
988 nf = numberFormat->get();
989 }
990 formatMeasure(
991 measures[i],
992 *nf,
993 results[i],
994 pos,
995 status);
996 }
997 listFormatter->format(results, measureCount, appendTo, status);
998 delete [] results;
999 return appendTo;
1000 }
1001
1002 // Apple-specific version for now;
1003 // uses FieldPositionIterator* instead of FieldPosition&
1004 UnicodeString &MeasureFormat::formatMeasures(
1005 const Measure *measures,
1006 int32_t measureCount,
1007 UnicodeString &appendTo,
1008 FieldPositionIterator* posIter,
1009 UErrorCode &status) const {
1010 if (U_FAILURE(status)) {
1011 return appendTo;
1012 }
1013 FieldPositionIteratorHandler handler(posIter, status);
1014 if (measureCount == 0) {
1015 return appendTo;
1016 }
1017 if (measureCount == 1) {
1018 int32_t start = appendTo.length();
1019 int32_t field = indexToUAMsasUnit[measures[0].getUnit().getIndex()];
1020 FieldPosition pos(UAMEASFMT_NUMERIC_FIELD_FLAG); // special field value to request range of entire numeric part
1021 formatMeasure(measures[0], **numberFormat, appendTo, pos, status);
1022 handler.addAttribute(field, start, appendTo.length());
1023 handler.addAttribute(field | UAMEASFMT_NUMERIC_FIELD_FLAG, pos.getBeginIndex(), pos.getEndIndex());
1024 return appendTo;
1025 }
1026 if (width == UMEASFMT_WIDTH_NUMERIC) {
1027 Formattable hms[3];
1028 int32_t bitMap = toHMS(measures, measureCount, hms, status);
1029 if (bitMap > 0) {
1030 return formatNumeric(hms, bitMap, appendTo, handler, status);
1031 }
1032 }
1033 UnicodeString *results = new UnicodeString[measureCount];
1034 if (results == NULL) {
1035 status = U_MEMORY_ALLOCATION_ERROR;
1036 return appendTo;
1037 }
1038 FieldPosition *numPositions = new FieldPosition[measureCount];
1039 if (results == NULL) {
1040 delete [] results;
1041 status = U_MEMORY_ALLOCATION_ERROR;
1042 return appendTo;
1043 }
1044
1045 for (int32_t i = 0; i < measureCount; ++i) {
1046 const NumberFormat *nf = cache->getIntegerFormat();
1047 if (i == measureCount - 1) {
1048 nf = numberFormat->get();
1049 }
1050 numPositions[i].setField(UAMEASFMT_NUMERIC_FIELD_FLAG);
1051 formatMeasure(
1052 measures[i],
1053 *nf,
1054 results[i],
1055 numPositions[i],
1056 status);
1057 }
1058 listFormatter->format(results, measureCount, appendTo, status);
1059 for (int32_t i = 0; i < measureCount; ++i) {
1060 int32_t begin = appendTo.indexOf(results[i]);
1061 if (begin >= 0) {
1062 int32_t field = indexToUAMsasUnit[measures[i].getUnit().getIndex()];
1063 handler.addAttribute(field, begin, begin + results[i].length());
1064 int32_t numPosBegin = numPositions[i].getBeginIndex();
1065 int32_t numPosEnd = numPositions[i].getEndIndex();
1066 if (numPosBegin >= 0 && numPosEnd > numPosBegin) {
1067 handler.addAttribute(field | UAMEASFMT_NUMERIC_FIELD_FLAG, begin + numPosBegin, begin + numPosEnd);
1068 }
1069 }
1070 }
1071 delete [] results;
1072 delete [] numPositions;
1073 return appendTo;
1074 }
1075
1076
1077 UnicodeString MeasureFormat::getUnitDisplayName(const MeasureUnit& unit, UErrorCode& /*status*/) const {
1078 UMeasureFormatWidth width = getRegularWidth(this->width);
1079 const UChar* const* styleToDnam = cache->dnams[unit.getIndex()];
1080 const UChar* dnam = styleToDnam[width];
1081 if (dnam == NULL) {
1082 int32_t fallbackWidth = cache->widthFallback[width];
1083 dnam = styleToDnam[fallbackWidth];
1084 }
1085
1086 UnicodeString result;
1087 if (dnam == NULL) {
1088 result.setToBogus();
1089 } else {
1090 result.setTo(dnam, -1);
1091 }
1092 return result;
1093 }
1094
1095 void MeasureFormat::initMeasureFormat(
1096 const Locale &locale,
1097 UMeasureFormatWidth w,
1098 NumberFormat *nfToAdopt,
1099 UErrorCode &status) {
1100 static const char *listStyles[] = {"unit", "unit-short", "unit-narrow"};
1101 LocalPointer<NumberFormat> nf(nfToAdopt);
1102 if (U_FAILURE(status)) {
1103 return;
1104 }
1105 const char *name = locale.getName();
1106 setLocaleIDs(name, name);
1107
1108 UnifiedCache::getByLocale(locale, cache, status);
1109 if (U_FAILURE(status)) {
1110 return;
1111 }
1112
1113 const SharedPluralRules *pr = PluralRules::createSharedInstance(
1114 locale, UPLURAL_TYPE_CARDINAL, status);
1115 if (U_FAILURE(status)) {
1116 return;
1117 }
1118 SharedObject::copyPtr(pr, pluralRules);
1119 pr->removeRef();
1120 if (nf.isNull()) {
1121 const SharedNumberFormat *shared = NumberFormat::createSharedInstance(
1122 locale, UNUM_DECIMAL, status);
1123 if (U_FAILURE(status)) {
1124 return;
1125 }
1126 SharedObject::copyPtr(shared, numberFormat);
1127 shared->removeRef();
1128 } else {
1129 adoptNumberFormat(nf.orphan(), status);
1130 if (U_FAILURE(status)) {
1131 return;
1132 }
1133 }
1134 width = w;
1135 if (stripPatternSpaces) {
1136 w = UMEASFMT_WIDTH_NARROW;
1137 }
1138 delete listFormatter;
1139 listFormatter = ListFormatter::createInstance(
1140 locale,
1141 listStyles[getRegularWidth(w)],
1142 status);
1143 delete listFormatterStd;
1144 listFormatterStd = ListFormatter::createInstance(
1145 locale,
1146 "standard",
1147 status);
1148 }
1149
1150 void MeasureFormat::adoptNumberFormat(
1151 NumberFormat *nfToAdopt, UErrorCode &status) {
1152 LocalPointer<NumberFormat> nf(nfToAdopt);
1153 if (U_FAILURE(status)) {
1154 return;
1155 }
1156 SharedNumberFormat *shared = new SharedNumberFormat(nf.getAlias());
1157 if (shared == NULL) {
1158 status = U_MEMORY_ALLOCATION_ERROR;
1159 return;
1160 }
1161 nf.orphan();
1162 SharedObject::copyPtr(shared, numberFormat);
1163 }
1164
1165 UBool MeasureFormat::setMeasureFormatLocale(const Locale &locale, UErrorCode &status) {
1166 if (U_FAILURE(status) || locale == getLocale(status)) {
1167 return FALSE;
1168 }
1169 initMeasureFormat(locale, width, NULL, status);
1170 return U_SUCCESS(status);
1171 }
1172
1173 // Apple-specific for now
1174 UMeasureFormatWidth MeasureFormat::getWidth() const {
1175 return width;
1176 }
1177
1178 const NumberFormat &MeasureFormat::getNumberFormat() const {
1179 return **numberFormat;
1180 }
1181
1182 const PluralRules &MeasureFormat::getPluralRules() const {
1183 return **pluralRules;
1184 }
1185
1186 Locale MeasureFormat::getLocale(UErrorCode &status) const {
1187 return Format::getLocale(ULOC_VALID_LOCALE, status);
1188 }
1189
1190 const char *MeasureFormat::getLocaleID(UErrorCode &status) const {
1191 return Format::getLocaleID(ULOC_VALID_LOCALE, status);
1192 }
1193
1194 // Apple=specific
1195 // now just re-implement using standard getUnitDisplayName
1196 // so we no longer use cache->getDisplayName
1197 UnicodeString &MeasureFormat::getUnitName(
1198 const MeasureUnit* unit,
1199 UnicodeString &result ) const {
1200 UErrorCode status = U_ZERO_ERROR;
1201 result = getUnitDisplayName(*unit, status); // does not use or set status
1202 return result;
1203 }
1204
1205 // Apple=specific
1206 UnicodeString &MeasureFormat::getMultipleUnitNames(
1207 const MeasureUnit** units,
1208 int32_t unitCount,
1209 UAMeasureNameListStyle listStyle,
1210 UnicodeString &result ) const {
1211 if (unitCount == 0) {
1212 return result.remove();
1213 }
1214 if (unitCount == 1) {
1215 return getUnitName(units[0], result);
1216 }
1217 UnicodeString *results = new UnicodeString[unitCount];
1218 if (results != NULL) {
1219 for (int32_t i = 0; i < unitCount; ++i) {
1220 getUnitName(units[i], results[i]);
1221 }
1222 UErrorCode status = U_ZERO_ERROR;
1223 if (listStyle == UAMEASNAME_LIST_STANDARD) {
1224 listFormatterStd->format(results, unitCount, result, status);
1225 } else {
1226 listFormatter->format(results, unitCount, result, status);
1227 }
1228 delete [] results;
1229 if (U_SUCCESS(status)) {
1230 return result;
1231 }
1232 }
1233 result.setToBogus();
1234 return result;
1235 }
1236
1237 UnicodeString &MeasureFormat::formatMeasure(
1238 const Measure &measure,
1239 const NumberFormat &nf,
1240 UnicodeString &appendTo,
1241 FieldPosition &pos,
1242 UErrorCode &status) const {
1243 if (U_FAILURE(status)) {
1244 return appendTo;
1245 }
1246 const Formattable& amtNumber = measure.getNumber();
1247 const MeasureUnit& amtUnit = measure.getUnit();
1248 if (isCurrency(amtUnit)) {
1249 UChar isoCode[4];
1250 u_charsToUChars(amtUnit.getSubtype(), isoCode, 4);
1251 return cache->getCurrencyFormat(width)->format(
1252 new CurrencyAmount(amtNumber, isoCode, status),
1253 appendTo,
1254 pos,
1255 status);
1256 }
1257 UnicodeString formattedNumber;
1258 UBool posForFullNumericPart = (pos.getField() == UAMEASFMT_NUMERIC_FIELD_FLAG);
1259 if (posForFullNumericPart) {
1260 pos.setField(FieldPosition::DONT_CARE);
1261 }
1262 StandardPlural::Form pluralForm = QuantityFormatter::selectPlural(
1263 amtNumber, nf, **pluralRules, formattedNumber, pos, status);
1264 if (posForFullNumericPart) {
1265 pos.setField(UAMEASFMT_NUMERIC_FIELD_FLAG);
1266 pos.setBeginIndex(0);
1267 pos.setEndIndex(formattedNumber.length());
1268 }
1269 const SimpleFormatter *formatter = getPluralFormatter(amtUnit, width, pluralForm, status);
1270 int32_t cur = appendTo.length();
1271 QuantityFormatter::format(*formatter, formattedNumber, appendTo, pos, status);
1272 if (stripPatternSpaces) {
1273 const SimpleFormatter *narrowFormatter = getPluralFormatter(amtUnit, UMEASFMT_WIDTH_NARROW, pluralForm, status);
1274 if (U_SUCCESS(status)) {
1275 // Get the narrow pattern with all {n} set to empty string.
1276 // If there are spaces in that, then do not continue to strip spaces
1277 // (i.e. even in the narrowest form this locale keeps spaces).
1278 UnicodeString narrowPatternNoArgs = narrowFormatter->getTextWithNoArguments();
1279 if (narrowPatternNoArgs.indexOf((UChar)0x0020) == -1 && narrowPatternNoArgs.indexOf((UChar)0x00A0) == -1) {
1280 int32_t end = appendTo.length();
1281 for (; cur < end; cur++) {
1282 if (appendTo.charAt(cur) == 0x0020) {
1283 appendTo.remove(cur, 1);
1284 if (pos.getBeginIndex() > cur) {
1285 pos.setBeginIndex(pos.getBeginIndex() - 1);
1286 pos.setEndIndex(pos.getEndIndex() - 1);
1287 }
1288 }
1289 }
1290 }
1291 }
1292 }
1293 return appendTo;
1294 }
1295
1296 // Formats hours-minutes-seconds as 5:37:23 or similar.
1297 UnicodeString &MeasureFormat::formatNumeric(
1298 const Formattable *hms, // always length 3
1299 int32_t bitMap, // 1=hourset, 2=minuteset, 4=secondset
1300 UnicodeString &appendTo,
1301 FieldPositionHandler& handler,
1302 UErrorCode &status) const {
1303 if (U_FAILURE(status)) {
1304 return appendTo;
1305 }
1306 UDate millis =
1307 (UDate) (((uprv_trunc(hms[0].getDouble(status)) * 60.0
1308 + uprv_trunc(hms[1].getDouble(status))) * 60.0
1309 + uprv_trunc(hms[2].getDouble(status))) * 1000.0);
1310 switch (bitMap) {
1311 case 5: // hs
1312 case 7: // hms
1313 return formatNumeric(
1314 millis,
1315 cache->getNumericDateFormatters()->hourMinuteSecond,
1316 UDAT_SECOND_FIELD,
1317 hms[2],
1318 appendTo,
1319 handler,
1320 status);
1321 break;
1322 case 6: // ms
1323 return formatNumeric(
1324 millis,
1325 cache->getNumericDateFormatters()->minuteSecond,
1326 UDAT_SECOND_FIELD,
1327 hms[2],
1328 appendTo,
1329 handler,
1330 status);
1331 break;
1332 case 3: // hm
1333 return formatNumeric(
1334 millis,
1335 cache->getNumericDateFormatters()->hourMinute,
1336 UDAT_MINUTE_FIELD,
1337 hms[1],
1338 appendTo,
1339 handler,
1340 status);
1341 break;
1342 default:
1343 status = U_INTERNAL_PROGRAM_ERROR;
1344 return appendTo;
1345 break;
1346 }
1347 return appendTo;
1348 }
1349
1350 static void appendRange(
1351 const UnicodeString &src,
1352 int32_t start,
1353 int32_t end,
1354 UnicodeString &dest) {
1355 dest.append(src, start, end - start);
1356 }
1357
1358 static void appendRange(
1359 const UnicodeString &src,
1360 int32_t end,
1361 UnicodeString &dest) {
1362 dest.append(src, end, src.length() - end);
1363 }
1364
1365 // Formats time like 5:37:23
1366 UnicodeString &MeasureFormat::formatNumeric(
1367 UDate date, // Time since epoch 1:30:00 would be 5400000
1368 const DateFormat &dateFmt, // h:mm, m:ss, or h:mm:ss
1369 UDateFormatField smallestField, // seconds in 5:37:23.5
1370 const Formattable &smallestAmount, // 23.5 for 5:37:23.5
1371 UnicodeString &appendTo,
1372 FieldPositionHandler& handler,
1373 UErrorCode &status) const {
1374 if (U_FAILURE(status)) {
1375 return appendTo;
1376 }
1377 // Format the smallest amount with this object's NumberFormat
1378 UnicodeString smallestAmountFormatted;
1379
1380 // We keep track of the integer part of smallest amount so that
1381 // we can replace it later so that we get '0:00:09.3' instead of
1382 // '0:00:9.3'
1383 FieldPosition intFieldPosition(UNUM_INTEGER_FIELD);
1384 (*numberFormat)->format(
1385 smallestAmount, smallestAmountFormatted, intFieldPosition, status);
1386 if (
1387 intFieldPosition.getBeginIndex() == 0 &&
1388 intFieldPosition.getEndIndex() == 0) {
1389 status = U_INTERNAL_PROGRAM_ERROR;
1390 return appendTo;
1391 }
1392
1393 // Format time. draft becomes something like '5:30:45'
1394 // #13606: DateFormat is not thread-safe, but MeasureFormat advertises itself as thread-safe.
1395 FieldPositionIterator posIter;
1396 UnicodeString draft;
1397 static UMutex dateFmtMutex = U_MUTEX_INITIALIZER;
1398 umtx_lock(&dateFmtMutex);
1399 dateFmt.format(date, draft, &posIter, status);
1400 umtx_unlock(&dateFmtMutex);
1401
1402 int32_t start = appendTo.length();
1403 FieldPosition smallestFieldPosition(smallestField);
1404 FieldPosition fp;
1405 int32_t measField = -1;
1406 while (posIter.next(fp)) {
1407 int32_t dateField = fp.getField();
1408 switch (dateField) {
1409 case UDAT_HOUR_OF_DAY1_FIELD:
1410 case UDAT_HOUR_OF_DAY0_FIELD:
1411 case UDAT_HOUR1_FIELD:
1412 case UDAT_HOUR0_FIELD:
1413 measField = UAMEASUNIT_DURATION_HOUR; break;
1414 case UDAT_MINUTE_FIELD:
1415 measField = UAMEASUNIT_DURATION_MINUTE; break;
1416 case UDAT_SECOND_FIELD:
1417 measField = UAMEASUNIT_DURATION_SECOND; break;
1418 default:
1419 measField = -1; break;
1420 }
1421 if (dateField != smallestField) {
1422 if (measField >= 0) {
1423 handler.addAttribute(measField, start + fp.getBeginIndex(), start + fp.getEndIndex());
1424 handler.addAttribute(measField | UAMEASFMT_NUMERIC_FIELD_FLAG, start + fp.getBeginIndex(), start + fp.getEndIndex());
1425 }
1426 } else {
1427 smallestFieldPosition.setBeginIndex(fp.getBeginIndex());
1428 smallestFieldPosition.setEndIndex(fp.getEndIndex());
1429 break;
1430 }
1431 }
1432
1433 // If we find field for smallest amount replace it with the formatted
1434 // smallest amount from above taking care to replace the integer part
1435 // with what is in original time. For example, If smallest amount
1436 // is 9.35s and the formatted time is 0:00:09 then 9.35 becomes 09.35
1437 // and replacing yields 0:00:09.35
1438 if (smallestFieldPosition.getBeginIndex() != 0 ||
1439 smallestFieldPosition.getEndIndex() != 0) {
1440 appendRange(draft, 0, smallestFieldPosition.getBeginIndex(), appendTo);
1441 appendRange(
1442 smallestAmountFormatted,
1443 0,
1444 intFieldPosition.getBeginIndex(),
1445 appendTo);
1446 appendRange(
1447 draft,
1448 smallestFieldPosition.getBeginIndex(),
1449 smallestFieldPosition.getEndIndex(),
1450 appendTo);
1451 appendRange(
1452 smallestAmountFormatted,
1453 intFieldPosition.getEndIndex(),
1454 appendTo);
1455 appendRange(
1456 draft,
1457 smallestFieldPosition.getEndIndex(),
1458 appendTo);
1459 handler.addAttribute(measField, start + smallestFieldPosition.getBeginIndex(), appendTo.length());
1460 handler.addAttribute(measField | UAMEASFMT_NUMERIC_FIELD_FLAG, start + smallestFieldPosition.getBeginIndex(), appendTo.length());
1461 } else {
1462 appendTo.append(draft);
1463 }
1464 return appendTo;
1465 }
1466
1467 const SimpleFormatter *MeasureFormat::getFormatterOrNull(
1468 const MeasureUnit &unit, UMeasureFormatWidth width, int32_t index) const {
1469 width = getRegularWidth(width);
1470 SimpleFormatter *const (*unitPatterns)[PATTERN_COUNT] = &cache->patterns[unit.getIndex()][0];
1471 if (unitPatterns[width][index] != NULL) {
1472 return unitPatterns[width][index];
1473 }
1474 int32_t fallbackWidth = cache->widthFallback[width];
1475 if (fallbackWidth != UMEASFMT_WIDTH_COUNT && unitPatterns[fallbackWidth][index] != NULL) {
1476 return unitPatterns[fallbackWidth][index];
1477 }
1478 return NULL;
1479 }
1480
1481 const SimpleFormatter *MeasureFormat::getFormatter(
1482 const MeasureUnit &unit, UMeasureFormatWidth width, int32_t index,
1483 UErrorCode &errorCode) const {
1484 if (U_FAILURE(errorCode)) {
1485 return NULL;
1486 }
1487 const SimpleFormatter *pattern = getFormatterOrNull(unit, width, index);
1488 if (pattern == NULL) {
1489 errorCode = U_MISSING_RESOURCE_ERROR;
1490 }
1491 return pattern;
1492 }
1493
1494 const SimpleFormatter *MeasureFormat::getPluralFormatter(
1495 const MeasureUnit &unit, UMeasureFormatWidth width, int32_t index,
1496 UErrorCode &errorCode) const {
1497 if (U_FAILURE(errorCode)) {
1498 return NULL;
1499 }
1500 if (index != StandardPlural::OTHER) {
1501 const SimpleFormatter *pattern = getFormatterOrNull(unit, width, index);
1502 if (pattern != NULL) {
1503 return pattern;
1504 }
1505 }
1506 return getFormatter(unit, width, StandardPlural::OTHER, errorCode);
1507 }
1508
1509 const SimpleFormatter *MeasureFormat::getPerFormatter(
1510 UMeasureFormatWidth width,
1511 UErrorCode &status) const {
1512 if (U_FAILURE(status)) {
1513 return NULL;
1514 }
1515 width = getRegularWidth(width);
1516 const SimpleFormatter * perFormatters = cache->perFormatters;
1517 if (perFormatters[width].getArgumentLimit() == 2) {
1518 return &perFormatters[width];
1519 }
1520 int32_t fallbackWidth = cache->widthFallback[width];
1521 if (fallbackWidth != UMEASFMT_WIDTH_COUNT &&
1522 perFormatters[fallbackWidth].getArgumentLimit() == 2) {
1523 return &perFormatters[fallbackWidth];
1524 }
1525 status = U_MISSING_RESOURCE_ERROR;
1526 return NULL;
1527 }
1528
1529 int32_t MeasureFormat::withPerUnitAndAppend(
1530 const UnicodeString &formatted,
1531 const MeasureUnit &perUnit,
1532 UnicodeString &appendTo,
1533 UErrorCode &status) const {
1534 int32_t offset = -1;
1535 if (U_FAILURE(status)) {
1536 return offset;
1537 }
1538 const SimpleFormatter *perUnitFormatter = getFormatterOrNull(perUnit, width, PER_UNIT_INDEX);
1539 if (perUnitFormatter != NULL) {
1540 const UnicodeString *params[] = {&formatted};
1541 perUnitFormatter->formatAndAppend(
1542 params,
1543 UPRV_LENGTHOF(params),
1544 appendTo,
1545 &offset,
1546 1,
1547 status);
1548 return offset;
1549 }
1550 const SimpleFormatter *perFormatter = getPerFormatter(width, status);
1551 const SimpleFormatter *pattern =
1552 getPluralFormatter(perUnit, width, StandardPlural::ONE, status);
1553 if (U_FAILURE(status)) {
1554 return offset;
1555 }
1556 UnicodeString perUnitString = pattern->getTextWithNoArguments();
1557 perUnitString.trim();
1558 const UnicodeString *params[] = {&formatted, &perUnitString};
1559 perFormatter->formatAndAppend(
1560 params,
1561 UPRV_LENGTHOF(params),
1562 appendTo,
1563 &offset,
1564 1,
1565 status);
1566 return offset;
1567 }
1568
1569 UnicodeString &MeasureFormat::formatMeasuresSlowTrack(
1570 const Measure *measures,
1571 int32_t measureCount,
1572 UnicodeString& appendTo,
1573 FieldPosition& pos,
1574 UErrorCode& status) const {
1575 if (U_FAILURE(status)) {
1576 return appendTo;
1577 }
1578 FieldPosition dontCare(FieldPosition::DONT_CARE);
1579 FieldPosition fpos(pos.getField());
1580 UnicodeString *results = new UnicodeString[measureCount];
1581 int32_t fieldPositionFoundIndex = -1;
1582 for (int32_t i = 0; i < measureCount; ++i) {
1583 const NumberFormat *nf = cache->getIntegerFormat();
1584 if (i == measureCount - 1) {
1585 nf = numberFormat->get();
1586 }
1587 if (fieldPositionFoundIndex == -1) {
1588 formatMeasure(measures[i], *nf, results[i], fpos, status);
1589 if (U_FAILURE(status)) {
1590 delete [] results;
1591 return appendTo;
1592 }
1593 if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) {
1594 fieldPositionFoundIndex = i;
1595 }
1596 } else {
1597 formatMeasure(measures[i], *nf, results[i], dontCare, status);
1598 }
1599 }
1600 int32_t offset;
1601 listFormatter->format(
1602 results,
1603 measureCount,
1604 appendTo,
1605 fieldPositionFoundIndex,
1606 offset,
1607 status);
1608 if (U_FAILURE(status)) {
1609 delete [] results;
1610 return appendTo;
1611 }
1612 if (offset != -1) {
1613 pos.setBeginIndex(fpos.getBeginIndex() + offset);
1614 pos.setEndIndex(fpos.getEndIndex() + offset);
1615 }
1616 delete [] results;
1617 return appendTo;
1618 }
1619
1620 MeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(const Locale& locale,
1621 UErrorCode& ec) {
1622 CurrencyFormat* fmt = NULL;
1623 if (U_SUCCESS(ec)) {
1624 fmt = new CurrencyFormat(locale, ec);
1625 if (U_FAILURE(ec)) {
1626 delete fmt;
1627 fmt = NULL;
1628 }
1629 }
1630 return fmt;
1631 }
1632
1633 MeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(UErrorCode& ec) {
1634 if (U_FAILURE(ec)) {
1635 return NULL;
1636 }
1637 return MeasureFormat::createCurrencyFormat(Locale::getDefault(), ec);
1638 }
1639
1640 U_NAMESPACE_END
1641
1642 #endif /* #if !UCONFIG_NO_FORMATTING */