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