tznames_impl.cpp 75 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308
  1. // © 2016 and later: Unicode, Inc. and others.
  2. // License & terms of use: http://www.unicode.org/copyright.html
  3. /*
  4. *******************************************************************************
  5. * Copyright (C) 2011-2016, International Business Machines Corporation and
  6. * others. All Rights Reserved.
  7. *******************************************************************************
  8. *
  9. * File TZNAMES_IMPL.CPP
  10. *
  11. *******************************************************************************
  12. */
  13. #include "unicode/utypes.h"
  14. #if !UCONFIG_NO_FORMATTING
  15. #include "unicode/strenum.h"
  16. #include "unicode/ustring.h"
  17. #include "unicode/timezone.h"
  18. #include "unicode/utf16.h"
  19. #include "tznames_impl.h"
  20. #include "bytesinkutil.h"
  21. #include "charstr.h"
  22. #include "cmemory.h"
  23. #include "cstring.h"
  24. #include "uassert.h"
  25. #include "mutex.h"
  26. #include "resource.h"
  27. #include "ulocimp.h"
  28. #include "uresimp.h"
  29. #include "ureslocs.h"
  30. #include "zonemeta.h"
  31. #include "ucln_in.h"
  32. #include "uvector.h"
  33. #include "olsontz.h"
  34. U_NAMESPACE_BEGIN
  35. #define ZID_KEY_MAX 128
  36. #define MZ_PREFIX_LEN 5
  37. static const char gZoneStrings[] = "zoneStrings";
  38. static const char gMZPrefix[] = "meta:";
  39. static const char EMPTY[] = "<empty>"; // place holder for empty ZNames
  40. static const char DUMMY_LOADER[] = "<dummy>"; // place holder for dummy ZNamesLoader
  41. static const char16_t NO_NAME[] = { 0 }; // for empty no-fallback time zone names
  42. // stuff for TZDBTimeZoneNames
  43. static const char* TZDBNAMES_KEYS[] = {"ss", "sd"};
  44. static const int32_t TZDBNAMES_KEYS_SIZE = UPRV_LENGTHOF(TZDBNAMES_KEYS);
  45. static UMutex gDataMutex;
  46. static UHashtable* gTZDBNamesMap = nullptr;
  47. static icu::UInitOnce gTZDBNamesMapInitOnce {};
  48. static TextTrieMap* gTZDBNamesTrie = nullptr;
  49. static icu::UInitOnce gTZDBNamesTrieInitOnce {};
  50. // The order in which strings are stored may be different than the order in the public enum.
  51. enum UTimeZoneNameTypeIndex {
  52. UTZNM_INDEX_UNKNOWN = -1,
  53. UTZNM_INDEX_EXEMPLAR_LOCATION,
  54. UTZNM_INDEX_LONG_GENERIC,
  55. UTZNM_INDEX_LONG_STANDARD,
  56. UTZNM_INDEX_LONG_DAYLIGHT,
  57. UTZNM_INDEX_SHORT_GENERIC,
  58. UTZNM_INDEX_SHORT_STANDARD,
  59. UTZNM_INDEX_SHORT_DAYLIGHT,
  60. UTZNM_INDEX_COUNT
  61. };
  62. static const char16_t* const EMPTY_NAMES[UTZNM_INDEX_COUNT] = {0,0,0,0,0,0,0};
  63. U_CDECL_BEGIN
  64. static UBool U_CALLCONV tzdbTimeZoneNames_cleanup() {
  65. if (gTZDBNamesMap != nullptr) {
  66. uhash_close(gTZDBNamesMap);
  67. gTZDBNamesMap = nullptr;
  68. }
  69. gTZDBNamesMapInitOnce.reset();
  70. if (gTZDBNamesTrie != nullptr) {
  71. delete gTZDBNamesTrie;
  72. gTZDBNamesTrie = nullptr;
  73. }
  74. gTZDBNamesTrieInitOnce.reset();
  75. return true;
  76. }
  77. U_CDECL_END
  78. /**
  79. * ZNameInfo stores zone name information in the trie
  80. */
  81. struct ZNameInfo {
  82. UTimeZoneNameType type;
  83. const char16_t* tzID;
  84. const char16_t* mzID;
  85. };
  86. /**
  87. * ZMatchInfo stores zone name match information used by find method
  88. */
  89. struct ZMatchInfo {
  90. const ZNameInfo* znameInfo;
  91. int32_t matchLength;
  92. };
  93. // Helper functions
  94. static void mergeTimeZoneKey(const UnicodeString& mzID, char* result);
  95. #define DEFAULT_CHARACTERNODE_CAPACITY 1
  96. // ---------------------------------------------------
  97. // CharacterNode class implementation
  98. // ---------------------------------------------------
  99. void CharacterNode::clear() {
  100. uprv_memset(this, 0, sizeof(*this));
  101. }
  102. void CharacterNode::deleteValues(UObjectDeleter *valueDeleter) {
  103. if (fValues == nullptr) {
  104. // Do nothing.
  105. } else if (!fHasValuesVector) {
  106. if (valueDeleter) {
  107. valueDeleter(fValues);
  108. }
  109. } else {
  110. delete (UVector *)fValues;
  111. }
  112. }
  113. void
  114. CharacterNode::addValue(void *value, UObjectDeleter *valueDeleter, UErrorCode &status) {
  115. if (U_FAILURE(status)) {
  116. if (valueDeleter) {
  117. valueDeleter(value);
  118. }
  119. return;
  120. }
  121. if (fValues == nullptr) {
  122. fValues = value;
  123. } else {
  124. // At least one value already.
  125. if (!fHasValuesVector) {
  126. // There is only one value so far, and not in a vector yet.
  127. // Create a vector and add the old value.
  128. LocalPointer<UVector> values(
  129. new UVector(valueDeleter, nullptr, DEFAULT_CHARACTERNODE_CAPACITY, status), status);
  130. if (U_FAILURE(status)) {
  131. if (valueDeleter) {
  132. valueDeleter(value);
  133. }
  134. return;
  135. }
  136. if (values->hasDeleter()) {
  137. values->adoptElement(fValues, status);
  138. } else {
  139. values->addElement(fValues, status);
  140. }
  141. fValues = values.orphan();
  142. fHasValuesVector = true;
  143. }
  144. // Add the new value.
  145. UVector *values = (UVector *)fValues;
  146. if (values->hasDeleter()) {
  147. values->adoptElement(value, status);
  148. } else {
  149. values->addElement(value, status);
  150. }
  151. }
  152. }
  153. // ---------------------------------------------------
  154. // TextTrieMapSearchResultHandler class implementation
  155. // ---------------------------------------------------
  156. TextTrieMapSearchResultHandler::~TextTrieMapSearchResultHandler(){
  157. }
  158. // ---------------------------------------------------
  159. // TextTrieMap class implementation
  160. // ---------------------------------------------------
  161. TextTrieMap::TextTrieMap(UBool ignoreCase, UObjectDeleter *valueDeleter)
  162. : fIgnoreCase(ignoreCase), fNodes(nullptr), fNodesCapacity(0), fNodesCount(0),
  163. fLazyContents(nullptr), fIsEmpty(true), fValueDeleter(valueDeleter) {
  164. }
  165. TextTrieMap::~TextTrieMap() {
  166. int32_t index;
  167. for (index = 0; index < fNodesCount; ++index) {
  168. fNodes[index].deleteValues(fValueDeleter);
  169. }
  170. uprv_free(fNodes);
  171. if (fLazyContents != nullptr) {
  172. for (int32_t i=0; i<fLazyContents->size(); i+=2) {
  173. if (fValueDeleter) {
  174. fValueDeleter(fLazyContents->elementAt(i+1));
  175. }
  176. }
  177. delete fLazyContents;
  178. }
  179. }
  180. int32_t TextTrieMap::isEmpty() const {
  181. // Use a separate field for fIsEmpty because it will remain unchanged once the
  182. // Trie is built, while fNodes and fLazyContents change with the lazy init
  183. // of the nodes structure. Trying to test the changing fields has
  184. // thread safety complications.
  185. return fIsEmpty;
  186. }
  187. // We defer actually building the TextTrieMap node structure until the first time a
  188. // search is performed. put() simply saves the parameters in case we do
  189. // eventually need to build it.
  190. //
  191. void
  192. TextTrieMap::put(const UnicodeString &key, void *value, ZNStringPool &sp, UErrorCode &status) {
  193. const char16_t *s = sp.get(key, status);
  194. put(s, value, status);
  195. }
  196. // This method is designed for a persistent key, such as string key stored in
  197. // resource bundle.
  198. void
  199. TextTrieMap::put(const char16_t *key, void *value, UErrorCode &status) {
  200. fIsEmpty = false;
  201. if (fLazyContents == nullptr) {
  202. LocalPointer<UVector> lpLazyContents(new UVector(status), status);
  203. fLazyContents = lpLazyContents.orphan();
  204. }
  205. if (U_FAILURE(status)) {
  206. if (fValueDeleter) {
  207. fValueDeleter((void*) key);
  208. }
  209. return;
  210. }
  211. U_ASSERT(fLazyContents != nullptr);
  212. char16_t *s = const_cast<char16_t *>(key);
  213. fLazyContents->addElement(s, status);
  214. if (U_FAILURE(status)) {
  215. if (fValueDeleter) {
  216. fValueDeleter((void*) key);
  217. }
  218. return;
  219. }
  220. fLazyContents->addElement(value, status);
  221. }
  222. void
  223. TextTrieMap::putImpl(const UnicodeString &key, void *value, UErrorCode &status) {
  224. if (fNodes == nullptr) {
  225. fNodesCapacity = 512;
  226. fNodes = (CharacterNode *)uprv_malloc(fNodesCapacity * sizeof(CharacterNode));
  227. if (fNodes == nullptr) {
  228. status = U_MEMORY_ALLOCATION_ERROR;
  229. return;
  230. }
  231. fNodes[0].clear(); // Init root node.
  232. fNodesCount = 1;
  233. }
  234. UnicodeString foldedKey;
  235. const char16_t *keyBuffer;
  236. int32_t keyLength;
  237. if (fIgnoreCase) {
  238. // Ok to use fastCopyFrom() because we discard the copy when we return.
  239. foldedKey.fastCopyFrom(key).foldCase();
  240. keyBuffer = foldedKey.getBuffer();
  241. keyLength = foldedKey.length();
  242. } else {
  243. keyBuffer = key.getBuffer();
  244. keyLength = key.length();
  245. }
  246. CharacterNode *node = fNodes;
  247. int32_t index;
  248. for (index = 0; index < keyLength; ++index) {
  249. node = addChildNode(node, keyBuffer[index], status);
  250. }
  251. node->addValue(value, fValueDeleter, status);
  252. }
  253. UBool
  254. TextTrieMap::growNodes() {
  255. if (fNodesCapacity == 0xffff) {
  256. return false; // We use 16-bit node indexes.
  257. }
  258. int32_t newCapacity = fNodesCapacity + 1000;
  259. if (newCapacity > 0xffff) {
  260. newCapacity = 0xffff;
  261. }
  262. CharacterNode *newNodes = (CharacterNode *)uprv_malloc(newCapacity * sizeof(CharacterNode));
  263. if (newNodes == nullptr) {
  264. return false;
  265. }
  266. uprv_memcpy(newNodes, fNodes, fNodesCount * sizeof(CharacterNode));
  267. uprv_free(fNodes);
  268. fNodes = newNodes;
  269. fNodesCapacity = newCapacity;
  270. return true;
  271. }
  272. CharacterNode*
  273. TextTrieMap::addChildNode(CharacterNode *parent, char16_t c, UErrorCode &status) {
  274. if (U_FAILURE(status)) {
  275. return nullptr;
  276. }
  277. // Linear search of the sorted list of children.
  278. uint16_t prevIndex = 0;
  279. uint16_t nodeIndex = parent->fFirstChild;
  280. while (nodeIndex > 0) {
  281. CharacterNode *current = fNodes + nodeIndex;
  282. char16_t childCharacter = current->fCharacter;
  283. if (childCharacter == c) {
  284. return current;
  285. } else if (childCharacter > c) {
  286. break;
  287. }
  288. prevIndex = nodeIndex;
  289. nodeIndex = current->fNextSibling;
  290. }
  291. // Ensure capacity. Grow fNodes[] if needed.
  292. if (fNodesCount == fNodesCapacity) {
  293. int32_t parentIndex = (int32_t)(parent - fNodes);
  294. if (!growNodes()) {
  295. status = U_MEMORY_ALLOCATION_ERROR;
  296. return nullptr;
  297. }
  298. parent = fNodes + parentIndex;
  299. }
  300. // Insert a new child node with c in sorted order.
  301. CharacterNode *node = fNodes + fNodesCount;
  302. node->clear();
  303. node->fCharacter = c;
  304. node->fNextSibling = nodeIndex;
  305. if (prevIndex == 0) {
  306. parent->fFirstChild = (uint16_t)fNodesCount;
  307. } else {
  308. fNodes[prevIndex].fNextSibling = (uint16_t)fNodesCount;
  309. }
  310. ++fNodesCount;
  311. return node;
  312. }
  313. CharacterNode*
  314. TextTrieMap::getChildNode(CharacterNode *parent, char16_t c) const {
  315. // Linear search of the sorted list of children.
  316. uint16_t nodeIndex = parent->fFirstChild;
  317. while (nodeIndex > 0) {
  318. CharacterNode *current = fNodes + nodeIndex;
  319. char16_t childCharacter = current->fCharacter;
  320. if (childCharacter == c) {
  321. return current;
  322. } else if (childCharacter > c) {
  323. break;
  324. }
  325. nodeIndex = current->fNextSibling;
  326. }
  327. return nullptr;
  328. }
  329. // buildTrie() - The Trie node structure is needed. Create it from the data that was
  330. // saved at the time the ZoneStringFormatter was created. The Trie is only
  331. // needed for parsing operations, which are less common than formatting,
  332. // and the Trie is big, which is why its creation is deferred until first use.
  333. void TextTrieMap::buildTrie(UErrorCode &status) {
  334. if (fLazyContents != nullptr) {
  335. for (int32_t i=0; i<fLazyContents->size(); i+=2) {
  336. const char16_t *key = (char16_t *)fLazyContents->elementAt(i);
  337. void *val = fLazyContents->elementAt(i+1);
  338. UnicodeString keyString(true, key, -1); // Aliasing UnicodeString constructor.
  339. putImpl(keyString, val, status);
  340. }
  341. delete fLazyContents;
  342. fLazyContents = nullptr;
  343. }
  344. }
  345. void
  346. TextTrieMap::search(const UnicodeString &text, int32_t start,
  347. TextTrieMapSearchResultHandler *handler, UErrorCode &status) const {
  348. {
  349. // TODO: if locking the mutex for each check proves to be a performance problem,
  350. // add a flag of type atomic_int32_t to class TextTrieMap, and use only
  351. // the ICU atomic safe functions for assigning and testing.
  352. // Don't test the pointer fLazyContents.
  353. // Don't do unless it's really required.
  354. // Mutex for protecting the lazy creation of the Trie node structure on the first call to search().
  355. static UMutex TextTrieMutex;
  356. Mutex lock(&TextTrieMutex);
  357. if (fLazyContents != nullptr) {
  358. TextTrieMap *nonConstThis = const_cast<TextTrieMap *>(this);
  359. nonConstThis->buildTrie(status);
  360. }
  361. }
  362. if (fNodes == nullptr) {
  363. return;
  364. }
  365. search(fNodes, text, start, start, handler, status);
  366. }
  367. void
  368. TextTrieMap::search(CharacterNode *node, const UnicodeString &text, int32_t start,
  369. int32_t index, TextTrieMapSearchResultHandler *handler, UErrorCode &status) const {
  370. if (U_FAILURE(status)) {
  371. return;
  372. }
  373. if (node->hasValues()) {
  374. if (!handler->handleMatch(index - start, node, status)) {
  375. return;
  376. }
  377. if (U_FAILURE(status)) {
  378. return;
  379. }
  380. }
  381. if (fIgnoreCase) {
  382. // for folding we need to get a complete code point.
  383. // size of character may grow after fold operation;
  384. // then we need to get result as UTF16 code units.
  385. UChar32 c32 = text.char32At(index);
  386. index += U16_LENGTH(c32);
  387. UnicodeString tmp(c32);
  388. tmp.foldCase();
  389. int32_t tmpidx = 0;
  390. while (tmpidx < tmp.length()) {
  391. char16_t c = tmp.charAt(tmpidx++);
  392. node = getChildNode(node, c);
  393. if (node == nullptr) {
  394. break;
  395. }
  396. }
  397. } else {
  398. // here we just get the next UTF16 code unit
  399. char16_t c = text.charAt(index++);
  400. node = getChildNode(node, c);
  401. }
  402. if (node != nullptr) {
  403. search(node, text, start, index, handler, status);
  404. }
  405. }
  406. // ---------------------------------------------------
  407. // ZNStringPool class implementation
  408. // ---------------------------------------------------
  409. static const int32_t POOL_CHUNK_SIZE = 2000;
  410. struct ZNStringPoolChunk: public UMemory {
  411. ZNStringPoolChunk *fNext; // Ptr to next pool chunk
  412. int32_t fLimit; // Index to start of unused area at end of fStrings
  413. char16_t fStrings[POOL_CHUNK_SIZE]; // Strings array
  414. ZNStringPoolChunk();
  415. };
  416. ZNStringPoolChunk::ZNStringPoolChunk() {
  417. fNext = nullptr;
  418. fLimit = 0;
  419. }
  420. ZNStringPool::ZNStringPool(UErrorCode &status) {
  421. fChunks = nullptr;
  422. fHash = nullptr;
  423. if (U_FAILURE(status)) {
  424. return;
  425. }
  426. fChunks = new ZNStringPoolChunk;
  427. if (fChunks == nullptr) {
  428. status = U_MEMORY_ALLOCATION_ERROR;
  429. return;
  430. }
  431. fHash = uhash_open(uhash_hashUChars /* keyHash */,
  432. uhash_compareUChars /* keyComp */,
  433. uhash_compareUChars /* valueComp */,
  434. &status);
  435. if (U_FAILURE(status)) {
  436. return;
  437. }
  438. }
  439. ZNStringPool::~ZNStringPool() {
  440. if (fHash != nullptr) {
  441. uhash_close(fHash);
  442. fHash = nullptr;
  443. }
  444. while (fChunks != nullptr) {
  445. ZNStringPoolChunk *nextChunk = fChunks->fNext;
  446. delete fChunks;
  447. fChunks = nextChunk;
  448. }
  449. }
  450. static const char16_t EmptyString = 0;
  451. const char16_t *ZNStringPool::get(const char16_t *s, UErrorCode &status) {
  452. const char16_t *pooledString;
  453. if (U_FAILURE(status)) {
  454. return &EmptyString;
  455. }
  456. pooledString = static_cast<char16_t *>(uhash_get(fHash, s));
  457. if (pooledString != nullptr) {
  458. return pooledString;
  459. }
  460. int32_t length = u_strlen(s);
  461. int32_t remainingLength = POOL_CHUNK_SIZE - fChunks->fLimit;
  462. if (remainingLength <= length) {
  463. U_ASSERT(length < POOL_CHUNK_SIZE);
  464. if (length >= POOL_CHUNK_SIZE) {
  465. status = U_INTERNAL_PROGRAM_ERROR;
  466. return &EmptyString;
  467. }
  468. ZNStringPoolChunk *oldChunk = fChunks;
  469. fChunks = new ZNStringPoolChunk;
  470. if (fChunks == nullptr) {
  471. status = U_MEMORY_ALLOCATION_ERROR;
  472. return &EmptyString;
  473. }
  474. fChunks->fNext = oldChunk;
  475. }
  476. char16_t *destString = &fChunks->fStrings[fChunks->fLimit];
  477. u_strcpy(destString, s);
  478. fChunks->fLimit += (length + 1);
  479. uhash_put(fHash, destString, destString, &status);
  480. return destString;
  481. }
  482. //
  483. // ZNStringPool::adopt() Put a string into the hash, but do not copy the string data
  484. // into the pool's storage. Used for strings from resource bundles,
  485. // which will persist for the life of the zone string formatter, and
  486. // therefore can be used directly without copying.
  487. const char16_t *ZNStringPool::adopt(const char16_t * s, UErrorCode &status) {
  488. const char16_t *pooledString;
  489. if (U_FAILURE(status)) {
  490. return &EmptyString;
  491. }
  492. if (s != nullptr) {
  493. pooledString = static_cast<char16_t *>(uhash_get(fHash, s));
  494. if (pooledString == nullptr) {
  495. char16_t *ncs = const_cast<char16_t *>(s);
  496. uhash_put(fHash, ncs, ncs, &status);
  497. }
  498. }
  499. return s;
  500. }
  501. const char16_t *ZNStringPool::get(const UnicodeString &s, UErrorCode &status) {
  502. UnicodeString &nonConstStr = const_cast<UnicodeString &>(s);
  503. return this->get(nonConstStr.getTerminatedBuffer(), status);
  504. }
  505. /*
  506. * freeze(). Close the hash table that maps to the pooled strings.
  507. * After freezing, the pool can not be searched or added to,
  508. * but all existing references to pooled strings remain valid.
  509. *
  510. * The main purpose is to recover the storage used for the hash.
  511. */
  512. void ZNStringPool::freeze() {
  513. uhash_close(fHash);
  514. fHash = nullptr;
  515. }
  516. /**
  517. * This class stores name data for a meta zone or time zone.
  518. */
  519. class ZNames : public UMemory {
  520. private:
  521. friend class TimeZoneNamesImpl;
  522. static UTimeZoneNameTypeIndex getTZNameTypeIndex(UTimeZoneNameType type) {
  523. switch(type) {
  524. case UTZNM_EXEMPLAR_LOCATION: return UTZNM_INDEX_EXEMPLAR_LOCATION;
  525. case UTZNM_LONG_GENERIC: return UTZNM_INDEX_LONG_GENERIC;
  526. case UTZNM_LONG_STANDARD: return UTZNM_INDEX_LONG_STANDARD;
  527. case UTZNM_LONG_DAYLIGHT: return UTZNM_INDEX_LONG_DAYLIGHT;
  528. case UTZNM_SHORT_GENERIC: return UTZNM_INDEX_SHORT_GENERIC;
  529. case UTZNM_SHORT_STANDARD: return UTZNM_INDEX_SHORT_STANDARD;
  530. case UTZNM_SHORT_DAYLIGHT: return UTZNM_INDEX_SHORT_DAYLIGHT;
  531. default: return UTZNM_INDEX_UNKNOWN;
  532. }
  533. }
  534. static UTimeZoneNameType getTZNameType(UTimeZoneNameTypeIndex index) {
  535. switch(index) {
  536. case UTZNM_INDEX_EXEMPLAR_LOCATION: return UTZNM_EXEMPLAR_LOCATION;
  537. case UTZNM_INDEX_LONG_GENERIC: return UTZNM_LONG_GENERIC;
  538. case UTZNM_INDEX_LONG_STANDARD: return UTZNM_LONG_STANDARD;
  539. case UTZNM_INDEX_LONG_DAYLIGHT: return UTZNM_LONG_DAYLIGHT;
  540. case UTZNM_INDEX_SHORT_GENERIC: return UTZNM_SHORT_GENERIC;
  541. case UTZNM_INDEX_SHORT_STANDARD: return UTZNM_SHORT_STANDARD;
  542. case UTZNM_INDEX_SHORT_DAYLIGHT: return UTZNM_SHORT_DAYLIGHT;
  543. default: return UTZNM_UNKNOWN;
  544. }
  545. }
  546. const char16_t* fNames[UTZNM_INDEX_COUNT];
  547. UBool fDidAddIntoTrie;
  548. // Whether we own the location string, if computed rather than loaded from a bundle.
  549. // A meta zone names instance never has an exemplar location string.
  550. UBool fOwnsLocationName;
  551. ZNames(const char16_t* names[], const char16_t* locationName)
  552. : fDidAddIntoTrie(false) {
  553. uprv_memcpy(fNames, names, sizeof(fNames));
  554. if (locationName != nullptr) {
  555. fOwnsLocationName = true;
  556. fNames[UTZNM_INDEX_EXEMPLAR_LOCATION] = locationName;
  557. } else {
  558. fOwnsLocationName = false;
  559. }
  560. }
  561. public:
  562. ~ZNames() {
  563. if (fOwnsLocationName) {
  564. const char16_t* locationName = fNames[UTZNM_INDEX_EXEMPLAR_LOCATION];
  565. U_ASSERT(locationName != nullptr);
  566. uprv_free((void*) locationName);
  567. }
  568. }
  569. private:
  570. static void* createMetaZoneAndPutInCache(UHashtable* cache, const char16_t* names[],
  571. const UnicodeString& mzID, UErrorCode& status) {
  572. if (U_FAILURE(status)) { return nullptr; }
  573. U_ASSERT(names != nullptr);
  574. // Use the persistent ID as the resource key, so we can
  575. // avoid duplications.
  576. // TODO: Is there a more efficient way, like intern() in Java?
  577. void* key = (void*) ZoneMeta::findMetaZoneID(mzID);
  578. void* value;
  579. if (uprv_memcmp(names, EMPTY_NAMES, sizeof(EMPTY_NAMES)) == 0) {
  580. value = (void*) EMPTY;
  581. } else {
  582. value = (void*) (new ZNames(names, nullptr));
  583. if (value == nullptr) {
  584. status = U_MEMORY_ALLOCATION_ERROR;
  585. return nullptr;
  586. }
  587. }
  588. uhash_put(cache, key, value, &status);
  589. return value;
  590. }
  591. static void* createTimeZoneAndPutInCache(UHashtable* cache, const char16_t* names[],
  592. const UnicodeString& tzID, UErrorCode& status) {
  593. if (U_FAILURE(status)) { return nullptr; }
  594. U_ASSERT(names != nullptr);
  595. // If necessary, compute the location name from the time zone name.
  596. char16_t* locationName = nullptr;
  597. if (names[UTZNM_INDEX_EXEMPLAR_LOCATION] == nullptr) {
  598. UnicodeString locationNameUniStr;
  599. TimeZoneNamesImpl::getDefaultExemplarLocationName(tzID, locationNameUniStr);
  600. // Copy the computed location name to the heap
  601. if (locationNameUniStr.length() > 0) {
  602. const char16_t* buff = locationNameUniStr.getTerminatedBuffer();
  603. int32_t len = sizeof(char16_t) * (locationNameUniStr.length() + 1);
  604. locationName = (char16_t*) uprv_malloc(len);
  605. if (locationName == nullptr) {
  606. status = U_MEMORY_ALLOCATION_ERROR;
  607. return nullptr;
  608. }
  609. uprv_memcpy(locationName, buff, len);
  610. }
  611. }
  612. // Use the persistent ID as the resource key, so we can
  613. // avoid duplications.
  614. // TODO: Is there a more efficient way, like intern() in Java?
  615. void* key = (void*) ZoneMeta::findTimeZoneID(tzID);
  616. void* value = (void*) (new ZNames(names, locationName));
  617. if (value == nullptr) {
  618. status = U_MEMORY_ALLOCATION_ERROR;
  619. return nullptr;
  620. }
  621. uhash_put(cache, key, value, &status);
  622. return value;
  623. }
  624. const char16_t* getName(UTimeZoneNameType type) const {
  625. UTimeZoneNameTypeIndex index = getTZNameTypeIndex(type);
  626. return index >= 0 ? fNames[index] : nullptr;
  627. }
  628. void addAsMetaZoneIntoTrie(const char16_t* mzID, TextTrieMap& trie, UErrorCode& status) {
  629. addNamesIntoTrie(mzID, nullptr, trie, status);
  630. }
  631. void addAsTimeZoneIntoTrie(const char16_t* tzID, TextTrieMap& trie, UErrorCode& status) {
  632. addNamesIntoTrie(nullptr, tzID, trie, status);
  633. }
  634. void addNamesIntoTrie(const char16_t* mzID, const char16_t* tzID, TextTrieMap& trie,
  635. UErrorCode& status) {
  636. if (U_FAILURE(status)) { return; }
  637. if (fDidAddIntoTrie) { return; }
  638. fDidAddIntoTrie = true;
  639. for (int32_t i = 0; i < UTZNM_INDEX_COUNT; i++) {
  640. const char16_t* name = fNames[i];
  641. if (name != nullptr) {
  642. ZNameInfo *nameinfo = (ZNameInfo *)uprv_malloc(sizeof(ZNameInfo));
  643. if (nameinfo == nullptr) {
  644. status = U_MEMORY_ALLOCATION_ERROR;
  645. return;
  646. }
  647. nameinfo->mzID = mzID;
  648. nameinfo->tzID = tzID;
  649. nameinfo->type = getTZNameType((UTimeZoneNameTypeIndex)i);
  650. trie.put(name, nameinfo, status); // trie.put() takes ownership of the key
  651. if (U_FAILURE(status)) {
  652. return;
  653. }
  654. }
  655. }
  656. }
  657. public:
  658. struct ZNamesLoader;
  659. };
  660. struct ZNames::ZNamesLoader : public ResourceSink {
  661. const char16_t *names[UTZNM_INDEX_COUNT];
  662. ZNamesLoader() {
  663. clear();
  664. }
  665. virtual ~ZNamesLoader();
  666. /** Reset for loading another set of names. */
  667. void clear() {
  668. uprv_memcpy(names, EMPTY_NAMES, sizeof(names));
  669. }
  670. void loadMetaZone(const UResourceBundle* zoneStrings, const UnicodeString& mzID, UErrorCode& errorCode) {
  671. if (U_FAILURE(errorCode)) { return; }
  672. char key[ZID_KEY_MAX + 1];
  673. mergeTimeZoneKey(mzID, key);
  674. loadNames(zoneStrings, key, errorCode);
  675. }
  676. void loadTimeZone(const UResourceBundle* zoneStrings, const UnicodeString& tzID, UErrorCode& errorCode) {
  677. // Replace "/" with ":".
  678. UnicodeString uKey(tzID);
  679. for (int32_t i = 0; i < uKey.length(); i++) {
  680. if (uKey.charAt(i) == (char16_t)0x2F) {
  681. uKey.setCharAt(i, (char16_t)0x3A);
  682. }
  683. }
  684. char key[ZID_KEY_MAX + 1];
  685. uKey.extract(0, uKey.length(), key, sizeof(key), US_INV);
  686. loadNames(zoneStrings, key, errorCode);
  687. }
  688. void loadNames(const UResourceBundle* zoneStrings, const char* key, UErrorCode& errorCode) {
  689. U_ASSERT(zoneStrings != nullptr);
  690. U_ASSERT(key != nullptr);
  691. U_ASSERT(key[0] != '\0');
  692. UErrorCode localStatus = U_ZERO_ERROR;
  693. clear();
  694. ures_getAllItemsWithFallback(zoneStrings, key, *this, localStatus);
  695. // Ignore errors, but propagate possible warnings.
  696. if (U_SUCCESS(localStatus)) {
  697. errorCode = localStatus;
  698. }
  699. }
  700. void setNameIfEmpty(const char* key, const ResourceValue* value, UErrorCode& errorCode) {
  701. UTimeZoneNameTypeIndex type = nameTypeFromKey(key);
  702. if (type == UTZNM_INDEX_UNKNOWN) { return; }
  703. if (names[type] == nullptr) {
  704. int32_t length;
  705. // 'NO_NAME' indicates internally that this field should remain empty. It will be
  706. // replaced by 'nullptr' in getNames()
  707. names[type] = (value == nullptr) ? NO_NAME : value->getString(length, errorCode);
  708. }
  709. }
  710. virtual void put(const char* key, ResourceValue& value, UBool /*noFallback*/,
  711. UErrorCode &errorCode) override {
  712. ResourceTable namesTable = value.getTable(errorCode);
  713. if (U_FAILURE(errorCode)) { return; }
  714. for (int32_t i = 0; namesTable.getKeyAndValue(i, key, value); ++i) {
  715. if (value.isNoInheritanceMarker()) {
  716. setNameIfEmpty(key, nullptr, errorCode);
  717. } else {
  718. setNameIfEmpty(key, &value, errorCode);
  719. }
  720. }
  721. }
  722. static UTimeZoneNameTypeIndex nameTypeFromKey(const char *key) {
  723. char c0, c1;
  724. if ((c0 = key[0]) == 0 || (c1 = key[1]) == 0 || key[2] != 0) {
  725. return UTZNM_INDEX_UNKNOWN;
  726. }
  727. if (c0 == 'l') {
  728. return c1 == 'g' ? UTZNM_INDEX_LONG_GENERIC :
  729. c1 == 's' ? UTZNM_INDEX_LONG_STANDARD :
  730. c1 == 'd' ? UTZNM_INDEX_LONG_DAYLIGHT : UTZNM_INDEX_UNKNOWN;
  731. } else if (c0 == 's') {
  732. return c1 == 'g' ? UTZNM_INDEX_SHORT_GENERIC :
  733. c1 == 's' ? UTZNM_INDEX_SHORT_STANDARD :
  734. c1 == 'd' ? UTZNM_INDEX_SHORT_DAYLIGHT : UTZNM_INDEX_UNKNOWN;
  735. } else if (c0 == 'e' && c1 == 'c') {
  736. return UTZNM_INDEX_EXEMPLAR_LOCATION;
  737. }
  738. return UTZNM_INDEX_UNKNOWN;
  739. }
  740. /**
  741. * Returns an array of names. It is the caller's responsibility to copy the data into a
  742. * permanent location, as the returned array is owned by the loader instance and may be
  743. * cleared or leave scope.
  744. *
  745. * This is different than Java, where the array will no longer be modified and null
  746. * may be returned.
  747. */
  748. const char16_t** getNames() {
  749. // Remove 'NO_NAME' references in the array and replace with 'nullptr'
  750. for (int32_t i = 0; i < UTZNM_INDEX_COUNT; ++i) {
  751. if (names[i] == NO_NAME) {
  752. names[i] = nullptr;
  753. }
  754. }
  755. return names;
  756. }
  757. };
  758. ZNames::ZNamesLoader::~ZNamesLoader() {}
  759. // ---------------------------------------------------
  760. // The meta zone ID enumeration class
  761. // ---------------------------------------------------
  762. class MetaZoneIDsEnumeration : public StringEnumeration {
  763. public:
  764. MetaZoneIDsEnumeration();
  765. MetaZoneIDsEnumeration(const UVector& mzIDs);
  766. MetaZoneIDsEnumeration(LocalPointer<UVector> mzIDs);
  767. virtual ~MetaZoneIDsEnumeration();
  768. static UClassID U_EXPORT2 getStaticClassID();
  769. virtual UClassID getDynamicClassID() const override;
  770. virtual const UnicodeString* snext(UErrorCode& status) override;
  771. virtual void reset(UErrorCode& status) override;
  772. virtual int32_t count(UErrorCode& status) const override;
  773. private:
  774. int32_t fLen;
  775. int32_t fPos;
  776. const UVector* fMetaZoneIDs;
  777. LocalPointer<UVector> fLocalVector;
  778. };
  779. UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MetaZoneIDsEnumeration)
  780. MetaZoneIDsEnumeration::MetaZoneIDsEnumeration()
  781. : fLen(0), fPos(0), fMetaZoneIDs(nullptr), fLocalVector(nullptr) {
  782. }
  783. MetaZoneIDsEnumeration::MetaZoneIDsEnumeration(const UVector& mzIDs)
  784. : fPos(0), fMetaZoneIDs(&mzIDs), fLocalVector(nullptr) {
  785. fLen = fMetaZoneIDs->size();
  786. }
  787. MetaZoneIDsEnumeration::MetaZoneIDsEnumeration(LocalPointer<UVector> mzIDs)
  788. : fLen(0), fPos(0), fMetaZoneIDs(nullptr), fLocalVector(std::move(mzIDs)) {
  789. fMetaZoneIDs = fLocalVector.getAlias();
  790. if (fMetaZoneIDs) {
  791. fLen = fMetaZoneIDs->size();
  792. }
  793. }
  794. const UnicodeString*
  795. MetaZoneIDsEnumeration::snext(UErrorCode& status) {
  796. if (U_SUCCESS(status) && fMetaZoneIDs != nullptr && fPos < fLen) {
  797. unistr.setTo((const char16_t*)fMetaZoneIDs->elementAt(fPos++), -1);
  798. return &unistr;
  799. }
  800. return nullptr;
  801. }
  802. void
  803. MetaZoneIDsEnumeration::reset(UErrorCode& /*status*/) {
  804. fPos = 0;
  805. }
  806. int32_t
  807. MetaZoneIDsEnumeration::count(UErrorCode& /*status*/) const {
  808. return fLen;
  809. }
  810. MetaZoneIDsEnumeration::~MetaZoneIDsEnumeration() {
  811. }
  812. // ---------------------------------------------------
  813. // ZNameSearchHandler
  814. // ---------------------------------------------------
  815. class ZNameSearchHandler : public TextTrieMapSearchResultHandler {
  816. public:
  817. ZNameSearchHandler(uint32_t types);
  818. virtual ~ZNameSearchHandler();
  819. UBool handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status) override;
  820. TimeZoneNames::MatchInfoCollection* getMatches(int32_t& maxMatchLen);
  821. private:
  822. uint32_t fTypes;
  823. int32_t fMaxMatchLen;
  824. TimeZoneNames::MatchInfoCollection* fResults;
  825. };
  826. ZNameSearchHandler::ZNameSearchHandler(uint32_t types)
  827. : fTypes(types), fMaxMatchLen(0), fResults(nullptr) {
  828. }
  829. ZNameSearchHandler::~ZNameSearchHandler() {
  830. if (fResults != nullptr) {
  831. delete fResults;
  832. }
  833. }
  834. UBool
  835. ZNameSearchHandler::handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status) {
  836. if (U_FAILURE(status)) {
  837. return false;
  838. }
  839. if (node->hasValues()) {
  840. int32_t valuesCount = node->countValues();
  841. for (int32_t i = 0; i < valuesCount; i++) {
  842. ZNameInfo *nameinfo = (ZNameInfo *)node->getValue(i);
  843. if (nameinfo == nullptr) {
  844. continue;
  845. }
  846. if ((nameinfo->type & fTypes) != 0) {
  847. // matches a requested type
  848. if (fResults == nullptr) {
  849. fResults = new TimeZoneNames::MatchInfoCollection();
  850. if (fResults == nullptr) {
  851. status = U_MEMORY_ALLOCATION_ERROR;
  852. }
  853. }
  854. if (U_SUCCESS(status)) {
  855. U_ASSERT(fResults != nullptr);
  856. if (nameinfo->tzID) {
  857. fResults->addZone(nameinfo->type, matchLength, UnicodeString(nameinfo->tzID, -1), status);
  858. } else {
  859. U_ASSERT(nameinfo->mzID);
  860. fResults->addMetaZone(nameinfo->type, matchLength, UnicodeString(nameinfo->mzID, -1), status);
  861. }
  862. if (U_SUCCESS(status) && matchLength > fMaxMatchLen) {
  863. fMaxMatchLen = matchLength;
  864. }
  865. }
  866. }
  867. }
  868. }
  869. return true;
  870. }
  871. TimeZoneNames::MatchInfoCollection*
  872. ZNameSearchHandler::getMatches(int32_t& maxMatchLen) {
  873. // give the ownership to the caller
  874. TimeZoneNames::MatchInfoCollection* results = fResults;
  875. maxMatchLen = fMaxMatchLen;
  876. // reset
  877. fResults = nullptr;
  878. fMaxMatchLen = 0;
  879. return results;
  880. }
  881. // ---------------------------------------------------
  882. // TimeZoneNamesImpl
  883. //
  884. // TimeZoneNames implementation class. This is the main
  885. // part of this module.
  886. // ---------------------------------------------------
  887. U_CDECL_BEGIN
  888. /**
  889. * Deleter for ZNames
  890. */
  891. static void U_CALLCONV
  892. deleteZNames(void *obj) {
  893. if (obj != EMPTY) {
  894. delete (ZNames*) obj;
  895. }
  896. }
  897. /**
  898. * Deleter for ZNameInfo
  899. */
  900. static void U_CALLCONV
  901. deleteZNameInfo(void *obj) {
  902. uprv_free(obj);
  903. }
  904. U_CDECL_END
  905. TimeZoneNamesImpl::TimeZoneNamesImpl(const Locale& locale, UErrorCode& status)
  906. : fLocale(locale),
  907. fZoneStrings(nullptr),
  908. fTZNamesMap(nullptr),
  909. fMZNamesMap(nullptr),
  910. fNamesTrieFullyLoaded(false),
  911. fNamesFullyLoaded(false),
  912. fNamesTrie(true, deleteZNameInfo) {
  913. initialize(locale, status);
  914. }
  915. void
  916. TimeZoneNamesImpl::initialize(const Locale& locale, UErrorCode& status) {
  917. if (U_FAILURE(status)) {
  918. return;
  919. }
  920. // Load zoneStrings bundle
  921. UErrorCode tmpsts = U_ZERO_ERROR; // OK with fallback warning..
  922. fZoneStrings = ures_open(U_ICUDATA_ZONE, locale.getName(), &tmpsts);
  923. fZoneStrings = ures_getByKeyWithFallback(fZoneStrings, gZoneStrings, fZoneStrings, &tmpsts);
  924. if (U_FAILURE(tmpsts)) {
  925. status = tmpsts;
  926. cleanup();
  927. return;
  928. }
  929. // Initialize hashtables holding time zone/meta zone names
  930. fMZNamesMap = uhash_open(uhash_hashUChars, uhash_compareUChars, nullptr, &status);
  931. fTZNamesMap = uhash_open(uhash_hashUChars, uhash_compareUChars, nullptr, &status);
  932. if (U_FAILURE(status)) {
  933. cleanup();
  934. return;
  935. }
  936. uhash_setValueDeleter(fMZNamesMap, deleteZNames);
  937. uhash_setValueDeleter(fTZNamesMap, deleteZNames);
  938. // no key deleters for name maps
  939. // preload zone strings for the default zone
  940. TimeZone *tz = TimeZone::createDefault();
  941. const char16_t *tzID = ZoneMeta::getCanonicalCLDRID(*tz);
  942. if (tzID != nullptr) {
  943. loadStrings(UnicodeString(tzID), status);
  944. }
  945. delete tz;
  946. return;
  947. }
  948. /*
  949. * This method updates the cache and must be called with a lock,
  950. * except initializer.
  951. */
  952. void
  953. TimeZoneNamesImpl::loadStrings(const UnicodeString& tzCanonicalID, UErrorCode& status) {
  954. loadTimeZoneNames(tzCanonicalID, status);
  955. LocalPointer<StringEnumeration> mzIDs(getAvailableMetaZoneIDs(tzCanonicalID, status));
  956. if (U_FAILURE(status)) { return; }
  957. U_ASSERT(!mzIDs.isNull());
  958. const UnicodeString *mzID;
  959. while (((mzID = mzIDs->snext(status)) != nullptr) && U_SUCCESS(status)) {
  960. loadMetaZoneNames(*mzID, status);
  961. }
  962. }
  963. TimeZoneNamesImpl::~TimeZoneNamesImpl() {
  964. cleanup();
  965. }
  966. void
  967. TimeZoneNamesImpl::cleanup() {
  968. if (fZoneStrings != nullptr) {
  969. ures_close(fZoneStrings);
  970. fZoneStrings = nullptr;
  971. }
  972. if (fMZNamesMap != nullptr) {
  973. uhash_close(fMZNamesMap);
  974. fMZNamesMap = nullptr;
  975. }
  976. if (fTZNamesMap != nullptr) {
  977. uhash_close(fTZNamesMap);
  978. fTZNamesMap = nullptr;
  979. }
  980. }
  981. bool
  982. TimeZoneNamesImpl::operator==(const TimeZoneNames& other) const {
  983. if (this == &other) {
  984. return true;
  985. }
  986. // No implementation for now
  987. return false;
  988. }
  989. TimeZoneNamesImpl*
  990. TimeZoneNamesImpl::clone() const {
  991. UErrorCode status = U_ZERO_ERROR;
  992. return new TimeZoneNamesImpl(fLocale, status);
  993. }
  994. StringEnumeration*
  995. TimeZoneNamesImpl::getAvailableMetaZoneIDs(UErrorCode& status) const {
  996. return TimeZoneNamesImpl::_getAvailableMetaZoneIDs(status);
  997. }
  998. // static implementation of getAvailableMetaZoneIDs(UErrorCode&)
  999. StringEnumeration*
  1000. TimeZoneNamesImpl::_getAvailableMetaZoneIDs(UErrorCode& status) {
  1001. if (U_FAILURE(status)) {
  1002. return nullptr;
  1003. }
  1004. const UVector* mzIDs = ZoneMeta::getAvailableMetazoneIDs();
  1005. if (mzIDs == nullptr) {
  1006. return new MetaZoneIDsEnumeration();
  1007. }
  1008. return new MetaZoneIDsEnumeration(*mzIDs);
  1009. }
  1010. StringEnumeration*
  1011. TimeZoneNamesImpl::getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const {
  1012. return TimeZoneNamesImpl::_getAvailableMetaZoneIDs(tzID, status);
  1013. }
  1014. // static implementation of getAvailableMetaZoneIDs(const UnicodeString&, UErrorCode&)
  1015. StringEnumeration*
  1016. TimeZoneNamesImpl::_getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) {
  1017. if (U_FAILURE(status)) {
  1018. return nullptr;
  1019. }
  1020. const UVector* mappings = ZoneMeta::getMetazoneMappings(tzID);
  1021. if (mappings == nullptr) {
  1022. return new MetaZoneIDsEnumeration();
  1023. }
  1024. LocalPointer<MetaZoneIDsEnumeration> senum;
  1025. LocalPointer<UVector> mzIDs(new UVector(nullptr, uhash_compareUChars, status), status);
  1026. if (U_SUCCESS(status)) {
  1027. U_ASSERT(mzIDs.isValid());
  1028. for (int32_t i = 0; U_SUCCESS(status) && i < mappings->size(); i++) {
  1029. OlsonToMetaMappingEntry *map = (OlsonToMetaMappingEntry *)mappings->elementAt(i);
  1030. const char16_t *mzID = map->mzid;
  1031. if (!mzIDs->contains((void *)mzID)) {
  1032. mzIDs->addElement((void *)mzID, status);
  1033. }
  1034. }
  1035. if (U_SUCCESS(status)) {
  1036. senum.adoptInsteadAndCheckErrorCode(new MetaZoneIDsEnumeration(std::move(mzIDs)), status);
  1037. }
  1038. }
  1039. return U_SUCCESS(status) ? senum.orphan() : nullptr;
  1040. }
  1041. UnicodeString&
  1042. TimeZoneNamesImpl::getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) const {
  1043. return TimeZoneNamesImpl::_getMetaZoneID(tzID, date, mzID);
  1044. }
  1045. // static implementation of getMetaZoneID
  1046. UnicodeString&
  1047. TimeZoneNamesImpl::_getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) {
  1048. ZoneMeta::getMetazoneID(tzID, date, mzID);
  1049. return mzID;
  1050. }
  1051. UnicodeString&
  1052. TimeZoneNamesImpl::getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID) const {
  1053. return TimeZoneNamesImpl::_getReferenceZoneID(mzID, region, tzID);
  1054. }
  1055. // static implementation of getReferenceZoneID
  1056. UnicodeString&
  1057. TimeZoneNamesImpl::_getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID) {
  1058. ZoneMeta::getZoneIdByMetazone(mzID, UnicodeString(region, -1, US_INV), tzID);
  1059. return tzID;
  1060. }
  1061. UnicodeString&
  1062. TimeZoneNamesImpl::getMetaZoneDisplayName(const UnicodeString& mzID,
  1063. UTimeZoneNameType type,
  1064. UnicodeString& name) const {
  1065. name.setToBogus(); // cleanup result.
  1066. if (mzID.isEmpty()) {
  1067. return name;
  1068. }
  1069. ZNames *znames = nullptr;
  1070. TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
  1071. {
  1072. Mutex lock(&gDataMutex);
  1073. UErrorCode status = U_ZERO_ERROR;
  1074. znames = nonConstThis->loadMetaZoneNames(mzID, status);
  1075. if (U_FAILURE(status)) { return name; }
  1076. }
  1077. if (znames != nullptr) {
  1078. const char16_t* s = znames->getName(type);
  1079. if (s != nullptr) {
  1080. name.setTo(true, s, -1);
  1081. }
  1082. }
  1083. return name;
  1084. }
  1085. UnicodeString&
  1086. TimeZoneNamesImpl::getTimeZoneDisplayName(const UnicodeString& tzID, UTimeZoneNameType type, UnicodeString& name) const {
  1087. name.setToBogus(); // cleanup result.
  1088. if (tzID.isEmpty()) {
  1089. return name;
  1090. }
  1091. ZNames *tznames = nullptr;
  1092. TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
  1093. {
  1094. Mutex lock(&gDataMutex);
  1095. UErrorCode status = U_ZERO_ERROR;
  1096. tznames = nonConstThis->loadTimeZoneNames(tzID, status);
  1097. if (U_FAILURE(status)) { return name; }
  1098. }
  1099. if (tznames != nullptr) {
  1100. const char16_t *s = tznames->getName(type);
  1101. if (s != nullptr) {
  1102. name.setTo(true, s, -1);
  1103. }
  1104. }
  1105. return name;
  1106. }
  1107. UnicodeString&
  1108. TimeZoneNamesImpl::getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const {
  1109. name.setToBogus(); // cleanup result.
  1110. const char16_t* locName = nullptr;
  1111. ZNames *tznames = nullptr;
  1112. TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
  1113. {
  1114. Mutex lock(&gDataMutex);
  1115. UErrorCode status = U_ZERO_ERROR;
  1116. tznames = nonConstThis->loadTimeZoneNames(tzID, status);
  1117. if (U_FAILURE(status)) { return name; }
  1118. }
  1119. if (tznames != nullptr) {
  1120. locName = tznames->getName(UTZNM_EXEMPLAR_LOCATION);
  1121. }
  1122. if (locName != nullptr) {
  1123. name.setTo(true, locName, -1);
  1124. }
  1125. return name;
  1126. }
  1127. // Merge the MZ_PREFIX and mzId
  1128. static void mergeTimeZoneKey(const UnicodeString& mzID, char* result) {
  1129. if (mzID.isEmpty()) {
  1130. result[0] = '\0';
  1131. return;
  1132. }
  1133. char mzIdChar[ZID_KEY_MAX + 1];
  1134. int32_t keyLen;
  1135. int32_t prefixLen = static_cast<int32_t>(uprv_strlen(gMZPrefix));
  1136. keyLen = mzID.extract(0, mzID.length(), mzIdChar, ZID_KEY_MAX + 1, US_INV);
  1137. uprv_memcpy((void *)result, (void *)gMZPrefix, prefixLen);
  1138. uprv_memcpy((void *)(result + prefixLen), (void *)mzIdChar, keyLen);
  1139. result[keyLen + prefixLen] = '\0';
  1140. }
  1141. /*
  1142. * This method updates the cache and must be called with a lock
  1143. */
  1144. ZNames*
  1145. TimeZoneNamesImpl::loadMetaZoneNames(const UnicodeString& mzID, UErrorCode& status) {
  1146. if (U_FAILURE(status)) { return nullptr; }
  1147. U_ASSERT(mzID.length() <= ZID_KEY_MAX - MZ_PREFIX_LEN);
  1148. char16_t mzIDKey[ZID_KEY_MAX + 1];
  1149. mzID.extract(mzIDKey, ZID_KEY_MAX + 1, status);
  1150. U_ASSERT(U_SUCCESS(status)); // already checked length above
  1151. mzIDKey[mzID.length()] = 0;
  1152. void* mznames = uhash_get(fMZNamesMap, mzIDKey);
  1153. if (mznames == nullptr) {
  1154. ZNames::ZNamesLoader loader;
  1155. loader.loadMetaZone(fZoneStrings, mzID, status);
  1156. mznames = ZNames::createMetaZoneAndPutInCache(fMZNamesMap, loader.getNames(), mzID, status);
  1157. if (U_FAILURE(status)) { return nullptr; }
  1158. }
  1159. if (mznames != EMPTY) {
  1160. return (ZNames*)mznames;
  1161. } else {
  1162. return nullptr;
  1163. }
  1164. }
  1165. /*
  1166. * This method updates the cache and must be called with a lock
  1167. */
  1168. ZNames*
  1169. TimeZoneNamesImpl::loadTimeZoneNames(const UnicodeString& tzID, UErrorCode& status) {
  1170. if (U_FAILURE(status)) { return nullptr; }
  1171. U_ASSERT(tzID.length() <= ZID_KEY_MAX);
  1172. char16_t tzIDKey[ZID_KEY_MAX + 1];
  1173. int32_t tzIDKeyLen = tzID.extract(tzIDKey, ZID_KEY_MAX + 1, status);
  1174. U_ASSERT(U_SUCCESS(status)); // already checked length above
  1175. tzIDKey[tzIDKeyLen] = 0;
  1176. void *tznames = uhash_get(fTZNamesMap, tzIDKey);
  1177. if (tznames == nullptr) {
  1178. ZNames::ZNamesLoader loader;
  1179. loader.loadTimeZone(fZoneStrings, tzID, status);
  1180. tznames = ZNames::createTimeZoneAndPutInCache(fTZNamesMap, loader.getNames(), tzID, status);
  1181. if (U_FAILURE(status)) { return nullptr; }
  1182. }
  1183. // tznames is never EMPTY
  1184. return (ZNames*)tznames;
  1185. }
  1186. TimeZoneNames::MatchInfoCollection*
  1187. TimeZoneNamesImpl::find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
  1188. ZNameSearchHandler handler(types);
  1189. TimeZoneNames::MatchInfoCollection* matches;
  1190. TimeZoneNamesImpl* nonConstThis = const_cast<TimeZoneNamesImpl*>(this);
  1191. // Synchronize so that data is not loaded multiple times.
  1192. // TODO: Consider more fine-grained synchronization.
  1193. {
  1194. Mutex lock(&gDataMutex);
  1195. // First try of lookup.
  1196. matches = doFind(handler, text, start, status);
  1197. if (U_FAILURE(status)) { return nullptr; }
  1198. if (matches != nullptr) {
  1199. return matches;
  1200. }
  1201. // All names are not yet loaded into the trie.
  1202. // We may have loaded names for formatting several time zones,
  1203. // and might be parsing one of those.
  1204. // Populate the parsing trie from all of the already-loaded names.
  1205. nonConstThis->addAllNamesIntoTrie(status);
  1206. // Second try of lookup.
  1207. matches = doFind(handler, text, start, status);
  1208. if (U_FAILURE(status)) { return nullptr; }
  1209. if (matches != nullptr) {
  1210. return matches;
  1211. }
  1212. // There are still some names we haven't loaded into the trie yet.
  1213. // Load everything now.
  1214. nonConstThis->internalLoadAllDisplayNames(status);
  1215. nonConstThis->addAllNamesIntoTrie(status);
  1216. nonConstThis->fNamesTrieFullyLoaded = true;
  1217. if (U_FAILURE(status)) { return nullptr; }
  1218. // Third try: we must return this one.
  1219. return doFind(handler, text, start, status);
  1220. }
  1221. }
  1222. TimeZoneNames::MatchInfoCollection*
  1223. TimeZoneNamesImpl::doFind(ZNameSearchHandler& handler,
  1224. const UnicodeString& text, int32_t start, UErrorCode& status) const {
  1225. fNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
  1226. if (U_FAILURE(status)) { return nullptr; }
  1227. int32_t maxLen = 0;
  1228. TimeZoneNames::MatchInfoCollection* matches = handler.getMatches(maxLen);
  1229. if (matches != nullptr && ((maxLen == (text.length() - start)) || fNamesTrieFullyLoaded)) {
  1230. // perfect match, or no more names available
  1231. return matches;
  1232. }
  1233. delete matches;
  1234. return nullptr;
  1235. }
  1236. // Caller must synchronize.
  1237. void TimeZoneNamesImpl::addAllNamesIntoTrie(UErrorCode& status) {
  1238. if (U_FAILURE(status)) return;
  1239. int32_t pos;
  1240. const UHashElement* element;
  1241. pos = UHASH_FIRST;
  1242. while ((element = uhash_nextElement(fMZNamesMap, &pos)) != nullptr) {
  1243. if (element->value.pointer == EMPTY) { continue; }
  1244. char16_t* mzID = (char16_t*) element->key.pointer;
  1245. ZNames* znames = (ZNames*) element->value.pointer;
  1246. znames->addAsMetaZoneIntoTrie(mzID, fNamesTrie, status);
  1247. if (U_FAILURE(status)) { return; }
  1248. }
  1249. pos = UHASH_FIRST;
  1250. while ((element = uhash_nextElement(fTZNamesMap, &pos)) != nullptr) {
  1251. if (element->value.pointer == EMPTY) { continue; }
  1252. char16_t* tzID = (char16_t*) element->key.pointer;
  1253. ZNames* znames = (ZNames*) element->value.pointer;
  1254. znames->addAsTimeZoneIntoTrie(tzID, fNamesTrie, status);
  1255. if (U_FAILURE(status)) { return; }
  1256. }
  1257. }
  1258. U_CDECL_BEGIN
  1259. static void U_CALLCONV
  1260. deleteZNamesLoader(void* obj) {
  1261. if (obj == DUMMY_LOADER) { return; }
  1262. const ZNames::ZNamesLoader* loader = (const ZNames::ZNamesLoader*) obj;
  1263. delete loader;
  1264. }
  1265. U_CDECL_END
  1266. struct TimeZoneNamesImpl::ZoneStringsLoader : public ResourceSink {
  1267. TimeZoneNamesImpl& tzn;
  1268. UHashtable* keyToLoader;
  1269. ZoneStringsLoader(TimeZoneNamesImpl& _tzn, UErrorCode& status)
  1270. : tzn(_tzn) {
  1271. keyToLoader = uhash_open(uhash_hashChars, uhash_compareChars, nullptr, &status);
  1272. if (U_FAILURE(status)) { return; }
  1273. uhash_setKeyDeleter(keyToLoader, uprv_free);
  1274. uhash_setValueDeleter(keyToLoader, deleteZNamesLoader);
  1275. }
  1276. virtual ~ZoneStringsLoader();
  1277. void* createKey(const char* key, UErrorCode& status) {
  1278. int32_t len = sizeof(char) * (static_cast<int32_t>(uprv_strlen(key)) + 1);
  1279. char* newKey = (char*) uprv_malloc(len);
  1280. if (newKey == nullptr) {
  1281. status = U_MEMORY_ALLOCATION_ERROR;
  1282. return nullptr;
  1283. }
  1284. uprv_memcpy(newKey, key, len);
  1285. newKey[len-1] = '\0';
  1286. return (void*) newKey;
  1287. }
  1288. UBool isMetaZone(const char* key) {
  1289. return (uprv_strlen(key) >= MZ_PREFIX_LEN && uprv_memcmp(key, gMZPrefix, MZ_PREFIX_LEN) == 0);
  1290. }
  1291. UnicodeString mzIDFromKey(const char* key) {
  1292. return UnicodeString(key + MZ_PREFIX_LEN, static_cast<int32_t>(uprv_strlen(key)) - MZ_PREFIX_LEN, US_INV);
  1293. }
  1294. UnicodeString tzIDFromKey(const char* key) {
  1295. UnicodeString tzID(key, -1, US_INV);
  1296. // Replace all colons ':' with slashes '/'
  1297. for (int i=0; i<tzID.length(); i++) {
  1298. if (tzID.charAt(i) == 0x003A) {
  1299. tzID.setCharAt(i, 0x002F);
  1300. }
  1301. }
  1302. return tzID;
  1303. }
  1304. void load(UErrorCode& status) {
  1305. ures_getAllItemsWithFallback(tzn.fZoneStrings, "", *this, status);
  1306. if (U_FAILURE(status)) { return; }
  1307. int32_t pos = UHASH_FIRST;
  1308. const UHashElement* element;
  1309. while ((element = uhash_nextElement(keyToLoader, &pos)) != nullptr) {
  1310. if (element->value.pointer == DUMMY_LOADER) { continue; }
  1311. ZNames::ZNamesLoader* loader = (ZNames::ZNamesLoader*) element->value.pointer;
  1312. char* key = (char*) element->key.pointer;
  1313. if (isMetaZone(key)) {
  1314. UnicodeString mzID = mzIDFromKey(key);
  1315. ZNames::createMetaZoneAndPutInCache(tzn.fMZNamesMap, loader->getNames(), mzID, status);
  1316. } else {
  1317. UnicodeString tzID = tzIDFromKey(key);
  1318. ZNames::createTimeZoneAndPutInCache(tzn.fTZNamesMap, loader->getNames(), tzID, status);
  1319. }
  1320. if (U_FAILURE(status)) { return; }
  1321. }
  1322. }
  1323. void consumeNamesTable(const char *key, ResourceValue &value, UBool noFallback,
  1324. UErrorCode &status) {
  1325. if (U_FAILURE(status)) { return; }
  1326. void* loader = uhash_get(keyToLoader, key);
  1327. if (loader == nullptr) {
  1328. if (isMetaZone(key)) {
  1329. UnicodeString mzID = mzIDFromKey(key);
  1330. void* cacheVal = uhash_get(tzn.fMZNamesMap, mzID.getTerminatedBuffer());
  1331. if (cacheVal != nullptr) {
  1332. // We have already loaded the names for this meta zone.
  1333. loader = (void*) DUMMY_LOADER;
  1334. } else {
  1335. loader = (void*) new ZNames::ZNamesLoader();
  1336. if (loader == nullptr) {
  1337. status = U_MEMORY_ALLOCATION_ERROR;
  1338. return;
  1339. }
  1340. }
  1341. } else {
  1342. UnicodeString tzID = tzIDFromKey(key);
  1343. void* cacheVal = uhash_get(tzn.fTZNamesMap, tzID.getTerminatedBuffer());
  1344. if (cacheVal != nullptr) {
  1345. // We have already loaded the names for this time zone.
  1346. loader = (void*) DUMMY_LOADER;
  1347. } else {
  1348. loader = (void*) new ZNames::ZNamesLoader();
  1349. if (loader == nullptr) {
  1350. status = U_MEMORY_ALLOCATION_ERROR;
  1351. return;
  1352. }
  1353. }
  1354. }
  1355. void* newKey = createKey(key, status);
  1356. if (U_FAILURE(status)) {
  1357. deleteZNamesLoader(loader);
  1358. return;
  1359. }
  1360. uhash_put(keyToLoader, newKey, loader, &status);
  1361. if (U_FAILURE(status)) { return; }
  1362. }
  1363. if (loader != DUMMY_LOADER) {
  1364. // Let the ZNamesLoader consume the names table.
  1365. ((ZNames::ZNamesLoader*)loader)->put(key, value, noFallback, status);
  1366. }
  1367. }
  1368. virtual void put(const char *key, ResourceValue &value, UBool noFallback,
  1369. UErrorCode &status) override {
  1370. ResourceTable timeZonesTable = value.getTable(status);
  1371. if (U_FAILURE(status)) { return; }
  1372. for (int32_t i = 0; timeZonesTable.getKeyAndValue(i, key, value); ++i) {
  1373. U_ASSERT(!value.isNoInheritanceMarker());
  1374. if (value.getType() == URES_TABLE) {
  1375. consumeNamesTable(key, value, noFallback, status);
  1376. } else {
  1377. // Ignore fields that aren't tables (e.g., fallbackFormat and regionFormatStandard).
  1378. // All time zone fields are tables.
  1379. }
  1380. if (U_FAILURE(status)) { return; }
  1381. }
  1382. }
  1383. };
  1384. // Virtual destructors must be defined out of line.
  1385. TimeZoneNamesImpl::ZoneStringsLoader::~ZoneStringsLoader() {
  1386. uhash_close(keyToLoader);
  1387. }
  1388. void TimeZoneNamesImpl::loadAllDisplayNames(UErrorCode& status) {
  1389. if (U_FAILURE(status)) return;
  1390. {
  1391. Mutex lock(&gDataMutex);
  1392. internalLoadAllDisplayNames(status);
  1393. }
  1394. }
  1395. void TimeZoneNamesImpl::getDisplayNames(const UnicodeString& tzID,
  1396. const UTimeZoneNameType types[], int32_t numTypes,
  1397. UDate date, UnicodeString dest[], UErrorCode& status) const {
  1398. if (U_FAILURE(status)) return;
  1399. if (tzID.isEmpty()) { return; }
  1400. void* tznames = nullptr;
  1401. void* mznames = nullptr;
  1402. TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl*>(this);
  1403. // Load the time zone strings
  1404. {
  1405. Mutex lock(&gDataMutex);
  1406. tznames = (void*) nonConstThis->loadTimeZoneNames(tzID, status);
  1407. if (U_FAILURE(status)) { return; }
  1408. }
  1409. U_ASSERT(tznames != nullptr);
  1410. // Load the values into the dest array
  1411. for (int i = 0; i < numTypes; i++) {
  1412. UTimeZoneNameType type = types[i];
  1413. const char16_t* name = ((ZNames*)tznames)->getName(type);
  1414. if (name == nullptr) {
  1415. if (mznames == nullptr) {
  1416. // Load the meta zone name
  1417. UnicodeString mzID;
  1418. getMetaZoneID(tzID, date, mzID);
  1419. if (mzID.isEmpty()) {
  1420. mznames = (void*) EMPTY;
  1421. } else {
  1422. // Load the meta zone strings
  1423. // Mutex is scoped to the "else" statement
  1424. Mutex lock(&gDataMutex);
  1425. mznames = (void*) nonConstThis->loadMetaZoneNames(mzID, status);
  1426. if (U_FAILURE(status)) { return; }
  1427. // Note: when the metazone doesn't exist, in Java, loadMetaZoneNames returns
  1428. // a dummy object instead of nullptr.
  1429. if (mznames == nullptr) {
  1430. mznames = (void*) EMPTY;
  1431. }
  1432. }
  1433. }
  1434. U_ASSERT(mznames != nullptr);
  1435. if (mznames != EMPTY) {
  1436. name = ((ZNames*)mznames)->getName(type);
  1437. }
  1438. }
  1439. if (name != nullptr) {
  1440. dest[i].setTo(true, name, -1);
  1441. } else {
  1442. dest[i].setToBogus();
  1443. }
  1444. }
  1445. }
  1446. // Caller must synchronize.
  1447. void TimeZoneNamesImpl::internalLoadAllDisplayNames(UErrorCode& status) {
  1448. if (!fNamesFullyLoaded) {
  1449. fNamesFullyLoaded = true;
  1450. ZoneStringsLoader loader(*this, status);
  1451. loader.load(status);
  1452. if (U_FAILURE(status)) { return; }
  1453. const UnicodeString *id;
  1454. // load strings for all zones
  1455. StringEnumeration *tzIDs = TimeZone::createTimeZoneIDEnumeration(
  1456. UCAL_ZONE_TYPE_CANONICAL, nullptr, nullptr, status);
  1457. if (U_SUCCESS(status)) {
  1458. while ((id = tzIDs->snext(status)) != nullptr) {
  1459. if (U_FAILURE(status)) {
  1460. break;
  1461. }
  1462. UnicodeString copy(*id);
  1463. void* value = uhash_get(fTZNamesMap, copy.getTerminatedBuffer());
  1464. if (value == nullptr) {
  1465. // loadStrings also loads related metazone strings
  1466. loadStrings(*id, status);
  1467. }
  1468. }
  1469. }
  1470. if (tzIDs != nullptr) {
  1471. delete tzIDs;
  1472. }
  1473. }
  1474. }
  1475. static const char16_t gEtcPrefix[] = { 0x45, 0x74, 0x63, 0x2F }; // "Etc/"
  1476. static const int32_t gEtcPrefixLen = 4;
  1477. static const char16_t gSystemVPrefix[] = { 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x56, 0x2F }; // "SystemV/
  1478. static const int32_t gSystemVPrefixLen = 8;
  1479. static const char16_t gRiyadh8[] = { 0x52, 0x69, 0x79, 0x61, 0x64, 0x68, 0x38 }; // "Riyadh8"
  1480. static const int32_t gRiyadh8Len = 7;
  1481. UnicodeString& U_EXPORT2
  1482. TimeZoneNamesImpl::getDefaultExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) {
  1483. if (tzID.isEmpty() || tzID.startsWith(gEtcPrefix, gEtcPrefixLen)
  1484. || tzID.startsWith(gSystemVPrefix, gSystemVPrefixLen) || tzID.indexOf(gRiyadh8, gRiyadh8Len, 0) > 0) {
  1485. name.setToBogus();
  1486. return name;
  1487. }
  1488. int32_t sep = tzID.lastIndexOf((char16_t)0x2F /* '/' */);
  1489. if (sep > 0 && sep + 1 < tzID.length()) {
  1490. name.setTo(tzID, sep + 1);
  1491. name.findAndReplace(UnicodeString((char16_t)0x5f /* _ */),
  1492. UnicodeString((char16_t)0x20 /* space */));
  1493. } else {
  1494. name.setToBogus();
  1495. }
  1496. return name;
  1497. }
  1498. // ---------------------------------------------------
  1499. // TZDBTimeZoneNames and its supporting classes
  1500. //
  1501. // TZDBTimeZoneNames is an implementation class of
  1502. // TimeZoneNames holding the IANA tz database abbreviations.
  1503. // ---------------------------------------------------
  1504. class TZDBNames : public UMemory {
  1505. public:
  1506. virtual ~TZDBNames();
  1507. static TZDBNames* createInstance(UResourceBundle* rb, const char* key);
  1508. const char16_t* getName(UTimeZoneNameType type) const;
  1509. const char** getParseRegions(int32_t& numRegions) const;
  1510. protected:
  1511. TZDBNames(const char16_t** names, char** regions, int32_t numRegions);
  1512. private:
  1513. const char16_t** fNames;
  1514. char** fRegions;
  1515. int32_t fNumRegions;
  1516. };
  1517. TZDBNames::TZDBNames(const char16_t** names, char** regions, int32_t numRegions)
  1518. : fNames(names),
  1519. fRegions(regions),
  1520. fNumRegions(numRegions) {
  1521. }
  1522. TZDBNames::~TZDBNames() {
  1523. if (fNames != nullptr) {
  1524. uprv_free(fNames);
  1525. }
  1526. if (fRegions != nullptr) {
  1527. char **p = fRegions;
  1528. for (int32_t i = 0; i < fNumRegions; p++, i++) {
  1529. uprv_free(*p);
  1530. }
  1531. uprv_free(fRegions);
  1532. }
  1533. }
  1534. TZDBNames*
  1535. TZDBNames::createInstance(UResourceBundle* rb, const char* key) {
  1536. if (rb == nullptr || key == nullptr || *key == 0) {
  1537. return nullptr;
  1538. }
  1539. UErrorCode status = U_ZERO_ERROR;
  1540. const char16_t **names = nullptr;
  1541. char** regions = nullptr;
  1542. int32_t numRegions = 0;
  1543. int32_t len = 0;
  1544. UResourceBundle* rbTable = nullptr;
  1545. rbTable = ures_getByKey(rb, key, rbTable, &status);
  1546. if (U_FAILURE(status)) {
  1547. return nullptr;
  1548. }
  1549. names = (const char16_t **)uprv_malloc(sizeof(const char16_t*) * TZDBNAMES_KEYS_SIZE);
  1550. UBool isEmpty = true;
  1551. if (names != nullptr) {
  1552. for (int32_t i = 0; i < TZDBNAMES_KEYS_SIZE; i++) {
  1553. status = U_ZERO_ERROR;
  1554. const char16_t *value = ures_getStringByKey(rbTable, TZDBNAMES_KEYS[i], &len, &status);
  1555. if (U_FAILURE(status) || len == 0) {
  1556. names[i] = nullptr;
  1557. } else {
  1558. names[i] = value;
  1559. isEmpty = false;
  1560. }
  1561. }
  1562. }
  1563. if (isEmpty) {
  1564. if (names != nullptr) {
  1565. uprv_free(names);
  1566. }
  1567. return nullptr;
  1568. }
  1569. UResourceBundle *regionsRes = ures_getByKey(rbTable, "parseRegions", nullptr, &status);
  1570. UBool regionError = false;
  1571. if (U_SUCCESS(status)) {
  1572. numRegions = ures_getSize(regionsRes);
  1573. if (numRegions > 0) {
  1574. regions = (char**)uprv_malloc(sizeof(char*) * numRegions);
  1575. if (regions != nullptr) {
  1576. char **pRegion = regions;
  1577. for (int32_t i = 0; i < numRegions; i++, pRegion++) {
  1578. *pRegion = nullptr;
  1579. }
  1580. // filling regions
  1581. pRegion = regions;
  1582. for (int32_t i = 0; i < numRegions; i++, pRegion++) {
  1583. status = U_ZERO_ERROR;
  1584. const char16_t *uregion = ures_getStringByIndex(regionsRes, i, &len, &status);
  1585. if (U_FAILURE(status)) {
  1586. regionError = true;
  1587. break;
  1588. }
  1589. *pRegion = (char*)uprv_malloc(sizeof(char) * (len + 1));
  1590. if (*pRegion == nullptr) {
  1591. regionError = true;
  1592. break;
  1593. }
  1594. u_UCharsToChars(uregion, *pRegion, len);
  1595. (*pRegion)[len] = 0;
  1596. }
  1597. }
  1598. }
  1599. }
  1600. ures_close(regionsRes);
  1601. ures_close(rbTable);
  1602. if (regionError) {
  1603. if (names != nullptr) {
  1604. uprv_free(names);
  1605. }
  1606. if (regions != nullptr) {
  1607. char **p = regions;
  1608. for (int32_t i = 0; i < numRegions; p++, i++) {
  1609. uprv_free(*p);
  1610. }
  1611. uprv_free(regions);
  1612. }
  1613. return nullptr;
  1614. }
  1615. return new TZDBNames(names, regions, numRegions);
  1616. }
  1617. const char16_t*
  1618. TZDBNames::getName(UTimeZoneNameType type) const {
  1619. if (fNames == nullptr) {
  1620. return nullptr;
  1621. }
  1622. const char16_t *name = nullptr;
  1623. switch(type) {
  1624. case UTZNM_SHORT_STANDARD:
  1625. name = fNames[0];
  1626. break;
  1627. case UTZNM_SHORT_DAYLIGHT:
  1628. name = fNames[1];
  1629. break;
  1630. default:
  1631. name = nullptr;
  1632. }
  1633. return name;
  1634. }
  1635. const char**
  1636. TZDBNames::getParseRegions(int32_t& numRegions) const {
  1637. if (fRegions == nullptr) {
  1638. numRegions = 0;
  1639. } else {
  1640. numRegions = fNumRegions;
  1641. }
  1642. return (const char**)fRegions;
  1643. }
  1644. U_CDECL_BEGIN
  1645. /**
  1646. * TZDBNameInfo stores metazone name information for the IANA abbreviations
  1647. * in the trie
  1648. */
  1649. typedef struct TZDBNameInfo {
  1650. const char16_t* mzID;
  1651. UTimeZoneNameType type;
  1652. UBool ambiguousType;
  1653. const char** parseRegions;
  1654. int32_t nRegions;
  1655. } TZDBNameInfo;
  1656. U_CDECL_END
  1657. class TZDBNameSearchHandler : public TextTrieMapSearchResultHandler {
  1658. public:
  1659. TZDBNameSearchHandler(uint32_t types, const char* region);
  1660. virtual ~TZDBNameSearchHandler();
  1661. UBool handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status) override;
  1662. TimeZoneNames::MatchInfoCollection* getMatches(int32_t& maxMatchLen);
  1663. private:
  1664. uint32_t fTypes;
  1665. int32_t fMaxMatchLen;
  1666. TimeZoneNames::MatchInfoCollection* fResults;
  1667. const char* fRegion;
  1668. };
  1669. TZDBNameSearchHandler::TZDBNameSearchHandler(uint32_t types, const char* region)
  1670. : fTypes(types), fMaxMatchLen(0), fResults(nullptr), fRegion(region) {
  1671. }
  1672. TZDBNameSearchHandler::~TZDBNameSearchHandler() {
  1673. if (fResults != nullptr) {
  1674. delete fResults;
  1675. }
  1676. }
  1677. UBool
  1678. TZDBNameSearchHandler::handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status) {
  1679. if (U_FAILURE(status)) {
  1680. return false;
  1681. }
  1682. TZDBNameInfo *match = nullptr;
  1683. TZDBNameInfo *defaultRegionMatch = nullptr;
  1684. if (node->hasValues()) {
  1685. int32_t valuesCount = node->countValues();
  1686. for (int32_t i = 0; i < valuesCount; i++) {
  1687. TZDBNameInfo *ninfo = (TZDBNameInfo *)node->getValue(i);
  1688. if (ninfo == nullptr) {
  1689. continue;
  1690. }
  1691. if ((ninfo->type & fTypes) != 0) {
  1692. // Some tz database abbreviations are ambiguous. For example,
  1693. // CST means either Central Standard Time or China Standard Time.
  1694. // Unlike CLDR time zone display names, this implementation
  1695. // does not use unique names. And TimeZoneFormat does not expect
  1696. // multiple results returned for the same time zone type.
  1697. // For this reason, this implementation resolve one among same
  1698. // zone type with a same name at this level.
  1699. if (ninfo->parseRegions == nullptr) {
  1700. // parseRegions == null means this is the default metazone
  1701. // mapping for the abbreviation.
  1702. if (defaultRegionMatch == nullptr) {
  1703. match = defaultRegionMatch = ninfo;
  1704. }
  1705. } else {
  1706. UBool matchRegion = false;
  1707. // non-default metazone mapping for an abbreviation
  1708. // comes with applicable regions. For example, the default
  1709. // metazone mapping for "CST" is America_Central,
  1710. // but if region is one of CN/MO/TW, "CST" is parsed
  1711. // as metazone China (China Standard Time).
  1712. for (int32_t j = 0; j < ninfo->nRegions; j++) {
  1713. const char *region = ninfo->parseRegions[j];
  1714. if (uprv_strcmp(fRegion, region) == 0) {
  1715. match = ninfo;
  1716. matchRegion = true;
  1717. break;
  1718. }
  1719. }
  1720. if (matchRegion) {
  1721. break;
  1722. }
  1723. if (match == nullptr) {
  1724. match = ninfo;
  1725. }
  1726. }
  1727. }
  1728. }
  1729. if (match != nullptr) {
  1730. UTimeZoneNameType ntype = match->type;
  1731. // Note: Workaround for duplicated standard/daylight names
  1732. // The tz database contains a few zones sharing a
  1733. // same name for both standard time and daylight saving
  1734. // time. For example, Australia/Sydney observes DST,
  1735. // but "EST" is used for both standard and daylight.
  1736. // When both SHORT_STANDARD and SHORT_DAYLIGHT are included
  1737. // in the find operation, we cannot tell which one was
  1738. // actually matched.
  1739. // TimeZoneFormat#parse returns a matched name type (standard
  1740. // or daylight) and DateFormat implementation uses the info to
  1741. // to adjust actual time. To avoid false type information,
  1742. // this implementation replaces the name type with SHORT_GENERIC.
  1743. if (match->ambiguousType
  1744. && (ntype == UTZNM_SHORT_STANDARD || ntype == UTZNM_SHORT_DAYLIGHT)
  1745. && (fTypes & UTZNM_SHORT_STANDARD) != 0
  1746. && (fTypes & UTZNM_SHORT_DAYLIGHT) != 0) {
  1747. ntype = UTZNM_SHORT_GENERIC;
  1748. }
  1749. if (fResults == nullptr) {
  1750. fResults = new TimeZoneNames::MatchInfoCollection();
  1751. if (fResults == nullptr) {
  1752. status = U_MEMORY_ALLOCATION_ERROR;
  1753. }
  1754. }
  1755. if (U_SUCCESS(status)) {
  1756. U_ASSERT(fResults != nullptr);
  1757. U_ASSERT(match->mzID != nullptr);
  1758. fResults->addMetaZone(ntype, matchLength, UnicodeString(match->mzID, -1), status);
  1759. if (U_SUCCESS(status) && matchLength > fMaxMatchLen) {
  1760. fMaxMatchLen = matchLength;
  1761. }
  1762. }
  1763. }
  1764. }
  1765. return true;
  1766. }
  1767. TimeZoneNames::MatchInfoCollection*
  1768. TZDBNameSearchHandler::getMatches(int32_t& maxMatchLen) {
  1769. // give the ownership to the caller
  1770. TimeZoneNames::MatchInfoCollection* results = fResults;
  1771. maxMatchLen = fMaxMatchLen;
  1772. // reset
  1773. fResults = nullptr;
  1774. fMaxMatchLen = 0;
  1775. return results;
  1776. }
  1777. U_CDECL_BEGIN
  1778. /**
  1779. * Deleter for TZDBNames
  1780. */
  1781. static void U_CALLCONV
  1782. deleteTZDBNames(void *obj) {
  1783. if (obj != EMPTY) {
  1784. delete (TZDBNames *)obj;
  1785. }
  1786. }
  1787. static void U_CALLCONV initTZDBNamesMap(UErrorCode &status) {
  1788. gTZDBNamesMap = uhash_open(uhash_hashUChars, uhash_compareUChars, nullptr, &status);
  1789. if (U_FAILURE(status)) {
  1790. gTZDBNamesMap = nullptr;
  1791. return;
  1792. }
  1793. // no key deleters for tzdb name maps
  1794. uhash_setValueDeleter(gTZDBNamesMap, deleteTZDBNames);
  1795. ucln_i18n_registerCleanup(UCLN_I18N_TZDBTIMEZONENAMES, tzdbTimeZoneNames_cleanup);
  1796. }
  1797. /**
  1798. * Deleter for TZDBNameInfo
  1799. */
  1800. static void U_CALLCONV
  1801. deleteTZDBNameInfo(void *obj) {
  1802. if (obj != nullptr) {
  1803. uprv_free(obj);
  1804. }
  1805. }
  1806. static void U_CALLCONV prepareFind(UErrorCode &status) {
  1807. if (U_FAILURE(status)) {
  1808. return;
  1809. }
  1810. gTZDBNamesTrie = new TextTrieMap(true, deleteTZDBNameInfo);
  1811. if (gTZDBNamesTrie == nullptr) {
  1812. status = U_MEMORY_ALLOCATION_ERROR;
  1813. return;
  1814. }
  1815. const UnicodeString *mzID;
  1816. StringEnumeration *mzIDs = TimeZoneNamesImpl::_getAvailableMetaZoneIDs(status);
  1817. if (U_SUCCESS(status)) {
  1818. while ((mzID = mzIDs->snext(status)) != 0 && U_SUCCESS(status)) {
  1819. const TZDBNames *names = TZDBTimeZoneNames::getMetaZoneNames(*mzID, status);
  1820. if (U_FAILURE(status)) {
  1821. break;
  1822. }
  1823. if (names == nullptr) {
  1824. continue;
  1825. }
  1826. const char16_t *std = names->getName(UTZNM_SHORT_STANDARD);
  1827. const char16_t *dst = names->getName(UTZNM_SHORT_DAYLIGHT);
  1828. if (std == nullptr && dst == nullptr) {
  1829. continue;
  1830. }
  1831. int32_t numRegions = 0;
  1832. const char **parseRegions = names->getParseRegions(numRegions);
  1833. // The tz database contains a few zones sharing a
  1834. // same name for both standard time and daylight saving
  1835. // time. For example, Australia/Sydney observes DST,
  1836. // but "EST" is used for both standard and daylight.
  1837. // we need to store the information for later processing.
  1838. UBool ambiguousType = (std != nullptr && dst != nullptr && u_strcmp(std, dst) == 0);
  1839. const char16_t *uMzID = ZoneMeta::findMetaZoneID(*mzID);
  1840. if (std != nullptr) {
  1841. TZDBNameInfo *stdInf = (TZDBNameInfo *)uprv_malloc(sizeof(TZDBNameInfo));
  1842. if (stdInf == nullptr) {
  1843. status = U_MEMORY_ALLOCATION_ERROR;
  1844. break;
  1845. }
  1846. stdInf->mzID = uMzID;
  1847. stdInf->type = UTZNM_SHORT_STANDARD;
  1848. stdInf->ambiguousType = ambiguousType;
  1849. stdInf->parseRegions = parseRegions;
  1850. stdInf->nRegions = numRegions;
  1851. gTZDBNamesTrie->put(std, stdInf, status);
  1852. }
  1853. if (U_SUCCESS(status) && dst != nullptr) {
  1854. TZDBNameInfo *dstInf = (TZDBNameInfo *)uprv_malloc(sizeof(TZDBNameInfo));
  1855. if (dstInf == nullptr) {
  1856. status = U_MEMORY_ALLOCATION_ERROR;
  1857. break;
  1858. }
  1859. dstInf->mzID = uMzID;
  1860. dstInf->type = UTZNM_SHORT_DAYLIGHT;
  1861. dstInf->ambiguousType = ambiguousType;
  1862. dstInf->parseRegions = parseRegions;
  1863. dstInf->nRegions = numRegions;
  1864. gTZDBNamesTrie->put(dst, dstInf, status);
  1865. }
  1866. }
  1867. }
  1868. delete mzIDs;
  1869. if (U_FAILURE(status)) {
  1870. delete gTZDBNamesTrie;
  1871. gTZDBNamesTrie = nullptr;
  1872. return;
  1873. }
  1874. ucln_i18n_registerCleanup(UCLN_I18N_TZDBTIMEZONENAMES, tzdbTimeZoneNames_cleanup);
  1875. }
  1876. U_CDECL_END
  1877. TZDBTimeZoneNames::TZDBTimeZoneNames(const Locale& locale)
  1878. : fLocale(locale) {
  1879. UBool useWorld = true;
  1880. const char* region = fLocale.getCountry();
  1881. int32_t regionLen = static_cast<int32_t>(uprv_strlen(region));
  1882. if (regionLen == 0) {
  1883. UErrorCode status = U_ZERO_ERROR;
  1884. CharString loc;
  1885. {
  1886. CharStringByteSink sink(&loc);
  1887. ulocimp_addLikelySubtags(fLocale.getName(), sink, &status);
  1888. }
  1889. regionLen = uloc_getCountry(loc.data(), fRegion, sizeof(fRegion), &status);
  1890. if (U_SUCCESS(status) && regionLen < (int32_t)sizeof(fRegion)) {
  1891. useWorld = false;
  1892. }
  1893. } else if (regionLen < (int32_t)sizeof(fRegion)) {
  1894. uprv_strcpy(fRegion, region);
  1895. useWorld = false;
  1896. }
  1897. if (useWorld) {
  1898. uprv_strcpy(fRegion, "001");
  1899. }
  1900. }
  1901. TZDBTimeZoneNames::~TZDBTimeZoneNames() {
  1902. }
  1903. bool
  1904. TZDBTimeZoneNames::operator==(const TimeZoneNames& other) const {
  1905. if (this == &other) {
  1906. return true;
  1907. }
  1908. // No implementation for now
  1909. return false;
  1910. }
  1911. TZDBTimeZoneNames*
  1912. TZDBTimeZoneNames::clone() const {
  1913. return new TZDBTimeZoneNames(fLocale);
  1914. }
  1915. StringEnumeration*
  1916. TZDBTimeZoneNames::getAvailableMetaZoneIDs(UErrorCode& status) const {
  1917. return TimeZoneNamesImpl::_getAvailableMetaZoneIDs(status);
  1918. }
  1919. StringEnumeration*
  1920. TZDBTimeZoneNames::getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const {
  1921. return TimeZoneNamesImpl::_getAvailableMetaZoneIDs(tzID, status);
  1922. }
  1923. UnicodeString&
  1924. TZDBTimeZoneNames::getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) const {
  1925. return TimeZoneNamesImpl::_getMetaZoneID(tzID, date, mzID);
  1926. }
  1927. UnicodeString&
  1928. TZDBTimeZoneNames::getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID) const {
  1929. return TimeZoneNamesImpl::_getReferenceZoneID(mzID, region, tzID);
  1930. }
  1931. UnicodeString&
  1932. TZDBTimeZoneNames::getMetaZoneDisplayName(const UnicodeString& mzID,
  1933. UTimeZoneNameType type,
  1934. UnicodeString& name) const {
  1935. name.setToBogus();
  1936. if (mzID.isEmpty()) {
  1937. return name;
  1938. }
  1939. UErrorCode status = U_ZERO_ERROR;
  1940. const TZDBNames *tzdbNames = TZDBTimeZoneNames::getMetaZoneNames(mzID, status);
  1941. if (U_SUCCESS(status)) {
  1942. if (tzdbNames != nullptr) {
  1943. const char16_t *s = tzdbNames->getName(type);
  1944. if (s != nullptr) {
  1945. name.setTo(true, s, -1);
  1946. }
  1947. }
  1948. }
  1949. return name;
  1950. }
  1951. UnicodeString&
  1952. TZDBTimeZoneNames::getTimeZoneDisplayName(const UnicodeString& /* tzID */, UTimeZoneNameType /* type */, UnicodeString& name) const {
  1953. // No abbreviations associated a zone directly for now.
  1954. name.setToBogus();
  1955. return name;
  1956. }
  1957. TZDBTimeZoneNames::MatchInfoCollection*
  1958. TZDBTimeZoneNames::find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
  1959. umtx_initOnce(gTZDBNamesTrieInitOnce, &prepareFind, status);
  1960. if (U_FAILURE(status)) {
  1961. return nullptr;
  1962. }
  1963. TZDBNameSearchHandler handler(types, fRegion);
  1964. gTZDBNamesTrie->search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
  1965. if (U_FAILURE(status)) {
  1966. return nullptr;
  1967. }
  1968. int32_t maxLen = 0;
  1969. return handler.getMatches(maxLen);
  1970. }
  1971. const TZDBNames*
  1972. TZDBTimeZoneNames::getMetaZoneNames(const UnicodeString& mzID, UErrorCode& status) {
  1973. umtx_initOnce(gTZDBNamesMapInitOnce, &initTZDBNamesMap, status);
  1974. if (U_FAILURE(status)) {
  1975. return nullptr;
  1976. }
  1977. TZDBNames* tzdbNames = nullptr;
  1978. char16_t mzIDKey[ZID_KEY_MAX + 1];
  1979. mzID.extract(mzIDKey, ZID_KEY_MAX + 1, status);
  1980. U_ASSERT(status == U_ZERO_ERROR); // already checked length above
  1981. mzIDKey[mzID.length()] = 0;
  1982. static UMutex gTZDBNamesMapLock;
  1983. umtx_lock(&gTZDBNamesMapLock);
  1984. {
  1985. void *cacheVal = uhash_get(gTZDBNamesMap, mzIDKey);
  1986. if (cacheVal == nullptr) {
  1987. UResourceBundle *zoneStringsRes = ures_openDirect(U_ICUDATA_ZONE, "tzdbNames", &status);
  1988. zoneStringsRes = ures_getByKey(zoneStringsRes, gZoneStrings, zoneStringsRes, &status);
  1989. if (U_SUCCESS(status)) {
  1990. char key[ZID_KEY_MAX + 1];
  1991. mergeTimeZoneKey(mzID, key);
  1992. tzdbNames = TZDBNames::createInstance(zoneStringsRes, key);
  1993. if (tzdbNames == nullptr) {
  1994. cacheVal = (void *)EMPTY;
  1995. } else {
  1996. cacheVal = tzdbNames;
  1997. }
  1998. // Use the persistent ID as the resource key, so we can
  1999. // avoid duplications.
  2000. // TODO: Is there a more efficient way, like intern() in Java?
  2001. void* newKey = (void*) ZoneMeta::findMetaZoneID(mzID);
  2002. if (newKey != nullptr) {
  2003. uhash_put(gTZDBNamesMap, newKey, cacheVal, &status);
  2004. if (U_FAILURE(status)) {
  2005. if (tzdbNames != nullptr) {
  2006. delete tzdbNames;
  2007. tzdbNames = nullptr;
  2008. }
  2009. }
  2010. } else {
  2011. // Should never happen with a valid input
  2012. if (tzdbNames != nullptr) {
  2013. // It's not possible that we get a valid tzdbNames with unknown ID.
  2014. // But just in case..
  2015. delete tzdbNames;
  2016. tzdbNames = nullptr;
  2017. }
  2018. }
  2019. }
  2020. ures_close(zoneStringsRes);
  2021. } else if (cacheVal != EMPTY) {
  2022. tzdbNames = (TZDBNames *)cacheVal;
  2023. }
  2024. }
  2025. umtx_unlock(&gTZDBNamesMapLock);
  2026. return tzdbNames;
  2027. }
  2028. U_NAMESPACE_END
  2029. #endif /* #if !UCONFIG_NO_FORMATTING */
  2030. //eof