1/*
2**********************************************************************
3* Copyright (c) 2004-2014, International Business Machines
4* Corporation and others.  All Rights Reserved.
5**********************************************************************
6* Author: Alan Liu
7* Created: April 26, 2004
8* Since: ICU 3.0
9**********************************************************************
10*/
11#include "utypeinfo.h" // for 'typeid' to work
12
13#include "unicode/measunit.h"
14
15#if !UCONFIG_NO_FORMATTING
16
17#include "unicode/uenum.h"
18#include "ustrenum.h"
19#include "cstring.h"
20#include "uassert.h"
21
22#define LENGTHOF(array) ((int32_t)(sizeof(array) / sizeof((array)[0])))
23
24U_NAMESPACE_BEGIN
25
26UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MeasureUnit)
27
28static const int32_t gOffsets[] = {
29    0,
30    1,
31    4,
32    10,
33    270,
34    278,
35    288,
36    293,    // Apple adjustments from here
37    296,
38    299,
39    302,
40    304,
41    307,
42    312     // Apple addition
43};
44
45static const int32_t gIndexes[] = {
46    0,
47    1,
48    4,
49    10,
50    10,
51    18,
52    28,
53    33,     // Apple adjustments from here
54    36,
55    39,
56    42,
57    44,
58    47,
59    52      // Apple addition
60};
61
62static const char * const gTypes[] = {
63    "acceleration",
64    "angle",
65    "area",
66    "currency",
67    "duration",
68    "length",
69    "mass",
70    "power",
71    "pressure",
72    "speed",
73    "temperature",
74    "volume",
75    "energy"        // Apple addition, out of order, handle specially
76};
77
78static const char * const gSubTypes[] = {
79    "g-force",          // 0 acceleration
80    "arc-minute",       // 1 angle
81    "arc-second",
82    "degree",
83    "acre",             // 4 area
84    "hectare",
85    "square-foot",
86    "square-kilometer",
87    "square-meter",
88    "square-mile",
89    "ADP",              // 10 currency
90    "AED",
91    "AFA",
92    "AFN",
93    "ALL",
94    "AMD",
95    "ANG",
96    "AOA",
97    "AON",
98    "AOR",
99    "ARA",
100    "ARP",
101    "ARS",
102    "ATS",
103    "AUD",
104    "AWG",
105    "AYM",
106    "AZM",
107    "AZN",
108    "BAD",
109    "BAM",
110    "BBD",
111    "BDT",
112    "BEC",
113    "BEF",
114    "BEL",
115    "BGL",
116    "BGN",
117    "BHD",
118    "BIF",
119    "BMD",
120    "BND",
121    "BOB",
122    "BOV",
123    "BRC",
124    "BRE",
125    "BRL",
126    "BRN",
127    "BRR",
128    "BSD",
129    "BTN",
130    "BWP",
131    "BYB",
132    "BYR",
133    "BZD",
134    "CAD",
135    "CDF",
136    "CHC",
137    "CHE",
138    "CHF",
139    "CHW",
140    "CLF",
141    "CLP",
142    "CNY",
143    "COP",
144    "COU",
145    "CRC",
146    "CSD",
147    "CSK",
148    "CUC",
149    "CUP",
150    "CVE",
151    "CYP",
152    "CZK",
153    "DDM",
154    "DEM",
155    "DJF",
156    "DKK",
157    "DOP",
158    "DZD",
159    "ECS",
160    "ECV",
161    "EEK",
162    "EGP",
163    "ERN",
164    "ESA",
165    "ESB",
166    "ESP",
167    "ETB",
168    "EUR",
169    "FIM",
170    "FJD",
171    "FKP",
172    "FRF",
173    "GBP",
174    "GEK",
175    "GEL",
176    "GHC",
177    "GHP",
178    "GHS",
179    "GIP",
180    "GMD",
181    "GNF",
182    "GQE",
183    "GRD",
184    "GTQ",
185    "GWP",
186    "GYD",
187    "HKD",
188    "HNL",
189    "HRD",
190    "HRK",
191    "HTG",
192    "HUF",
193    "IDR",
194    "IEP",
195    "ILS",
196    "INR",
197    "IQD",
198    "IRR",
199    "ISK",
200    "ITL",
201    "JMD",
202    "JOD",
203    "JPY",
204    "KES",
205    "KGS",
206    "KHR",
207    "KMF",
208    "KPW",
209    "KRW",
210    "KWD",
211    "KYD",
212    "KZT",
213    "LAK",
214    "LBP",
215    "LKR",
216    "LRD",
217    "LSL",
218    "LTL",
219    "LTT",
220    "LUC",
221    "LUF",
222    "LUL",
223    "LVL",
224    "LVR",
225    "LYD",
226    "MAD",
227    "MDL",
228    "MGA",
229    "MGF",
230    "MKD",
231    "MLF",
232    "MMK",
233    "MNT",
234    "MOP",
235    "MRO",
236    "MTL",
237    "MUR",
238    "MVR",
239    "MWK",
240    "MXN",
241    "MXV",
242    "MYR",
243    "MZM",
244    "MZN",
245    "NAD",
246    "NGN",
247    "NIO",
248    "NLG",
249    "NOK",
250    "NPR",
251    "NZD",
252    "OMR",
253    "PAB",
254    "PEI",
255    "PEN",
256    "PES",
257    "PGK",
258    "PHP",
259    "PKR",
260    "PLN",
261    "PLZ",
262    "PTE",
263    "PYG",
264    "QAR",
265    "ROL",
266    "RON",
267    "RSD",
268    "RUB",
269    "RUR",
270    "RWF",
271    "SAR",
272    "SBD",
273    "SCR",
274    "SDD",
275    "SDG",
276    "SEK",
277    "SGD",
278    "SHP",
279    "SIT",
280    "SKK",
281    "SLL",
282    "SOS",
283    "SRD",
284    "SRG",
285    "SSP",
286    "STD",
287    "SVC",
288    "SYP",
289    "SZL",
290    "THB",
291    "TJR",
292    "TJS",
293    "TMM",
294    "TMT",
295    "TND",
296    "TOP",
297    "TPE",
298    "TRL",
299    "TRY",
300    "TTD",
301    "TWD",
302    "TZS",
303    "UAH",
304    "UAK",
305    "UGX",
306    "USD",
307    "USN",
308    "USS",
309    "UYI",
310    "UYU",
311    "UZS",
312    "VEB",
313    "VEF",
314    "VND",
315    "VUV",
316    "WST",
317    "XAF",
318    "XAG",
319    "XAU",
320    "XBA",
321    "XBB",
322    "XBC",
323    "XBD",
324    "XCD",
325    "XDR",
326    "XEU",
327    "XOF",
328    "XPD",
329    "XPF",
330    "XPT",
331    "XSU",
332    "XTS",
333    "XUA",
334    "XXX",
335    "YDD",
336    "YER",
337    "YUM",
338    "YUN",
339    "ZAL",
340    "ZAR",
341    "ZMK",
342    "ZMW",
343    "ZRN",
344    "ZRZ",
345    "ZWD",
346    "ZWL",
347    "ZWN",
348    "ZWR",
349    "day",              // 270 duration
350    "hour",
351    "millisecond",
352    "minute",
353    "month",
354    "second",
355    "week",
356    "year",
357    "centimeter",       // 278 length
358    "foot",
359    "inch",
360    "kilometer",
361    "light-year",
362    "meter",
363    "mile",
364    "millimeter",
365    "picometer",
366    "yard",
367    "gram",             // 288 mass
368    "kilogram",
369    "ounce",
370    "pound",
371    "stone",            // Apple addition
372    "horsepower",       // 293 power
373    "kilowatt",
374    "watt",
375    "hectopascal",      // 296 pressure
376    "inch-hg",
377    "millibar",
378    "kilometer-per-hour",   // 299 speed
379    "meter-per-second",
380    "mile-per-hour",
381    "celsius",          // 302 temperature
382    "fahrenheit",
383    "cubic-kilometer",  // 304 volume
384    "cubic-mile",
385    "liter",
386    "calorie",          // 307 energy Apple additions
387    "foodcalorie",
388    "joule",
389    "kilocalorie",
390    "kilojoule"
391};                      // 312
392
393MeasureUnit *MeasureUnit::createGForce(UErrorCode &status) {
394    return MeasureUnit::create(0, 0, status);
395}
396
397MeasureUnit *MeasureUnit::createArcMinute(UErrorCode &status) {
398    return MeasureUnit::create(1, 0, status);
399}
400
401MeasureUnit *MeasureUnit::createArcSecond(UErrorCode &status) {
402    return MeasureUnit::create(1, 1, status);
403}
404
405MeasureUnit *MeasureUnit::createDegree(UErrorCode &status) {
406    return MeasureUnit::create(1, 2, status);
407}
408
409MeasureUnit *MeasureUnit::createAcre(UErrorCode &status) {
410    return MeasureUnit::create(2, 0, status);
411}
412
413MeasureUnit *MeasureUnit::createHectare(UErrorCode &status) {
414    return MeasureUnit::create(2, 1, status);
415}
416
417MeasureUnit *MeasureUnit::createSquareFoot(UErrorCode &status) {
418    return MeasureUnit::create(2, 2, status);
419}
420
421MeasureUnit *MeasureUnit::createSquareKilometer(UErrorCode &status) {
422    return MeasureUnit::create(2, 3, status);
423}
424
425MeasureUnit *MeasureUnit::createSquareMeter(UErrorCode &status) {
426    return MeasureUnit::create(2, 4, status);
427}
428
429MeasureUnit *MeasureUnit::createSquareMile(UErrorCode &status) {
430    return MeasureUnit::create(2, 5, status);
431}
432
433MeasureUnit *MeasureUnit::createDay(UErrorCode &status) {
434    return MeasureUnit::create(4, 0, status);
435}
436
437MeasureUnit *MeasureUnit::createHour(UErrorCode &status) {
438    return MeasureUnit::create(4, 1, status);
439}
440
441MeasureUnit *MeasureUnit::createMillisecond(UErrorCode &status) {
442    return MeasureUnit::create(4, 2, status);
443}
444
445MeasureUnit *MeasureUnit::createMinute(UErrorCode &status) {
446    return MeasureUnit::create(4, 3, status);
447}
448
449MeasureUnit *MeasureUnit::createMonth(UErrorCode &status) {
450    return MeasureUnit::create(4, 4, status);
451}
452
453MeasureUnit *MeasureUnit::createSecond(UErrorCode &status) {
454    return MeasureUnit::create(4, 5, status);
455}
456
457MeasureUnit *MeasureUnit::createWeek(UErrorCode &status) {
458    return MeasureUnit::create(4, 6, status);
459}
460
461MeasureUnit *MeasureUnit::createYear(UErrorCode &status) {
462    return MeasureUnit::create(4, 7, status);
463}
464
465MeasureUnit *MeasureUnit::createCentimeter(UErrorCode &status) {
466    return MeasureUnit::create(5, 0, status);
467}
468
469MeasureUnit *MeasureUnit::createFoot(UErrorCode &status) {
470    return MeasureUnit::create(5, 1, status);
471}
472
473MeasureUnit *MeasureUnit::createInch(UErrorCode &status) {
474    return MeasureUnit::create(5, 2, status);
475}
476
477MeasureUnit *MeasureUnit::createKilometer(UErrorCode &status) {
478    return MeasureUnit::create(5, 3, status);
479}
480
481MeasureUnit *MeasureUnit::createLightYear(UErrorCode &status) {
482    return MeasureUnit::create(5, 4, status);
483}
484
485MeasureUnit *MeasureUnit::createMeter(UErrorCode &status) {
486    return MeasureUnit::create(5, 5, status);
487}
488
489MeasureUnit *MeasureUnit::createMile(UErrorCode &status) {
490    return MeasureUnit::create(5, 6, status);
491}
492
493MeasureUnit *MeasureUnit::createMillimeter(UErrorCode &status) {
494    return MeasureUnit::create(5, 7, status);
495}
496
497MeasureUnit *MeasureUnit::createPicometer(UErrorCode &status) {
498    return MeasureUnit::create(5, 8, status);
499}
500
501MeasureUnit *MeasureUnit::createYard(UErrorCode &status) {
502    return MeasureUnit::create(5, 9, status);
503}
504
505MeasureUnit *MeasureUnit::createGram(UErrorCode &status) {
506    return MeasureUnit::create(6, 0, status);
507}
508
509MeasureUnit *MeasureUnit::createKilogram(UErrorCode &status) {
510    return MeasureUnit::create(6, 1, status);
511}
512
513MeasureUnit *MeasureUnit::createOunce(UErrorCode &status) {
514    return MeasureUnit::create(6, 2, status);
515}
516
517MeasureUnit *MeasureUnit::createPound(UErrorCode &status) {
518    return MeasureUnit::create(6, 3, status);
519}
520
521MeasureUnit *MeasureUnit::createStone(UErrorCode &status) {
522    return MeasureUnit::create(6, 4, status);
523}
524
525MeasureUnit *MeasureUnit::createHorsepower(UErrorCode &status) {
526    return MeasureUnit::create(7, 0, status);
527}
528
529MeasureUnit *MeasureUnit::createKilowatt(UErrorCode &status) {
530    return MeasureUnit::create(7, 1, status);
531}
532
533MeasureUnit *MeasureUnit::createWatt(UErrorCode &status) {
534    return MeasureUnit::create(7, 2, status);
535}
536
537MeasureUnit *MeasureUnit::createHectopascal(UErrorCode &status) {
538    return MeasureUnit::create(8, 0, status);
539}
540
541MeasureUnit *MeasureUnit::createInchHg(UErrorCode &status) {
542    return MeasureUnit::create(8, 1, status);
543}
544
545MeasureUnit *MeasureUnit::createMillibar(UErrorCode &status) {
546    return MeasureUnit::create(8, 2, status);
547}
548
549MeasureUnit *MeasureUnit::createKilometerPerHour(UErrorCode &status) {
550    return MeasureUnit::create(9, 0, status);
551}
552
553MeasureUnit *MeasureUnit::createMeterPerSecond(UErrorCode &status) {
554    return MeasureUnit::create(9, 1, status);
555}
556
557MeasureUnit *MeasureUnit::createMilePerHour(UErrorCode &status) {
558    return MeasureUnit::create(9, 2, status);
559}
560
561MeasureUnit *MeasureUnit::createCelsius(UErrorCode &status) {
562    return MeasureUnit::create(10, 0, status);
563}
564
565MeasureUnit *MeasureUnit::createFahrenheit(UErrorCode &status) {
566    return MeasureUnit::create(10, 1, status);
567}
568
569MeasureUnit *MeasureUnit::createCubicKilometer(UErrorCode &status) {
570    return MeasureUnit::create(11, 0, status);
571}
572
573MeasureUnit *MeasureUnit::createCubicMile(UErrorCode &status) {
574    return MeasureUnit::create(11, 1, status);
575}
576
577MeasureUnit *MeasureUnit::createLiter(UErrorCode &status) {
578    return MeasureUnit::create(11, 2, status);
579}
580
581MeasureUnit *MeasureUnit::createCalorie(UErrorCode &status) {
582    return MeasureUnit::create(12, 0, status);
583}
584
585MeasureUnit *MeasureUnit::createFoodcalorie(UErrorCode &status) {
586    return MeasureUnit::create(12, 1, status);
587}
588
589MeasureUnit *MeasureUnit::createJoule(UErrorCode &status) {
590    return MeasureUnit::create(12, 2, status);
591}
592
593MeasureUnit *MeasureUnit::createKilocalorie(UErrorCode &status) {
594    return MeasureUnit::create(12, 3, status);
595}
596
597MeasureUnit *MeasureUnit::createKilojoule(UErrorCode &status) {
598    return MeasureUnit::create(12, 4, status);
599}
600
601
602static int32_t binarySearch(
603        const char * const * array, int32_t start, int32_t end, const char * key) {
604    while (start < end) {
605        int32_t mid = (start + end) / 2;
606        int32_t cmp = uprv_strcmp(array[mid], key);
607        if (cmp < 0) {
608            start = mid + 1;
609            continue;
610        }
611        if (cmp == 0) {
612            return mid;
613        }
614        end = mid;
615    }
616    return -1;
617}
618
619MeasureUnit::MeasureUnit(const MeasureUnit &other)
620        : fTypeId(other.fTypeId), fSubTypeId(other.fSubTypeId) {
621    uprv_strcpy(fCurrency, other.fCurrency);
622}
623
624MeasureUnit &MeasureUnit::operator=(const MeasureUnit &other) {
625    if (this == &other) {
626        return *this;
627    }
628    fTypeId = other.fTypeId;
629    fSubTypeId = other.fSubTypeId;
630    uprv_strcpy(fCurrency, other.fCurrency);
631    return *this;
632}
633
634UObject *MeasureUnit::clone() const {
635    return new MeasureUnit(*this);
636}
637
638MeasureUnit::~MeasureUnit() {
639}
640
641const char *MeasureUnit::getType() const {
642    return gTypes[fTypeId];
643}
644
645const char *MeasureUnit::getSubtype() const {
646    return fCurrency[0] == 0 ? gSubTypes[getOffset()] : fCurrency;
647}
648
649UBool MeasureUnit::operator==(const UObject& other) const {
650    if (this == &other) {  // Same object, equal
651        return TRUE;
652    }
653    if (typeid(*this) != typeid(other)) { // Different types, not equal
654        return FALSE;
655    }
656    const MeasureUnit &rhs = static_cast<const MeasureUnit&>(other);
657    return (
658            fTypeId == rhs.fTypeId
659            && fSubTypeId == rhs.fSubTypeId
660            && uprv_strcmp(fCurrency, rhs.fCurrency) == 0);
661}
662
663int32_t MeasureUnit::getIndex() const {
664    return gIndexes[fTypeId] + fSubTypeId;
665}
666
667int32_t MeasureUnit::getAvailable(
668        MeasureUnit *dest,
669        int32_t destCapacity,
670        UErrorCode &errorCode) {
671    if (U_FAILURE(errorCode)) {
672        return 0;
673    }
674    if (destCapacity < LENGTHOF(gSubTypes)) {
675        errorCode = U_BUFFER_OVERFLOW_ERROR;
676        return LENGTHOF(gSubTypes);
677    }
678    int32_t idx = 0;
679    for (int32_t typeIdx = 0; typeIdx < LENGTHOF(gTypes); ++typeIdx) {
680        int32_t len = gOffsets[typeIdx + 1] - gOffsets[typeIdx];
681        for (int32_t subTypeIdx = 0; subTypeIdx < len; ++subTypeIdx) {
682            dest[idx].setTo(typeIdx, subTypeIdx);
683            ++idx;
684        }
685    }
686    U_ASSERT(idx == LENGTHOF(gSubTypes));
687    return LENGTHOF(gSubTypes);
688}
689
690int32_t MeasureUnit::getAvailable(
691        const char *type,
692        MeasureUnit *dest,
693        int32_t destCapacity,
694        UErrorCode &errorCode) {
695    if (U_FAILURE(errorCode)) {
696        return 0;
697    }
698    int32_t typeIdx = binarySearch(gTypes, 0, LENGTHOF(gTypes)-1, type);
699    if (typeIdx == -1) {
700        if (uprv_strcmp(type, gTypes[LENGTHOF(gTypes)-1]) == 0) {
701            typeIdx = LENGTHOF(gTypes)-1;
702        } else {
703            return 0;
704        }
705    }
706    int32_t len = gOffsets[typeIdx + 1] - gOffsets[typeIdx];
707    if (destCapacity < len) {
708        errorCode = U_BUFFER_OVERFLOW_ERROR;
709        return len;
710    }
711    for (int subTypeIdx = 0; subTypeIdx < len; ++subTypeIdx) {
712        dest[subTypeIdx].setTo(typeIdx, subTypeIdx);
713    }
714    return len;
715}
716
717StringEnumeration* MeasureUnit::getAvailableTypes(UErrorCode &errorCode) {
718    UEnumeration *uenum = uenum_openCharStringsEnumeration(
719            gTypes, LENGTHOF(gTypes), &errorCode);
720    if (U_FAILURE(errorCode)) {
721        uenum_close(uenum);
722        return NULL;
723    }
724    StringEnumeration *result = new UStringEnumeration(uenum);
725    if (result == NULL) {
726        errorCode = U_MEMORY_ALLOCATION_ERROR;
727        uenum_close(uenum);
728        return NULL;
729    }
730    return result;
731}
732
733int32_t MeasureUnit::getIndexCount() {
734    return gIndexes[LENGTHOF(gIndexes) - 1];
735}
736
737MeasureUnit *MeasureUnit::create(int typeId, int subTypeId, UErrorCode &status) {
738    if (U_FAILURE(status)) {
739        return NULL;
740    }
741    MeasureUnit *result = new MeasureUnit(typeId, subTypeId);
742    if (result == NULL) {
743        status = U_MEMORY_ALLOCATION_ERROR;
744    }
745    return result;
746}
747
748void MeasureUnit::initTime(const char *timeId) {
749    int32_t result = binarySearch(gTypes, 0, LENGTHOF(gTypes)-1, "duration"); // Apple mod
750    U_ASSERT(result != -1);
751    fTypeId = result;
752    result = binarySearch(gSubTypes, gOffsets[fTypeId], gOffsets[fTypeId + 1], timeId);
753    U_ASSERT(result != -1);
754    fSubTypeId = result - gOffsets[fTypeId];
755}
756
757void MeasureUnit::initCurrency(const char *isoCurrency) {
758    int32_t result = binarySearch(gTypes, 0, LENGTHOF(gTypes)-1, "currency"); // Apple mod
759    U_ASSERT(result != -1);
760    fTypeId = result;
761    result = binarySearch(
762            gSubTypes, gOffsets[fTypeId], gOffsets[fTypeId + 1], isoCurrency);
763    if (result != -1) {
764        fSubTypeId = result - gOffsets[fTypeId];
765    } else {
766        uprv_strncpy(fCurrency, isoCurrency, LENGTHOF(fCurrency));
767    }
768}
769
770void MeasureUnit::setTo(int32_t typeId, int32_t subTypeId) {
771    fTypeId = typeId;
772    fSubTypeId = subTypeId;
773    fCurrency[0] = 0;
774}
775
776int32_t MeasureUnit::getOffset() const {
777    return gOffsets[fTypeId] + fSubTypeId;
778}
779
780U_NAMESPACE_END
781
782#endif /* !UNCONFIG_NO_FORMATTING */
783