1b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*
2b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*******************************************************************************
350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho* Copyright (C) 2007-2010, International Business Machines Corporation and    *
4b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* others. All Rights Reserved.                                                *
5b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*******************************************************************************
6b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*/
7b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
8b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/utypes.h"
9b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
10b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#if !UCONFIG_NO_FORMATTING
11b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
12b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "zonemeta.h"
13b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
14b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/timezone.h"
15b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/ustring.h"
16b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/putil.h"
17b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
18b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "umutex.h"
19b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "uvector.h"
20b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "cmemory.h"
21b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "gregoimp.h"
22b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "cstring.h"
23b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "ucln_in.h"
2450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#include "uassert.h"
25b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
26b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic UMTX gZoneMetaLock = NULL;
2750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
2850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho// Metazone mapping table
29b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UHashtable *gOlsonToMeta = NULL;
30b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool gOlsonToMetaInitialized = FALSE;
31b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
3250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho// Country info vectors
3350294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostatic U_NAMESPACE_QUALIFIER UVector *gSingleZoneCountries = NULL;
3450294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostatic U_NAMESPACE_QUALIFIER UVector *gMultiZonesCountries = NULL;
3550294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostatic UBool gCountryInfoVectorsInitialized = FALSE;
36b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
3750294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoU_CDECL_BEGIN
38b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
39b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
40b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
41b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Cleanup callback func
42b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
43b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic UBool U_CALLCONV zoneMeta_cleanup(void)
44b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
45b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru     umtx_destroy(&gZoneMetaLock);
46b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
47b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (gOlsonToMeta != NULL) {
48b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        uhash_close(gOlsonToMeta);
49b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        gOlsonToMeta = NULL;
50b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
51b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    gOlsonToMetaInitialized = FALSE;
52b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
5350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    delete gSingleZoneCountries;
5450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    delete gMultiZonesCountries;
5550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    gCountryInfoVectorsInitialized = FALSE;
56b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
57b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return TRUE;
58b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
59b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
60b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
61b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * Deleter for UChar* string
62b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */
63b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic void U_CALLCONV
64b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QuerudeleteUCharString(void *obj) {
65b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UChar *entry = (UChar*)obj;
66b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_free(entry);
67b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
68b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
69b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/**
70b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Deleter for UVector
71b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
72b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic void U_CALLCONV
73b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QuerudeleteUVector(void *obj) {
74b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru   delete (U_NAMESPACE_QUALIFIER UVector*) obj;
75b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
76b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
77b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
78b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Deleter for OlsonToMetaMappingEntry
79b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
80b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic void U_CALLCONV
81b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QuerudeleteOlsonToMetaMappingEntry(void *obj) {
82b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    U_NAMESPACE_QUALIFIER OlsonToMetaMappingEntry *entry = (U_NAMESPACE_QUALIFIER OlsonToMetaMappingEntry*)obj;
83b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    uprv_free(entry);
84b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
85b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
86b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CDECL_END
87b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
88b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_NAMESPACE_BEGIN
89b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
90b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#define ZID_KEY_MAX 128
91b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
9250294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostatic const char gMetaZones[]          = "metaZones";
9350294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostatic const char gMetazoneInfo[]       = "metazoneInfo";
94b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const char gMapTimezonesTag[]    = "mapTimezones";
95b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
9627f654740f2a26ad62a5c155af9199af9e69b889clairehostatic const char gTimeZoneTypes[]      = "timezoneTypes";
9750294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostatic const char gTypeAliasTag[]       = "typeAlias";
9827f654740f2a26ad62a5c155af9199af9e69b889clairehostatic const char gTypeMapTag[]         = "typeMap";
9950294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostatic const char gTimezoneTag[]        = "timezone";
100b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
10150294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostatic const char gWorldTag[]           = "001";
102b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
103b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const UChar gWorld[] = {0x30, 0x30, 0x31, 0x00}; // "001"
104b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
10550294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostatic const UChar gDefaultFrom[] = {0x31, 0x39, 0x37, 0x30, 0x2D, 0x30, 0x31, 0x2D, 0x30, 0x31,
10650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                                     0x20, 0x30, 0x30, 0x3A, 0x30, 0x30, 0x00}; // "1970-01-01 00:00"
10750294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostatic const UChar gDefaultTo[]   = {0x39, 0x39, 0x39, 0x39, 0x2D, 0x31, 0x32, 0x2D, 0x33, 0x31,
10850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                                     0x20, 0x32, 0x33, 0x3A, 0x35, 0x39, 0x00}; // "9999-12-31 23:59"
10950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
110b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#define ASCII_DIGIT(c) (((c)>=0x30 && (c)<=0x39) ? (c)-0x30 : -1)
111b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
112b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*
113b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Convert a date string used by metazone mappings to UDate.
114b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * The format used by CLDR metazone mapping is "yyyy-MM-dd HH:mm".
115b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
116c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Querustatic UDate
117c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruparseDate (const UChar *text, UErrorCode &status) {
118b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
119b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
120b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
121b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t len = u_strlen(text);
122b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (len != 16 && len != 10) {
123b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // It must be yyyy-MM-dd HH:mm (length 16) or yyyy-MM-dd (length 10)
124b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        status = U_INVALID_FORMAT_ERROR;
125b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
126b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
127b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
128b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t year = 0, month = 0, day = 0, hour = 0, min = 0, n;
129b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t idx;
130b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
131b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // "yyyy" (0 - 3)
132b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    for (idx = 0; idx <= 3 && U_SUCCESS(status); idx++) {
133b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        n = ASCII_DIGIT((int32_t)text[idx]);
134b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (n >= 0) {
135b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            year = 10*year + n;
136b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
137b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            status = U_INVALID_FORMAT_ERROR;
138b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
139b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
140b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // "MM" (5 - 6)
141b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    for (idx = 5; idx <= 6 && U_SUCCESS(status); idx++) {
142b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        n = ASCII_DIGIT((int32_t)text[idx]);
143b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (n >= 0) {
144b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            month = 10*month + n;
145b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
146b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            status = U_INVALID_FORMAT_ERROR;
147b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
148b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
149b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // "dd" (8 - 9)
150b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    for (idx = 8; idx <= 9 && U_SUCCESS(status); idx++) {
151b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        n = ASCII_DIGIT((int32_t)text[idx]);
152b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (n >= 0) {
153b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            day = 10*day + n;
154b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
155b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            status = U_INVALID_FORMAT_ERROR;
156b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
157b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
158b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (len == 16) {
159b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // "HH" (11 - 12)
160b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        for (idx = 11; idx <= 12 && U_SUCCESS(status); idx++) {
161b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            n = ASCII_DIGIT((int32_t)text[idx]);
162b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (n >= 0) {
163b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                hour = 10*hour + n;
164b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            } else {
165b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                status = U_INVALID_FORMAT_ERROR;
166b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
167b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
168b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // "mm" (14 - 15)
169b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        for (idx = 14; idx <= 15 && U_SUCCESS(status); idx++) {
170b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            n = ASCII_DIGIT((int32_t)text[idx]);
171b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (n >= 0) {
172b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                min = 10*min + n;
173b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            } else {
174b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                status = U_INVALID_FORMAT_ERROR;
175b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
176b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
177b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
178b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
179b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_SUCCESS(status)) {
180b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UDate date = Grego::fieldsToDay(year, month - 1, day) * U_MILLIS_PER_DAY
181b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            + hour * U_MILLIS_PER_HOUR + min * U_MILLIS_PER_MINUTE;
182b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return date;
183b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
184b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return 0;
185b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
186b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
18750294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoUnicodeString& U_EXPORT2
18850294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoZoneMeta::getCanonicalSystemID(const UnicodeString &tzid, UnicodeString &systemID, UErrorCode& status) {
18927f654740f2a26ad62a5c155af9199af9e69b889claireho    int32_t len = tzid.length();
19027f654740f2a26ad62a5c155af9199af9e69b889claireho    if ( len >= ZID_KEY_MAX ) {
19127f654740f2a26ad62a5c155af9199af9e69b889claireho        status = U_ILLEGAL_ARGUMENT_ERROR;
19227f654740f2a26ad62a5c155af9199af9e69b889claireho        systemID.remove();
19327f654740f2a26ad62a5c155af9199af9e69b889claireho        return systemID;
19427f654740f2a26ad62a5c155af9199af9e69b889claireho    }
195c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
19627f654740f2a26ad62a5c155af9199af9e69b889claireho    char id[ZID_KEY_MAX];
19727f654740f2a26ad62a5c155af9199af9e69b889claireho    const UChar* idChars = tzid.getBuffer();
19827f654740f2a26ad62a5c155af9199af9e69b889claireho
19927f654740f2a26ad62a5c155af9199af9e69b889claireho    u_UCharsToChars(idChars,id,len);
20027f654740f2a26ad62a5c155af9199af9e69b889claireho    id[len] = (char) 0; // Make sure it is null terminated.
20127f654740f2a26ad62a5c155af9199af9e69b889claireho
20227f654740f2a26ad62a5c155af9199af9e69b889claireho    // replace '/' with ':'
20327f654740f2a26ad62a5c155af9199af9e69b889claireho    char *p = id;
20427f654740f2a26ad62a5c155af9199af9e69b889claireho    while (*p++) {
20527f654740f2a26ad62a5c155af9199af9e69b889claireho        if (*p == '/') {
20627f654740f2a26ad62a5c155af9199af9e69b889claireho            *p = ':';
20750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        }
208b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
20927f654740f2a26ad62a5c155af9199af9e69b889claireho
21027f654740f2a26ad62a5c155af9199af9e69b889claireho
21127f654740f2a26ad62a5c155af9199af9e69b889claireho    UErrorCode tmpStatus = U_ZERO_ERROR;
21227f654740f2a26ad62a5c155af9199af9e69b889claireho    UResourceBundle *top = ures_openDirect(NULL, gTimeZoneTypes, &tmpStatus);
21327f654740f2a26ad62a5c155af9199af9e69b889claireho    UResourceBundle *rb = ures_getByKey(top, gTypeMapTag, NULL, &tmpStatus);
21427f654740f2a26ad62a5c155af9199af9e69b889claireho    ures_getByKey(rb, gTimezoneTag, rb, &tmpStatus);
21527f654740f2a26ad62a5c155af9199af9e69b889claireho    ures_getByKey(rb, id, rb, &tmpStatus);
21627f654740f2a26ad62a5c155af9199af9e69b889claireho    if (U_SUCCESS(tmpStatus)) {
21727f654740f2a26ad62a5c155af9199af9e69b889claireho        // direct map found
21827f654740f2a26ad62a5c155af9199af9e69b889claireho        systemID.setTo(tzid);
21927f654740f2a26ad62a5c155af9199af9e69b889claireho        ures_close(rb);
22027f654740f2a26ad62a5c155af9199af9e69b889claireho        ures_close(top);
22127f654740f2a26ad62a5c155af9199af9e69b889claireho        return systemID;
22227f654740f2a26ad62a5c155af9199af9e69b889claireho    }
22327f654740f2a26ad62a5c155af9199af9e69b889claireho
22427f654740f2a26ad62a5c155af9199af9e69b889claireho    // If a map element not found, then look for an alias
22527f654740f2a26ad62a5c155af9199af9e69b889claireho    tmpStatus = U_ZERO_ERROR;
22627f654740f2a26ad62a5c155af9199af9e69b889claireho    ures_getByKey(top, gTypeAliasTag, rb, &tmpStatus);
22727f654740f2a26ad62a5c155af9199af9e69b889claireho    ures_getByKey(rb, gTimezoneTag, rb, &tmpStatus);
22827f654740f2a26ad62a5c155af9199af9e69b889claireho    const UChar *alias = ures_getStringByKey(rb,id,NULL,&tmpStatus);
22927f654740f2a26ad62a5c155af9199af9e69b889claireho    if (U_SUCCESS(tmpStatus)) {
23027f654740f2a26ad62a5c155af9199af9e69b889claireho        // alias found
23127f654740f2a26ad62a5c155af9199af9e69b889claireho        ures_close(rb);
23227f654740f2a26ad62a5c155af9199af9e69b889claireho        ures_close(top);
23327f654740f2a26ad62a5c155af9199af9e69b889claireho        systemID.setTo(alias);
23427f654740f2a26ad62a5c155af9199af9e69b889claireho        return systemID;
23527f654740f2a26ad62a5c155af9199af9e69b889claireho    }
23627f654740f2a26ad62a5c155af9199af9e69b889claireho
23727f654740f2a26ad62a5c155af9199af9e69b889claireho    // Dereference the input ID using the tz data
23827f654740f2a26ad62a5c155af9199af9e69b889claireho    const UChar *derefer = TimeZone::dereferOlsonLink(tzid);
23927f654740f2a26ad62a5c155af9199af9e69b889claireho    if (derefer == NULL) {
24050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        systemID.remove();
24150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        status = U_ILLEGAL_ARGUMENT_ERROR;
24250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    } else {
24327f654740f2a26ad62a5c155af9199af9e69b889claireho
24427f654740f2a26ad62a5c155af9199af9e69b889claireho        len = u_strlen(derefer);
24527f654740f2a26ad62a5c155af9199af9e69b889claireho        u_UCharsToChars(derefer,id,len);
24627f654740f2a26ad62a5c155af9199af9e69b889claireho        id[len] = (char) 0; // Make sure it is null terminated.
24727f654740f2a26ad62a5c155af9199af9e69b889claireho
24827f654740f2a26ad62a5c155af9199af9e69b889claireho        // replace '/' with ':'
24927f654740f2a26ad62a5c155af9199af9e69b889claireho        char *p = id;
25027f654740f2a26ad62a5c155af9199af9e69b889claireho        while (*p++) {
25127f654740f2a26ad62a5c155af9199af9e69b889claireho            if (*p == '/') {
25227f654740f2a26ad62a5c155af9199af9e69b889claireho                *p = ':';
25327f654740f2a26ad62a5c155af9199af9e69b889claireho            }
25427f654740f2a26ad62a5c155af9199af9e69b889claireho        }
25527f654740f2a26ad62a5c155af9199af9e69b889claireho
25627f654740f2a26ad62a5c155af9199af9e69b889claireho        // If a dereference turned something up then look for an alias.
25727f654740f2a26ad62a5c155af9199af9e69b889claireho        // rb still points to the alias table, so we don't have to go looking
25827f654740f2a26ad62a5c155af9199af9e69b889claireho        // for it.
25927f654740f2a26ad62a5c155af9199af9e69b889claireho        tmpStatus = U_ZERO_ERROR;
26027f654740f2a26ad62a5c155af9199af9e69b889claireho        const UChar *alias = ures_getStringByKey(rb,id,NULL,&tmpStatus);
26127f654740f2a26ad62a5c155af9199af9e69b889claireho        if (U_SUCCESS(tmpStatus)) {
26227f654740f2a26ad62a5c155af9199af9e69b889claireho            // alias found
26327f654740f2a26ad62a5c155af9199af9e69b889claireho            systemID.setTo(alias);
26427f654740f2a26ad62a5c155af9199af9e69b889claireho        } else {
26527f654740f2a26ad62a5c155af9199af9e69b889claireho            systemID.setTo(derefer);
26627f654740f2a26ad62a5c155af9199af9e69b889claireho        }
267b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
268b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
26927f654740f2a26ad62a5c155af9199af9e69b889claireho     ures_close(rb);
27027f654740f2a26ad62a5c155af9199af9e69b889claireho     ures_close(top);
27127f654740f2a26ad62a5c155af9199af9e69b889claireho     return systemID;
27250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
273b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
27450294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoUnicodeString& U_EXPORT2
27550294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoZoneMeta::getCanonicalCountry(const UnicodeString &tzid, UnicodeString &canonicalCountry) {
27650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    const UChar *region = TimeZone::getRegion(tzid);
27750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (u_strcmp(gWorld, region) != 0) {
27850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        canonicalCountry.setTo(region, -1);
27950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    } else {
28050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        canonicalCountry.remove();
28150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
28250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    return canonicalCountry;
28350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
284b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
28550294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoUnicodeString& U_EXPORT2
28650294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoZoneMeta::getSingleCountry(const UnicodeString &tzid, UnicodeString &country) {
28750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    // Get canonical country for the zone
28850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    const UChar *region = TimeZone::getRegion(tzid);
28950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (u_strcmp(gWorld, region) == 0) {
29050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // special case - "001"
29150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        country.remove();
29250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        return country;
29350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
294b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
29550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    // Checking the cached results
29650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UErrorCode status = U_ZERO_ERROR;
29750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UBool initialized;
29850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UMTX_CHECK(&gZoneMetaLock, gCountryInfoVectorsInitialized, initialized);
29950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (!initialized) {
30050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // Create empty vectors
30150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        umtx_lock(&gZoneMetaLock);
30250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        {
30350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (!gCountryInfoVectorsInitialized) {
30450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                // No deleters for these UVectors, it's a reference to a resource bundle string.
30550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                gSingleZoneCountries = new UVector(NULL, uhash_compareUChars, status);
30650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if (gSingleZoneCountries == NULL) {
30750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    status = U_MEMORY_ALLOCATION_ERROR;
30850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
30950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                gMultiZonesCountries = new UVector(NULL, uhash_compareUChars, status);
31050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if (gMultiZonesCountries == NULL) {
31150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    status = U_MEMORY_ALLOCATION_ERROR;
31250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
313b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
31450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if (U_SUCCESS(status)) {
31550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    gCountryInfoVectorsInitialized = TRUE;
31650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                } else {
31750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    delete gSingleZoneCountries;
31850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    delete gMultiZonesCountries;
31950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
32050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            }
321b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
32250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        umtx_unlock(&gZoneMetaLock);
323b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
324b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (U_FAILURE(status)) {
32550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            country.remove();
32650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            return country;
327b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
32850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
329b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
33050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    // Check if it was already cached
33150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UBool cached = FALSE;
33250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UBool multiZones = FALSE;
33350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    umtx_lock(&gZoneMetaLock);
33450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    {
33550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        multiZones = cached = gMultiZonesCountries->contains((void*)region);
33650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (!multiZones) {
33750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            cached = gSingleZoneCountries->contains((void*)region);
338c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
339c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
34050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    umtx_unlock(&gZoneMetaLock);
341c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
34250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (!cached) {
34350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // We need to go through all zones associated with the region.
34450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // This is relatively heavy operation.
34550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
34650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        U_ASSERT(u_strlen(region) == 2);
34750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
34850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        char buf[] = {0, 0, 0};
34950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        u_UCharsToChars(region, buf, 2);
35050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
35150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        StringEnumeration *ids = TimeZone::createEnumeration(buf);
35250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        int32_t idsLen = ids->count(status);
35350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (U_SUCCESS(status) && idsLen > 1) {
35450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            // multiple zones are available for the region
35550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            UnicodeString canonical, tmp;
35650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            const UnicodeString *id = ids->snext(status);
35750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            getCanonicalSystemID(*id, canonical, status);
35850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (U_SUCCESS(status)) {
35950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                // check if there are any other canonical zone in the group
36027f654740f2a26ad62a5c155af9199af9e69b889claireho                while ((id = ids->snext(status))!=NULL) {
36150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    getCanonicalSystemID(*id, tmp, status);
36250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    if (U_FAILURE(status)) {
36350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        break;
36450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    }
36550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    if (canonical != tmp) {
36650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        // another canonical zone was found
36750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        multiZones = TRUE;
36850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        break;
36950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    }
370c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                }
371c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            }
37250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        }
37350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (U_FAILURE(status)) {
37450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            // no single country by default for any error cases
37550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            multiZones = TRUE;
37650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        }
37750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        delete ids;
37850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
37950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // Cache the result
38050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        umtx_lock(&gZoneMetaLock);
38150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        {
38250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            UErrorCode ec = U_ZERO_ERROR;
38350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (multiZones) {
38450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if (!gMultiZonesCountries->contains((void*)region)) {
38550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    gMultiZonesCountries->addElement((void*)region, ec);
386c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                }
387c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            } else {
38850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if (!gSingleZoneCountries->contains((void*)region)) {
38950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    gSingleZoneCountries->addElement((void*)region, ec);
39050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
391b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
392b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
39350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        umtx_unlock(&gZoneMetaLock);
394b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
395b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
39650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (multiZones) {
39750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        country.remove();
39850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    } else {
39950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        country.setTo(region, -1);
400b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
40150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    return country;
402b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
403b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
40450294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoUnicodeString& U_EXPORT2
40550294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoZoneMeta::getMetazoneID(const UnicodeString &tzid, UDate date, UnicodeString &result) {
40650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UBool isSet = FALSE;
40750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    const UVector *mappings = getMetazoneMappings(tzid);
40850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (mappings != NULL) {
40950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        for (int32_t i = 0; i < mappings->size(); i++) {
41050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            OlsonToMetaMappingEntry *mzm = (OlsonToMetaMappingEntry*)mappings->elementAt(i);
41150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (mzm->from <= date && mzm->to > date) {
41250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                result.setTo(mzm->mzid, -1);
41350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                isSet = TRUE;
414b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                break;
415b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
416b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
417b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
41850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (!isSet) {
41950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        result.remove();
420b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
42150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    return result;
422b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
423b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
42450294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoconst UVector* U_EXPORT2
42550294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoZoneMeta::getMetazoneMappings(const UnicodeString &tzid) {
426b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UErrorCode status = U_ZERO_ERROR;
42750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UChar tzidUChars[ZID_KEY_MAX];
42850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    tzid.extract(tzidUChars, ZID_KEY_MAX, status);
42950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
430b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return NULL;
431b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
432b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
43350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UBool initialized;
43450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UMTX_CHECK(&gZoneMetaLock, gOlsonToMetaInitialized, initialized);
43550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (!initialized) {
43650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        UHashtable *tmpOlsonToMeta = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
437b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (U_FAILURE(status)) {
43850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            return NULL;
439b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
44050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        uhash_setKeyDeleter(tmpOlsonToMeta, deleteUCharString);
44150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        uhash_setValueDeleter(tmpOlsonToMeta, deleteUVector);
44250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
44350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        umtx_lock(&gZoneMetaLock);
44450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        {
44550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (!gOlsonToMetaInitialized) {
44650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                gOlsonToMeta = tmpOlsonToMeta;
44750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                tmpOlsonToMeta = NULL;
44850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                gOlsonToMetaInitialized = TRUE;
449b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
450b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
45150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        umtx_unlock(&gZoneMetaLock);
452b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
45350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // OK to call the following multiple times with the same function
45450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup);
45550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (tmpOlsonToMeta != NULL) {
45650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            uhash_close(tmpOlsonToMeta);
45750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        }
458b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
459b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
46050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    // get the mapping from cache
46150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    const UVector *result = NULL;
462b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
463b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    umtx_lock(&gZoneMetaLock);
46450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    {
46550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        result = (UVector*) uhash_get(gOlsonToMeta, tzidUChars);
466b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
467b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    umtx_unlock(&gZoneMetaLock);
468b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
46950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (result != NULL) {
47050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        return result;
471b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
472c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
47350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    // miss the cache - create new one
47450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UVector *tmpResult = createMetazoneMappings(tzid);
47550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (tmpResult == NULL) {
47650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // not available
47750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        return NULL;
478b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
479c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
48050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    // put the new one into the cache
481c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    umtx_lock(&gZoneMetaLock);
48250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    {
48350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // make sure it's already created
48450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        result = (UVector*) uhash_get(gOlsonToMeta, tzidUChars);
48550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (result == NULL) {
48650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            // add the one just created
48750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            int32_t tzidLen = tzid.length() + 1;
48850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            UChar *key = (UChar*)uprv_malloc(tzidLen * sizeof(UChar));
48950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (key == NULL) {
49050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                // memory allocation error..  just return NULL
49150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                result = NULL;
49250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                delete tmpResult;
49350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            } else {
49450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                tzid.extract(key, tzidLen, status);
49550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                uhash_put(gOlsonToMeta, key, tmpResult, &status);
49650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if (U_FAILURE(status)) {
49750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    // delete the mapping
49850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    result = NULL;
49950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    delete tmpResult;
50050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                } else {
50150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    result = tmpResult;
50250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
50350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            }
50450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        } else {
50550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            // another thread already put the one
50650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            delete tmpResult;
50750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        }
508b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
509b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    umtx_unlock(&gZoneMetaLock);
510b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
51150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    return result;
512c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru}
513c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
51450294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoUVector*
51550294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoZoneMeta::createMetazoneMappings(const UnicodeString &tzid) {
51650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UVector *mzMappings = NULL;
51750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UErrorCode status = U_ZERO_ERROR;
518b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
51950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UnicodeString canonicalID;
52050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UResourceBundle *rb = ures_openDirect(NULL, gMetaZones, &status);
52150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ures_getByKey(rb, gMetazoneInfo, rb, &status);
52250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    TimeZone::getCanonicalID(tzid, canonicalID, status);
523b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
52450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (U_SUCCESS(status)) {
52550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        char tzKey[ZID_KEY_MAX];
52650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        canonicalID.extract(0, canonicalID.length(), tzKey, sizeof(tzKey), US_INV);
52750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
52850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // tzid keys are using ':' as separators
52950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        char *p = tzKey;
53050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        while (*p) {
53150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (*p == '/') {
53250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                *p = ':';
53350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            }
53450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            p++;
535b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
536b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
53750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        ures_getByKey(rb, tzKey, rb, &status);
538b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
53950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (U_SUCCESS(status)) {
54050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            UResourceBundle *mz = NULL;
54150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            while (ures_hasNext(rb)) {
54250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                mz = ures_getNextResource(rb, mz, &status);
543b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
54450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                const UChar *mz_name = ures_getStringByIndex(mz, 0, NULL, &status);
54550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                const UChar *mz_from = gDefaultFrom;
54650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                const UChar *mz_to = gDefaultTo;
547b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
54850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if (ures_getSize(mz) == 3) {
54950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    mz_from = ures_getStringByIndex(mz, 1, NULL, &status);
55050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    mz_to   = ures_getStringByIndex(mz, 2, NULL, &status);
55150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
55250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
55350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if(U_FAILURE(status)){
55450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    status = U_ZERO_ERROR;
55550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    continue;
55650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
55750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                // We do not want to use SimpleDateformat to parse boundary dates,
55850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                // because this code could be triggered by the initialization code
55950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                // used by SimpleDateFormat.
56050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                UDate from = parseDate(mz_from, status);
56150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                UDate to = parseDate(mz_to, status);
56250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if (U_FAILURE(status)) {
56350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    status = U_ZERO_ERROR;
56450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    continue;
56550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
56650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
56750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                OlsonToMetaMappingEntry *entry = (OlsonToMetaMappingEntry*)uprv_malloc(sizeof(OlsonToMetaMappingEntry));
56850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if (entry == NULL) {
56950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    status = U_MEMORY_ALLOCATION_ERROR;
570b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    break;
571b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
57250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                entry->mzid = mz_name;
57350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                entry->from = from;
57450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                entry->to = to;
57550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
57650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if (mzMappings == NULL) {
57750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    mzMappings = new UVector(deleteOlsonToMetaMappingEntry, NULL, status);
57850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    if (U_FAILURE(status)) {
57950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        delete mzMappings;
58050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        deleteOlsonToMetaMappingEntry(entry);
58150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        uprv_free(entry);
58250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        break;
58350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    }
58450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
58550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
58650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                mzMappings->addElement(entry, status);
58750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if (U_FAILURE(status)) {
58850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    break;
58950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
59050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            }
59150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            ures_close(mz);
59250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (U_FAILURE(status)) {
59350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if (mzMappings != NULL) {
59450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    delete mzMappings;
59550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    mzMappings = NULL;
59650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
597b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
598b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
599b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
60050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ures_close(rb);
60150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    return mzMappings;
602b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
603b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
604c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste QueruUnicodeString& U_EXPORT2
60550294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoZoneMeta::getZoneIdByMetazone(const UnicodeString &mzid, const UnicodeString &region, UnicodeString &result) {
60650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UErrorCode status = U_ZERO_ERROR;
60750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    const UChar *tzid = NULL;
60850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    int32_t tzidLen = 0;
60950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    char keyBuf[ZID_KEY_MAX + 1];
61050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    int32_t keyLen = 0;
61150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
61250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (mzid.length() >= ZID_KEY_MAX) {
613b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        result.remove();
61450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        return result;
615b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
616b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
61750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    keyLen = mzid.extract(0, mzid.length(), keyBuf, ZID_KEY_MAX, US_INV);
618b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
61950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UResourceBundle *rb = ures_openDirect(NULL, gMetaZones, &status);
62050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ures_getByKey(rb, gMapTimezonesTag, rb, &status);
62150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ures_getByKey(rb, keyBuf, rb, &status);
62250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
62350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (U_SUCCESS(status)) {
62450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // check region mapping
62550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (region.length() == 2 || region.length() == 3) {
62650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            region.extract(0, region.length(), keyBuf, ZID_KEY_MAX, US_INV);
62750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            tzid = ures_getStringByKey(rb, keyBuf, &tzidLen, &status);
62850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (status == U_MISSING_RESOURCE_ERROR) {
62950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                status = U_ZERO_ERROR;
630b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
631b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
63250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (U_SUCCESS(status) && tzid == NULL) {
63350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            // try "001"
63450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            tzid = ures_getStringByKey(rb, gWorldTag, &tzidLen, &status);
63550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        }
636b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
63750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ures_close(rb);
63850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
63950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (tzid == NULL) {
640b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        result.remove();
64150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    } else {
64250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        result.setTo(tzid, tzidLen);
643b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
64450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
645b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return result;
646b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
647b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
648b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_NAMESPACE_END
649b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
650b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif /* #if !UCONFIG_NO_FORMATTING */
651