10596faeddefbf198de137d5e893708495ab1584cFredrik Roubert// © 2016 and later: Unicode, Inc. and others. 264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html 3b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/* 4b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru********************************************************************** 5fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* Copyright (c) 2003-2014, International Business Machines 6b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* Corporation and others. All Rights Reserved. 7b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru********************************************************************** 8b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* Author: Alan Liu 9b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* Created: July 10 2003 10b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* Since: ICU 2.8 11b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru********************************************************************** 12b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*/ 13b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "tzfile.h" // from Olson tzcode archive, copied to this dir 14b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 15b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#ifdef WIN32 16b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 17b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru #include <windows.h> 18b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru #undef min // windows.h/STL conflict 19b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru #undef max // windows.h/STL conflict 20b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // "identifier was truncated to 'number' characters" warning 21b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru #pragma warning(disable: 4786) 22b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 23b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#else 24b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 25b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru #include <unistd.h> 26b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru #include <stdio.h> 27b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru #include <dirent.h> 28b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru #include <string.h> 29b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru #include <sys/stat.h> 30b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 31b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif 32b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 33b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include <algorithm> 34b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include <cassert> 35b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include <ctime> 36b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include <fstream> 37b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include <iomanip> 38b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include <iostream> 39b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include <iterator> 40b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include <limits> 41b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include <map> 42b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include <set> 43b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include <sstream> 44b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include <sstream> 45b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include <stdexcept> 46b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include <string> 47b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include <vector> 48b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 49b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "tz2icu.h" 50b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/uversion.h" 51b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 52b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruusing namespace std; 53b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 5450294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehobool ICU44PLUS = TRUE; 5550294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostring TZ_RESOURCE_NAME = ICU_TZ_RESOURCE; 5650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 57b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-------------------------------------------------------------------- 58b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// Time utilities 59b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-------------------------------------------------------------------- 60b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 61b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruconst int64_t SECS_PER_YEAR = 31536000; // 365 days 62b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruconst int64_t SECS_PER_LEAP_YEAR = 31622400; // 366 days 63b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruconst int64_t LOWEST_TIME32 = (int64_t)((int32_t)0x80000000); 64b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruconst int64_t HIGHEST_TIME32 = (int64_t)((int32_t)0x7fffffff); 65b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 66b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querubool isLeap(int32_t y) { 67b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return (y%4 == 0) && ((y%100 != 0) || (y%400 == 0)); // Gregorian 68b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 69b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 70b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruint64_t secsPerYear(int32_t y) { 71b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return isLeap(y) ? SECS_PER_LEAP_YEAR : SECS_PER_YEAR; 72b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 73b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 74b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/** 75b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Given a calendar year, return the GMT epoch seconds for midnight 76b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * GMT of January 1 of that year. yearToSeconds(1970) == 0. 77b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 78b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruint64_t yearToSeconds(int32_t year) { 79b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // inefficient but foolproof 80b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int64_t s = 0; 81b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t y = 1970; 82b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru while (y < year) { 83b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru s += secsPerYear(y++); 84b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 85b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru while (y > year) { 86b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru s -= secsPerYear(--y); 87b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 88b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return s; 89b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 90b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 91b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/** 92b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Given 1970 GMT epoch seconds, return the calendar year containing 93b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * that time. secondsToYear(0) == 1970. 94b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 95b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruint32_t secondsToYear(int64_t seconds) { 96b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // inefficient but foolproof 97b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t y = 1970; 98b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int64_t s = 0; 99b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (seconds >= 0) { 100b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (;;) { 101b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru s += secsPerYear(y++); 102b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (s > seconds) break; 103b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 104b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru --y; 105b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else { 106b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (;;) { 107b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru s -= secsPerYear(--y); 108b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (s <= seconds) break; 109b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 110b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 111b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return y; 112b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 113b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 114b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-------------------------------------------------------------------- 115b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// Types 116b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-------------------------------------------------------------------- 117b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 118b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustruct FinalZone; 119b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustruct FinalRule; 120b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustruct SimplifiedZoneType; 121b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 122b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// A transition from one ZoneType to another 123b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// Minimal size = 5 bytes (4+1) 124b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustruct Transition { 125b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int64_t time; // seconds, 1970 epoch 126b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t type; // index into 'ZoneInfo.types' 0..255 127b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru Transition(int64_t _time, int32_t _type) { 128b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru time = _time; 129b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru type = _type; 130b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 131b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}; 132b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 133b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// A behavior mode (what zic calls a 'type') of a time zone. 134b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// Minimal size = 6 bytes (4+1+3bits) 135b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// SEE: SimplifiedZoneType 136b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustruct ZoneType { 137b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int64_t rawoffset; // raw seconds offset from GMT 138b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int64_t dstoffset; // dst seconds offset from GMT 139b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 140b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // We don't really need any of the following, but they are 141b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // retained for possible future use. See SimplifiedZoneType. 142b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t abbr; // index into ZoneInfo.abbrs 0..n-1 143b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru bool isdst; 144b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru bool isstd; 145b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru bool isgmt; 146b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 147b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ZoneType(const SimplifiedZoneType&); // used by optimizeTypeList 148b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 149b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ZoneType() : rawoffset(-1), dstoffset(-1), abbr(-1) {} 150b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 151b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // A restricted equality, of just the raw and dst offset 152b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru bool matches(const ZoneType& other) { 153b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return rawoffset == other.rawoffset && 154b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru dstoffset == other.dstoffset; 155b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 156b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}; 157b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 158b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// A collection of transitions from one ZoneType to another, together 159b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// with a list of the ZoneTypes. A ZoneInfo object may have a long 160b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// list of transitions between a smaller list of ZoneTypes. 161b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// 162b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// This object represents the contents of a single zic-created 163b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// zoneinfo file. 164b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustruct ZoneInfo { 165b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru vector<Transition> transitions; 166b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru vector<ZoneType> types; 167b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru vector<string> abbrs; 168b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 169b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru string finalRuleID; 170b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t finalOffset; 171b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t finalYear; // -1 if none 172b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 173b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // If this is an alias, then all other fields are meaningless, and 174b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // this field will point to the "real" zone 0..n-1. 175b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t aliasTo; // -1 if this is a "real" zone 176b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 177b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // If there are aliases TO this zone, then the following set will 178b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // contain their index numbers (each index >= 0). 179b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru set<int32_t> aliases; 180b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 181b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ZoneInfo() : finalYear(-1), aliasTo(-1) {} 182b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 183b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru void mergeFinalData(const FinalZone& fz); 184b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 185b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru void optimizeTypeList(); 186b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 187b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Set this zone to be an alias TO another zone. 188b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru void setAliasTo(int32_t index); 189b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 190b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Clear the list of aliases OF this zone. 191b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru void clearAliases(); 192b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 193b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Add an alias to the list of aliases OF this zone. 194b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru void addAlias(int32_t index); 195b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 196b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Is this an alias to another zone? 197b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru bool isAlias() const { 198b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return aliasTo >= 0; 199b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 200b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 201b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Retrieve alias list 202b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru const set<int32_t>& getAliases() const { 203b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return aliases; 204b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 205b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 206b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru void print(ostream& os, const string& id) const; 207b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}; 208b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 209b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid ZoneInfo::clearAliases() { 210b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru assert(aliasTo < 0); 211b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru aliases.clear(); 212b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 213b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 214b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid ZoneInfo::addAlias(int32_t index) { 215b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru assert(aliasTo < 0 && index >= 0 && aliases.find(index) == aliases.end()); 216b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru aliases.insert(index); 217b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 218b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 219b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid ZoneInfo::setAliasTo(int32_t index) { 220b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru assert(index >= 0); 221b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru assert(aliases.size() == 0); 222b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru aliasTo = index; 223b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 224b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 225b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querutypedef map<string, ZoneInfo> ZoneMap; 226b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 227b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querutypedef ZoneMap::const_iterator ZoneMapIter; 228b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 229b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-------------------------------------------------------------------- 230b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// ZONEINFO 231b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-------------------------------------------------------------------- 232b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 233b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// Global map holding all our ZoneInfo objects, indexed by id. 234b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruZoneMap ZONEINFO; 235b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 236b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-------------------------------------------------------------------- 237b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// zoneinfo file parsing 238b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-------------------------------------------------------------------- 239b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 240b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// Read zic-coded 32-bit integer from file 241b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruint64_t readcoded(ifstream& file, int64_t minv=numeric_limits<int64_t>::min(), 242b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int64_t maxv=numeric_limits<int64_t>::max()) { 243b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru unsigned char buf[4]; // must be UNSIGNED 244b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int64_t val=0; 245b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru file.read((char*)buf, 4); 246b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for(int32_t i=0,shift=24;i<4;++i,shift-=8) { 247b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru val |= buf[i] << shift; 248b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 249b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (val < minv || val > maxv) { 250b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ostringstream os; 251b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << "coded value out-of-range: " << val << ", expected [" 252b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << minv << ", " << maxv << "]"; 253b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw out_of_range(os.str()); 254b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 255b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return val; 256b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 257b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 258b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// Read zic-coded 64-bit integer from file 259b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruint64_t readcoded64(ifstream& file, int64_t minv=numeric_limits<int64_t>::min(), 260b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int64_t maxv=numeric_limits<int64_t>::max()) { 261b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru unsigned char buf[8]; // must be UNSIGNED 262b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int64_t val=0; 263b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru file.read((char*)buf, 8); 264b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for(int32_t i=0,shift=56;i<8;++i,shift-=8) { 265b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru val |= (int64_t)buf[i] << shift; 266b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 267b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (val < minv || val > maxv) { 268b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ostringstream os; 269b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << "coded value out-of-range: " << val << ", expected [" 270b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << minv << ", " << maxv << "]"; 271b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw out_of_range(os.str()); 272b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 273b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return val; 274b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 275b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 276b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// Read a boolean value 277b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querubool readbool(ifstream& file) { 278b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru char c; 279b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru file.read(&c, 1); 280b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (c!=0 && c!=1) { 281b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ostringstream os; 282b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << "boolean value out-of-range: " << (int32_t)c; 283b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw out_of_range(os.str()); 284b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 285b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return (c!=0); 286b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 287b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 288b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/** 289b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Read the zoneinfo file structure (see tzfile.h) into a ZoneInfo 290b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param file an already-open file stream 291b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 29250294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehovoid readzoneinfo(ifstream& file, ZoneInfo& info, bool is64bitData) { 293b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t i; 294b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 295b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Check for TZ_ICU_MAGIC signature at file start. If we get a 296b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // signature mismatch, it means we're trying to read a file which 297b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // isn't a ICU-modified-zic-created zoneinfo file. Typically this 298b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // means the user is passing in a "normal" zoneinfo directory, or 299b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // a zoneinfo directory that is polluted with other files, or that 300b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // the user passed in the wrong directory. 301b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru char buf[32]; 302b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru file.read(buf, 4); 303b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (strncmp(buf, TZ_ICU_MAGIC, 4) != 0) { 304b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw invalid_argument("TZ_ICU_MAGIC signature missing"); 305b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 306b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // skip additional Olson byte version 307b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru file.read(buf, 1); 308f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius // if '\0', we have just one copy of data, if '2' or '3', there is additional 309b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // 64 bit version at the end. 310f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius if(buf[0]!=0 && buf[0]!='2' && buf[0]!='3') { 311b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw invalid_argument("Bad Olson version info"); 312b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 313b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 314b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Read reserved bytes. The first of these will be a version byte. 315b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru file.read(buf, 15); 316b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (*(ICUZoneinfoVersion*)&buf != TZ_ICU_VERSION) { 317b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw invalid_argument("File version mismatch"); 318b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 319b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 320b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Read array sizes 321b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int64_t isgmtcnt = readcoded(file, 0); 322b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int64_t isdstcnt = readcoded(file, 0); 323b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int64_t leapcnt = readcoded(file, 0); 324b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int64_t timecnt = readcoded(file, 0); 325b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int64_t typecnt = readcoded(file, 0); 326b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int64_t charcnt = readcoded(file, 0); 327b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 328b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Confirm sizes that we assume to be equal. These assumptions 329b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // are drawn from a reading of the zic source (2003a), so they 330b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // should hold unless the zic source changes. 331b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (isgmtcnt != typecnt || isdstcnt != typecnt) { 332b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw invalid_argument("count mismatch between tzh_ttisgmtcnt, tzh_ttisdstcnt, tth_typecnt"); 333b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 334b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 335b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Used temporarily to store transition times and types. We need 336b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // to do this because the times and types are stored in two 337b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // separate arrays. 338b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru vector<int64_t> transitionTimes(timecnt, -1); // temporary 339b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru vector<int32_t> transitionTypes(timecnt, -1); // temporary 340b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 341b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Read transition times 342b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (i=0; i<timecnt; ++i) { 343b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (is64bitData) { 344b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru transitionTimes[i] = readcoded64(file); 345b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else { 346b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru transitionTimes[i] = readcoded(file); 347b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 348b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 349b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 350b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Read transition types 351b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (i=0; i<timecnt; ++i) { 352b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru unsigned char c; 353b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru file.read((char*) &c, 1); 354b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t t = (int32_t) c; 355b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (t < 0 || t >= typecnt) { 356b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ostringstream os; 357b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << "illegal type: " << t << ", expected [0, " << (typecnt-1) << "]"; 358b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw out_of_range(os.str()); 359b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 360b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru transitionTypes[i] = t; 361b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 362b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 363b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Build transitions vector out of corresponding times and types. 364b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru bool insertInitial = false; 36550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (is64bitData && !ICU44PLUS) { 366b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (timecnt > 0) { 367b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t minidx = -1; 368b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (i=0; i<timecnt; ++i) { 369b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (transitionTimes[i] < LOWEST_TIME32) { 370b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (minidx == -1 || transitionTimes[i] > transitionTimes[minidx]) { 371b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Preserve the latest transition before the 32bit minimum time 372b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru minidx = i; 373b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 374b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru } else if (transitionTimes[i] > HIGHEST_TIME32) { 375b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // Skipping the rest of the transition data. We cannot put such 376b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // transitions into zoneinfo.res, because data is limited to singed 377b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru // 32bit int by the ICU resource bundle. 378b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru break; 379b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else { 380b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru info.transitions.push_back(Transition(transitionTimes[i], transitionTypes[i])); 381b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 382b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 383b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 384b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (minidx != -1) { 385b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // If there are any transitions before the 32bit minimum time, 386b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // put the type information with the 32bit minimum time 387b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru vector<Transition>::iterator itr = info.transitions.begin(); 388b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru info.transitions.insert(itr, Transition(LOWEST_TIME32, transitionTypes[minidx])); 389b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else { 390b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Otherwise, we need insert the initial type later 391b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru insertInitial = true; 392b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 393b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 394b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else { 395b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (i=0; i<timecnt; ++i) { 396b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru info.transitions.push_back(Transition(transitionTimes[i], transitionTypes[i])); 397b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 398b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 399b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 400b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Read types (except for the isdst and isgmt flags, which come later (why??)) 401b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (i=0; i<typecnt; ++i) { 402b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ZoneType type; 403b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 404b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru type.rawoffset = readcoded(file); 405b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru type.dstoffset = readcoded(file); 406b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru type.isdst = readbool(file); 407b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 408b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru unsigned char c; 409b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru file.read((char*) &c, 1); 410b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru type.abbr = (int32_t) c; 411b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 412b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (type.isdst != (type.dstoffset != 0)) { 413b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw invalid_argument("isdst does not reflect dstoffset"); 414b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 415b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 416b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru info.types.push_back(type); 417b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 418b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 419b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru assert(info.types.size() == (unsigned) typecnt); 420b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 421b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (insertInitial) { 422b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru assert(timecnt > 0); 423b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru assert(typecnt > 0); 424b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 425b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t initialTypeIdx = -1; 426b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 427b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Check if the first type is not dst 428b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (info.types.at(0).dstoffset != 0) { 429b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Initial type's rawoffset is same with the rawoffset after the 430b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // first transition, but no DST is observed. 431b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int64_t rawoffset0 = (info.types.at(info.transitions.at(0).type)).rawoffset; 432b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Look for matching type 433b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (i=0; i<(int32_t)info.types.size(); ++i) { 434b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (info.types.at(i).rawoffset == rawoffset0 435b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru && info.types.at(i).dstoffset == 0) { 436b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru initialTypeIdx = i; 437b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru break; 438b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 439b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 440b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else { 44150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho initialTypeIdx = 0; 442b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 443b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru assert(initialTypeIdx >= 0); 444b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Add the initial type associated with the lowest int32 time 445b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru vector<Transition>::iterator itr = info.transitions.begin(); 446b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru info.transitions.insert(itr, Transition(LOWEST_TIME32, initialTypeIdx)); 447b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 448b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 449b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 450b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Read the abbreviation string 451b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (charcnt) { 452b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // All abbreviations are concatenated together, with a 0 at 453b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // the end of each abbr. 454b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru char* str = new char[charcnt + 8]; 455b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru file.read(str, charcnt); 456b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 457b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Split abbreviations apart into individual strings. Record 458b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // offset of each abbr in a vector. 459b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru vector<int32_t> abbroffset; 460b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru char *limit=str+charcnt; 461b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (char* p=str; p<limit; ++p) { 462b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru char* start = p; 463b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru while (*p != 0) ++p; 464b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru info.abbrs.push_back(string(start, p-start)); 465b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru abbroffset.push_back(start-str); 466b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 467b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 468b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Remap all the abbrs. Old value is offset into concatenated 469b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // raw abbr strings. New value is index into vector of 470b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // strings. E.g., 0,5,10,14 => 0,1,2,3. 471b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 472b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Keep track of which abbreviations get used. 473b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru vector<bool> abbrseen(abbroffset.size(), false); 474b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 475b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (vector<ZoneType>::iterator it=info.types.begin(); 476b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru it!=info.types.end(); 477b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ++it) { 478b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru vector<int32_t>::const_iterator x= 479b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru find(abbroffset.begin(), abbroffset.end(), it->abbr); 480b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (x==abbroffset.end()) { 481b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // TODO: Modify code to add a new string to the end of 482b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // the abbr list when a middle offset is given, e.g., 483b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // "abc*def*" where * == '\0', take offset of 1 and 484b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // make the array "abc", "def", "bc", and translate 1 485b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // => 2. NOT CRITICAL since we don't even use the 486b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // abbr at this time. 487b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#if 0 488b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // TODO: Re-enable this warning if we start using 489b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // the Olson abbr data, or if the above TODO is completed. 490b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ostringstream os; 491b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << "Warning: unusual abbr offset " << it->abbr 492b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << ", expected one of"; 493b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (vector<int32_t>::const_iterator y=abbroffset.begin(); 494b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru y!=abbroffset.end(); ++y) { 495b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << ' ' << *y; 496b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 497b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru cerr << os.str() << "; using 0" << endl; 498b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif 499b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru it->abbr = 0; 500b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else { 501b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t index = x - abbroffset.begin(); 502b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru it->abbr = index; 503b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru abbrseen[index] = true; 504b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 505b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 506b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 507b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (int32_t ii=0;ii<(int32_t) abbrseen.size();++ii) { 508b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (!abbrseen[ii]) { 509b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru cerr << "Warning: unused abbreviation: " << ii << endl; 510b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 511b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 512b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 513b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 514b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Read leap second info, if any. 515b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // *** We discard leap second data. *** 516b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (i=0; i<leapcnt; ++i) { 517b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru readcoded(file); // transition time 518b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru readcoded(file); // total correction after above 519b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 520b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 521b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Read isstd flags 522b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (i=0; i<typecnt; ++i) info.types[i].isstd = readbool(file); 523b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 524b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Read isgmt flags 525b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (i=0; i<typecnt; ++i) info.types[i].isgmt = readbool(file); 526b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 527b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 528b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-------------------------------------------------------------------- 529b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// Directory and file reading 530b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-------------------------------------------------------------------- 531b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 532b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/** 533b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Process a single zoneinfo file, adding the data to ZONEINFO 534b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param path the full path to the file, e.g., ".\zoneinfo\America\Los_Angeles" 535b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param id the zone ID, e.g., "America/Los_Angeles" 536b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 537b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid handleFile(string path, string id) { 538b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Check for duplicate id 539b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (ZONEINFO.find(id) != ZONEINFO.end()) { 540b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ostringstream os; 541b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << "duplicate zone ID: " << id; 542b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw invalid_argument(os.str()); 543b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 544b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 545b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ifstream file(path.c_str(), ios::in | ios::binary); 546b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (!file) { 547b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw invalid_argument("can't open file"); 548b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 549b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 55050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // eat 32bit data part 551b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ZoneInfo info; 55250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho readzoneinfo(file, info, false); 553b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 554b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Check for errors 555b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (!file) { 556b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw invalid_argument("read error"); 557b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 558b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 55950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // we only use 64bit part 560b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ZoneInfo info64; 561b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru readzoneinfo(file, info64, true); 562b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 563b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru bool alldone = false; 564b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int64_t eofPos = (int64_t) file.tellg(); 565b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 566b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // '\n' + <envvar string> + '\n' after the 64bit version data 567b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru char ch = file.get(); 568b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (ch == 0x0a) { 569b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru bool invalidchar = false; 570b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru while (file.get(ch)) { 571b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (ch == 0x0a) { 572b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru break; 573b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 574b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (ch < 0x20) { 575b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // must be printable ascii 576b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru invalidchar = true; 577b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru break; 578b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 579b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 580b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (!invalidchar) { 581b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru eofPos = (int64_t) file.tellg(); 582b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru file.seekg(0, ios::end); 583b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru eofPos = eofPos - (int64_t) file.tellg(); 584b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (eofPos == 0) { 585b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru alldone = true; 586b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 587b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 588b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 589b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (!alldone) { 590b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ostringstream os; 591b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << (-eofPos) << " unprocessed bytes at end"; 592b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw invalid_argument(os.str()); 593b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 594b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 595b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ZONEINFO[id] = info64; 596b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 597b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 598b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/** 599b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Recursively scan the given directory, calling handleFile() for each 600b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * file in the tree. The user should call with the root directory and 601b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * a prefix of "". The function will call itself with non-empty 602b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * prefix values. 603b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 604b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#ifdef WIN32 605b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 606b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid scandir(string dirname, string prefix="") { 607b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru HANDLE hList; 608b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru WIN32_FIND_DATA FileData; 609b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 610b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Get the first file 611b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru hList = FindFirstFile((dirname + "\\*").c_str(), &FileData); 612b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (hList == INVALID_HANDLE_VALUE) { 613b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru cerr << "Error: Invalid directory: " << dirname << endl; 614b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru exit(1); 615b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 616b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (;;) { 617b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru string name(FileData.cFileName); 618b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru string path(dirname + "\\" + name); 619b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 620b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (name != "." && name != "..") { 621b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru scandir(path, prefix + name + "/"); 622b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 623b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else { 624b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru try { 625b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru string id = prefix + name; 626b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru handleFile(path, id); 627b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } catch (const exception& e) { 628b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru cerr << "Error: While processing \"" << path << "\", " 629b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << e.what() << endl; 630b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru exit(1); 631b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 632b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 633b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 634b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (!FindNextFile(hList, &FileData)) { 635b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (GetLastError() == ERROR_NO_MORE_FILES) { 636b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru break; 637b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } // else...? 638b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 639b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 640b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru FindClose(hList); 641b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 642b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 643b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#else 644b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 645b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid scandir(string dir, string prefix="") { 646b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru DIR *dp; 647b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru struct dirent *dir_entry; 648b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru struct stat stat_info; 649b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru char pwd[512]; 650b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru vector<string> subdirs; 651b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru vector<string> subfiles; 652b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 653b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if ((dp = opendir(dir.c_str())) == NULL) { 654b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru cerr << "Error: Invalid directory: " << dir << endl; 655b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru exit(1); 656b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 657b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (!getcwd(pwd, sizeof(pwd))) { 658b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru cerr << "Error: Directory name too long" << endl; 659b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru exit(1); 660b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 661b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru chdir(dir.c_str()); 662b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru while ((dir_entry = readdir(dp)) != NULL) { 663b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru string name = dir_entry->d_name; 664b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru string path = dir + "/" + name; 665b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru lstat(dir_entry->d_name,&stat_info); 666b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (S_ISDIR(stat_info.st_mode)) { 667b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (name != "." && name != "..") { 668b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru subdirs.push_back(path); 669b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru subdirs.push_back(prefix + name + "/"); 670b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // scandir(path, prefix + name + "/"); 671b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 672b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else { 673b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru try { 674b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru string id = prefix + name; 675b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru subfiles.push_back(path); 676b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru subfiles.push_back(id); 677b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // handleFile(path, id); 678b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } catch (const exception& e) { 679b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru cerr << "Error: While processing \"" << path << "\", " 680b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << e.what() << endl; 681b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru exit(1); 682b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 683b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 684b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 685b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru closedir(dp); 686b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru chdir(pwd); 687b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 688b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for(int32_t i=0;i<(int32_t)subfiles.size();i+=2) { 689b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru try { 690b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru handleFile(subfiles[i], subfiles[i+1]); 691b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } catch (const exception& e) { 692b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru cerr << "Error: While processing \"" << subfiles[i] << "\", " 693b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << e.what() << endl; 694b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru exit(1); 695b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 696b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 697b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for(int32_t i=0;i<(int32_t)subdirs.size();i+=2) { 698b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru scandir(subdirs[i], subdirs[i+1]); 699b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 700b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 701b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 702b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif 703b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 704b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-------------------------------------------------------------------- 705b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// Final zone and rule info 706b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-------------------------------------------------------------------- 707b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 708b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/** 709b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Read and discard the current line. 710b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 711b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid consumeLine(istream& in) { 712b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t c; 713b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru do { 714b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru c = in.get(); 715b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } while (c != EOF && c != '\n'); 716b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 717b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 718b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruenum { 719b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru DOM = 0, 720b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru DOWGEQ = 1, 721b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru DOWLEQ = 2 722b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}; 723b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 724b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruconst char* TIME_MODE[] = {"w", "s", "u"}; 725b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 726b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// Allow 29 days in February because zic outputs February 29 727b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// for rules like "last Sunday in February". 728b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruconst int32_t MONTH_LEN[] = {31,29,31,30,31,30,31,31,30,31,30,31}; 729b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 730b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruconst int32_t HOUR = 3600; 731b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 732b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustruct FinalZone { 733b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t offset; // raw offset 734b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t year; // takes effect for y >= year 735b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru string ruleid; 736b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru set<string> aliases; 737b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru FinalZone(int32_t _offset, int32_t _year, const string& _ruleid) : 738b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru offset(_offset), year(_year), ruleid(_ruleid) { 739b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (offset <= -16*HOUR || offset >= 16*HOUR) { 740b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ostringstream os; 741b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << "Invalid input offset " << offset 742b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << " for year " << year 743b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << " and rule ID " << ruleid; 744b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw invalid_argument(os.str()); 745b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 746c7d806c5cbbacca0827c1059d1b1a073b0fae214Neil Fuller if (year < 1900) { 747b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ostringstream os; 748b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << "Invalid input year " << year 749b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << " with offset " << offset 750b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << " and rule ID " << ruleid; 751b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw invalid_argument(os.str()); 752b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 753b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 754b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru FinalZone() : offset(-1), year(-1) {} 755b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru void addLink(const string& alias) { 756b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (aliases.find(alias) != aliases.end()) { 757b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ostringstream os; 758b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << "Duplicate alias " << alias; 759b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw invalid_argument(os.str()); 760b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 761b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru aliases.insert(alias); 762b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 763b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}; 764b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 765b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustruct FinalRulePart { 766b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t mode; 767b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t month; 768b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t dom; 769b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t dow; 770b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t time; 771b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t offset; // dst offset, usually either 0 or 1:00 772b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 773b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Isstd and isgmt only have 3 valid states, corresponding to local 774b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // wall time, local standard time, and GMT standard time. 775b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Here is how the isstd & isgmt flags are set by zic: 776b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru //| case 's': /* Standard */ 777b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru //| rp->r_todisstd = TRUE; 778b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru //| rp->r_todisgmt = FALSE; 779b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru //| case 'w': /* Wall */ 780b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru //| rp->r_todisstd = FALSE; 781b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru //| rp->r_todisgmt = FALSE; 782b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru //| case 'g': /* Greenwich */ 783b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru //| case 'u': /* Universal */ 784b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru //| case 'z': /* Zulu */ 785b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru //| rp->r_todisstd = TRUE; 786b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru //| rp->r_todisgmt = TRUE; 787b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru bool isstd; 788b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru bool isgmt; 789b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 790b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru bool isset; // used during building; later ignored 791b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 792b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru FinalRulePart() : isset(false) {} 793b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru void set(const string& id, 794b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru const string& _mode, 795b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t _month, 796b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t _dom, 797b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t _dow, 798b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t _time, 799b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru bool _isstd, 800b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru bool _isgmt, 801b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t _offset) { 802b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (isset) { 803b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw invalid_argument("FinalRulePart set twice"); 804b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 805b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru isset = true; 806b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (_mode == "DOWLEQ") { 807b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mode = DOWLEQ; 808b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else if (_mode == "DOWGEQ") { 809b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mode = DOWGEQ; 810b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else if (_mode == "DOM") { 811b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mode = DOM; 812b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else { 813b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw invalid_argument("Unrecognized FinalRulePart mode"); 814b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 815b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru month = _month; 816b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru dom = _dom; 817b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru dow = _dow; 818b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru time = _time; 819b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru isstd = _isstd; 820b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru isgmt = _isgmt; 821b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru offset = _offset; 822b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 823b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ostringstream os; 824b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (month < 0 || month >= 12) { 825b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << "Invalid input month " << month; 826b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 827b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (dom < 1 || dom > MONTH_LEN[month]) { 828b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << "Invalid input day of month " << dom; 829b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 830b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (mode != DOM && (dow < 0 || dow >= 7)) { 831b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << "Invalid input day of week " << dow; 832b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 83306e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller if (offset < (-1 * HOUR) || offset > (2 * HOUR)) { 834b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << "Invalid input offset " << offset; 835b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 836b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (isgmt && !isstd) { 837b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << "Invalid input isgmt && !isstd"; 838b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 839b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (!os.str().empty()) { 840b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << " for rule " 841b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << id 842b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << _mode 843b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << month << dom << dow << time 844b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << isstd << isgmt 845b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << offset; 846b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw invalid_argument(os.str()); 847b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 848b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 849b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 850b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 851b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Return the time mode as an ICU SimpleTimeZone int from 0..2; 852b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * see simpletz.h. 853b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 854b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t timemode() const { 855b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (isgmt) { 856b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru assert(isstd); 857b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return 2; // gmt standard 858b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 859b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (isstd) { 860b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return 1; // local standard 861b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 862b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return 0; // local wall 863b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 864b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 865b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // The SimpleTimeZone encoding method for rules is as follows: 866b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // stz_dowim stz_dow 867b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // DOM: dom 0 868b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // DOWGEQ: dom -(dow+1) 869b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // DOWLEQ: -dom -(dow+1) 870b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // E.g., to encode Mon>=7, use stz_dowim=7, stz_dow=-2 871b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // to encode Mon<=7, use stz_dowim=-7, stz_dow=-2 872b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // to encode 7, use stz_dowim=7, stz_dow=0 873b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Note that for this program and for SimpleTimeZone, 0==Jan, 874b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // but for this program 0==Sun while for SimpleTimeZone 1==Sun. 875b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 876b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 877b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Return a "dowim" param suitable for SimpleTimeZone. 878b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 879b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t stz_dowim() const { 880b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return (mode == DOWLEQ) ? -dom : dom; 881b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 882b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 883b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru /** 884b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Return a "dow" param suitable for SimpleTimeZone. 885b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 886b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t stz_dow() const { 887b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return (mode == DOM) ? 0 : -(dow+1); 888b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 889b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}; 890b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 891b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustruct FinalRule { 892b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru FinalRulePart part[2]; 893b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 894b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru bool isset() const { 895b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return part[0].isset && part[1].isset; 896b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 897b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 898b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru void print(ostream& os) const; 899b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}; 900b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 901b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querumap<string,FinalZone> finalZones; 902b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querumap<string,FinalRule> finalRules; 903b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 904b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querumap<string, set<string> > links; 905b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querumap<string, string> reverseLinks; 906b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 907b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/** 908b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Predicate used to find FinalRule objects that do not have both 909b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * sub-parts set (indicating an error in the input file). 910b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 911b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querubool isNotSet(const pair<const string,FinalRule>& p) { 912b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return !p.second.isset(); 913b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 914b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 915b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/** 916b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Predicate used to find FinalZone objects that do not map to a known 917b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * rule (indicating an error in the input file). 918b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 919b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querubool mapsToUnknownRule(const pair<const string,FinalZone>& p) { 920b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return finalRules.find(p.second.ruleid) == finalRules.end(); 921b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 922b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 923b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/** 924b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * This set is used to make sure each rule in finalRules is used at 925b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * least once. First we populate it with all the rules from 926b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * finalRules; then we remove all the rules referred to in 927b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * finaleZones. 928b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 929b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruset<string> ruleIDset; 930b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 931b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid insertRuleID(const pair<string,FinalRule>& p) { 932b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ruleIDset.insert(p.first); 933b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 934b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 935b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid eraseRuleID(const pair<string,FinalZone>& p) { 936b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ruleIDset.erase(p.second.ruleid); 937b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 938b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 939b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/** 940b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Populate finalZones and finalRules from the given istream. 941b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 942b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid readFinalZonesAndRules(istream& in) { 943b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 944b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (;;) { 945b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru string token; 946b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru in >> token; 947b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (in.eof() || !in) { 948b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru break; 949b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else if (token == "zone") { 950b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // zone Africa/Cairo 7200 1995 Egypt # zone Africa/Cairo, offset 7200, year >= 1995, rule Egypt (0) 951b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru string id, ruleid; 952b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t offset, year; 953b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru in >> id >> offset >> year >> ruleid; 954b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru consumeLine(in); 955b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru finalZones[id] = FinalZone(offset, year, ruleid); 956b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else if (token == "rule") { 957b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // rule US DOWGEQ 3 1 0 7200 0 0 3600 # 52: US, file data/northamerica, line 119, mode DOWGEQ, April, dom 1, Sunday, time 7200, isstd 0, isgmt 0, offset 3600 958b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // rule US DOWLEQ 9 31 0 7200 0 0 0 # 53: US, file data/northamerica, line 114, mode DOWLEQ, October, dom 31, Sunday, time 7200, isstd 0, isgmt 0, offset 0 959b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru string id, mode; 960b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t month, dom, dow, time, offset; 961b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru bool isstd, isgmt; 962b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru in >> id >> mode >> month >> dom >> dow >> time >> isstd >> isgmt >> offset; 963b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru consumeLine(in); 964b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru FinalRule& fr = finalRules[id]; 965b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t p = fr.part[0].isset ? 1 : 0; 966b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru fr.part[p].set(id, mode, month, dom, dow, time, isstd, isgmt, offset); 967b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else if (token == "link") { 968b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru string fromid, toid; // fromid == "real" zone, toid == alias 969b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru in >> fromid >> toid; 970b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // DO NOT consumeLine(in); 971b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (finalZones.find(toid) != finalZones.end()) { 972b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw invalid_argument("Bad link: `to' id is a \"real\" zone"); 973b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 974b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 975b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru links[fromid].insert(toid); 976b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru reverseLinks[toid] = fromid; 977b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else if (token.length() > 0 && token[0] == '#') { 978b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru consumeLine(in); 979b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else { 980b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw invalid_argument("Unrecognized keyword"); 981b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 982b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 983b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 984b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (!in.eof() && !in) { 985b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw invalid_argument("Parse failure"); 986b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 987b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 988b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Perform validity check: Each rule should have data for 2 parts. 989b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (count_if(finalRules.begin(), finalRules.end(), isNotSet) != 0) { 990b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw invalid_argument("One or more incomplete rule pairs"); 991b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 992b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 993b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Perform validity check: Each zone should map to a known rule. 994b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (count_if(finalZones.begin(), finalZones.end(), mapsToUnknownRule) != 0) { 995b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw invalid_argument("One or more zones refers to an unknown rule"); 996b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 997b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 998b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Perform validity check: Each rule should be referred to by a zone. 999b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ruleIDset.clear(); 1000b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for_each(finalRules.begin(), finalRules.end(), insertRuleID); 1001b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for_each(finalZones.begin(), finalZones.end(), eraseRuleID); 1002b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (ruleIDset.size() != 0) { 1003b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw invalid_argument("Unused rules"); 1004b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1005b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 1006b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1007b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-------------------------------------------------------------------- 1008b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// Resource bundle output 1009b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-------------------------------------------------------------------- 1010b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1011b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// SEE olsontz.h FOR RESOURCE BUNDLE DATA LAYOUT 1012b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1013b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid ZoneInfo::print(ostream& os, const string& id) const { 1014b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Implement compressed format #2: 1015b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << " /* " << id << " */ "; 1016b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1017b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (aliasTo >= 0) { 1018b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru assert(aliases.size() == 0); 1019b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << ":int { " << aliasTo << " } "; // No endl - save room for comment. 1020b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return; 1021b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1022b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 102350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (ICU44PLUS) { 102450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << ":table {" << endl; 102550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 102650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << ":array {" << endl; 102750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 1028b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1029b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru vector<Transition>::const_iterator trn; 1030b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru vector<ZoneType>::const_iterator typ; 1031b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 103250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho bool first; 103350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 103450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (ICU44PLUS) { 103550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho trn = transitions.begin(); 103650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 103750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // pre 32bit transitions 103850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (trn != transitions.end() && trn->time < LOWEST_TIME32) { 103950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << " transPre32:intvector { "; 104050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho for (first = true; trn != transitions.end() && trn->time < LOWEST_TIME32; ++trn) { 104150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (!first) { 104250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os<< ", "; 104350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 104450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho first = false; 104550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << (int32_t)(trn->time >> 32) << ", " << (int32_t)(trn->time & 0x00000000ffffffff); 104650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 104750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << " }" << endl; 104850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 104950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 105050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // 32bit transtions 105150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (trn != transitions.end() && trn->time < HIGHEST_TIME32) { 105250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << " trans:intvector { "; 105350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho for (first = true; trn != transitions.end() && trn->time < HIGHEST_TIME32; ++trn) { 105450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (!first) { 105550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << ", "; 105650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 105750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho first = false; 105850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << trn->time; 105950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 106050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << " }" << endl; 106150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 106250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 106350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // post 32bit transitons 106450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (trn != transitions.end()) { 106550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << " transPost32:intvector { "; 106650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho for (first = true; trn != transitions.end(); ++trn) { 106750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (!first) { 106850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os<< ", "; 106950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 107050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho first = false; 107150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << (int32_t)(trn->time >> 32) << ", " << (int32_t)(trn->time & 0x00000000ffffffff); 107250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 107350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << " }" << endl; 107450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 107550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 107650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << " :intvector { "; 107750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho for (trn = transitions.begin(), first = true; trn != transitions.end(); ++trn) { 107850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (!first) os << ", "; 107950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho first = false; 108050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << trn->time; 108150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 108250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << " }" << endl; 1083b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 108450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 1085b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1086b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru first=true; 108750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (ICU44PLUS) { 108850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << " typeOffsets:intvector { "; 108950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 109050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << " :intvector { "; 109150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 1092b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (typ = types.begin(); typ != types.end(); ++typ) { 1093b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (!first) os << ", "; 1094b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru first = false; 1095b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << typ->rawoffset << ", " << typ->dstoffset; 1096b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1097b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << " }" << endl; 1098b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 109950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (ICU44PLUS) { 110050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (transitions.size() != 0) { 110150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << " typeMap:bin { \"" << hex << setfill('0'); 110250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho for (trn = transitions.begin(); trn != transitions.end(); ++trn) { 110350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << setw(2) << trn->type; 110450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 110550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << dec << "\" }" << endl; 110650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 110750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 110850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << " :bin { \"" << hex << setfill('0'); 110950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho for (trn = transitions.begin(); trn != transitions.end(); ++trn) { 111050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << setw(2) << trn->type; 111150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 111250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << dec << "\" }" << endl; 1113b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1114b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1115b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Final zone info, if any 1116b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (finalYear != -1) { 111750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (ICU44PLUS) { 111850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << " finalRule { \"" << finalRuleID << "\" }" << endl; 111950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << " finalRaw:int { " << finalOffset << " }" << endl; 112050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << " finalYear:int { " << finalYear << " }" << endl; 112150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 112250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << " \"" << finalRuleID << "\"" << endl; 112350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << " :intvector { " << finalOffset << ", " 112450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho << finalYear << " }" << endl; 112550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 1126b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1127b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1128b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Alias list, if any 1129b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (aliases.size() != 0) { 1130b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru first = true; 113150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (ICU44PLUS) { 113250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << " links:intvector { "; 113350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 113450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho os << " :intvector { "; 113550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 1136b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (set<int32_t>::const_iterator i=aliases.begin(); i!=aliases.end(); ++i) { 1137b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (!first) os << ", "; 1138b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru first = false; 1139b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << *i; 1140b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1141b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << " }" << endl; 1142b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1143b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1144b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << " } "; // no trailing 'endl', so comments can be placed. 1145b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 1146b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1147b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruinline ostream& 1148b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruoperator<<(ostream& os, const ZoneMap& zoneinfo) { 1149b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t c = 0; 1150b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (ZoneMapIter it = zoneinfo.begin(); 1151b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru it != zoneinfo.end(); 1152b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ++it) { 115350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if(c && !ICU44PLUS) os << ","; 1154b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru it->second.print(os, it->first); 1155b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << "//Z#" << c++ << endl; 1156b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1157b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return os; 1158b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 1159b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1160b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// print the string list 1161b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruostream& printStringList( ostream& os, const ZoneMap& zoneinfo) { 1162b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t n = 0; // count 1163b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t col = 0; // column 1164b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << " Names {" << endl 1165b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << " "; 1166b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (ZoneMapIter it = zoneinfo.begin(); 1167b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru it != zoneinfo.end(); 1168b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ++it) { 1169b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if(n) { 1170b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << ","; 1171b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru col ++; 1172b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1173b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru const string& id = it->first; 1174b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << "\"" << id << "\""; 1175b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru col += id.length() + 2; 1176b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if(col >= 50) { 1177b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << " // " << n << endl 1178b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << " "; 1179b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru col = 0; 1180b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1181b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru n++; 1182b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1183b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << " // " << (n-1) << endl 1184b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << " }" << endl; 1185b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1186b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return os; 1187b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 1188b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1189b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-------------------------------------------------------------------- 1190b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// main 1191b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//-------------------------------------------------------------------- 1192b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1193b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// Unary predicate for finding transitions after a given time 1194b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querubool isAfter(const Transition t, int64_t thresh) { 1195b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return t.time >= thresh; 1196b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 1197b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1198b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/** 1199b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * A zone type that contains only the raw and dst offset. Used by the 1200b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * optimizeTypeList() method. 1201b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 1202b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustruct SimplifiedZoneType { 1203b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int64_t rawoffset; 1204b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int64_t dstoffset; 1205b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru SimplifiedZoneType() : rawoffset(-1), dstoffset(-1) {} 1206b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru SimplifiedZoneType(const ZoneType& t) : rawoffset(t.rawoffset), 1207b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru dstoffset(t.dstoffset) {} 1208b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru bool operator<(const SimplifiedZoneType& t) const { 1209b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return rawoffset < t.rawoffset || 1210b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru (rawoffset == t.rawoffset && 1211b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru dstoffset < t.dstoffset); 1212b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1213b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}; 1214b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1215b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/** 1216b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Construct a ZoneType from a SimplifiedZoneType. Note that this 1217b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * discards information; the new ZoneType will have meaningless 1218b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * (empty) abbr, isdst, isstd, and isgmt flags; this is appropriate, 1219b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * since ignoring these is how we do optimization (we have no use for 1220b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * these in historical transitions). 1221b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 1222b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruZoneType::ZoneType(const SimplifiedZoneType& t) : 1223b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru rawoffset(t.rawoffset), dstoffset(t.dstoffset), 1224b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru abbr(-1), isdst(false), isstd(false), isgmt(false) {} 1225b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1226b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/** 1227b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Optimize the type list to remove excess entries. The type list may 1228b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * contain entries that are distinct only in terms of their dst, std, 1229b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * or gmt flags. Since we don't care about those flags, we can reduce 1230b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * the type list to a set of unique raw/dst offset pairs, and remap 1231b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * the type indices in the transition list, which stores, for each 1232b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * transition, a transition time and a type index. 1233b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 1234b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid ZoneInfo::optimizeTypeList() { 1235b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Assemble set of unique types; only those in the `transitions' 1236b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // list, since there may be unused types in the `types' list 1237b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // corresponding to transitions that have been trimmed (during 1238b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // merging of final data). 1239b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1240b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (aliasTo >= 0) return; // Nothing to do for aliases 1241b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 124250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (!ICU44PLUS) { 124350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // This is the old logic which has a bug, which occasionally removes 124450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // the type before the first transition. The problem was fixed 124550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // by inserting the dummy transition indirectly. 124650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 124750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // If there are zero transitions and one type, then leave that as-is. 124850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (transitions.size() == 0) { 124950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (types.size() != 1) { 125050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho cerr << "Error: transition count = 0, type count = " << types.size() << endl; 125150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 125250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho return; 1253b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1254b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 125550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho set<SimplifiedZoneType> simpleset; 125650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho for (vector<Transition>::const_iterator i=transitions.begin(); 125750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho i!=transitions.end(); ++i) { 125850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho assert(i->type < (int32_t)types.size()); 125950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho simpleset.insert(types[i->type]); 126050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 1261b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 126250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Map types to integer indices 126350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho map<SimplifiedZoneType,int32_t> simplemap; 126450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho int32_t n=0; 126550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho for (set<SimplifiedZoneType>::const_iterator i=simpleset.begin(); 126650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho i!=simpleset.end(); ++i) { 126750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho simplemap[*i] = n++; 126850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 126950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 127050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Remap transitions 127150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho for (vector<Transition>::iterator i=transitions.begin(); 127250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho i!=transitions.end(); ++i) { 127350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho assert(i->type < (int32_t)types.size()); 127450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho ZoneType oldtype = types[i->type]; 127550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho SimplifiedZoneType newtype(oldtype); 127650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho assert(simplemap.find(newtype) != simplemap.end()); 127750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho i->type = simplemap[newtype]; 127850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 127950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 128050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Replace type list 128150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho types.clear(); 128250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho copy(simpleset.begin(), simpleset.end(), back_inserter(types)); 128350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 128450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 128550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (types.size() > 1) { 128650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Note: localtime uses the very first non-dst type as initial offsets. 128750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // If all types are DSTs, the very first type is treated as the initial offsets. 128850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 128950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Decide a type used as the initial offsets. ICU put the type at index 0. 129050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho ZoneType initialType = types[0]; 129150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho for (vector<ZoneType>::const_iterator i=types.begin(); i!=types.end(); ++i) { 129250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (i->dstoffset == 0) { 129350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho initialType = *i; 129450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho break; 129550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 129650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 129750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 129850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho SimplifiedZoneType initialSimplifiedType(initialType); 129950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 130050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // create a set of unique types, but ignoring fields which we're not interested in 130150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho set<SimplifiedZoneType> simpleset; 130250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho simpleset.insert(initialSimplifiedType); 130350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho for (vector<Transition>::const_iterator i=transitions.begin(); i!=transitions.end(); ++i) { 130450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho assert(i->type < (int32_t)types.size()); 130550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho simpleset.insert(types[i->type]); 130650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 130750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 130850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Map types to integer indices, however, keeping the first type at offset 0 130950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho map<SimplifiedZoneType,int32_t> simplemap; 131050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho simplemap[initialSimplifiedType] = 0; 131150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho int32_t n = 1; 131250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho for (set<SimplifiedZoneType>::const_iterator i=simpleset.begin(); i!=simpleset.end(); ++i) { 131350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (*i < initialSimplifiedType || initialSimplifiedType < *i) { 131450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho simplemap[*i] = n++; 131550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 131650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 131750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 131850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Remap transitions 131950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho for (vector<Transition>::iterator i=transitions.begin(); 132050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho i!=transitions.end(); ++i) { 132150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho assert(i->type < (int32_t)types.size()); 132250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho ZoneType oldtype = types[i->type]; 132350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho SimplifiedZoneType newtype(oldtype); 132450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho assert(simplemap.find(newtype) != simplemap.end()); 132550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho i->type = simplemap[newtype]; 132650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 132750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 132850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Replace type list 132950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho types.clear(); 133050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho types.push_back(initialSimplifiedType); 133150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho for (set<SimplifiedZoneType>::const_iterator i=simpleset.begin(); i!=simpleset.end(); ++i) { 133250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (*i < initialSimplifiedType || initialSimplifiedType < *i) { 133350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho types.push_back(*i); 133450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 133550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 1336b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 133750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Reiterating transitions to remove any transitions which 133850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // do not actually change the raw/dst offsets 133950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho int32_t prevTypeIdx = 0; 134050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho for (vector<Transition>::iterator i=transitions.begin(); i!=transitions.end();) { 134150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (i->type == prevTypeIdx) { 134250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // this is not a time transition, probably just name change 134350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // e.g. America/Resolute after 2006 in 2010b 134450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho transitions.erase(i); 134550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 134650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho prevTypeIdx = i->type; 134750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho i++; 134850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 134950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 135050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 1351b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1352b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1353b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 1354b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1355b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/** 1356b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Merge final zone data into this zone. 1357b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 1358b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid ZoneInfo::mergeFinalData(const FinalZone& fz) { 1359b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t year = fz.year; 1360b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int64_t seconds = yearToSeconds(year); 136150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 136250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (!ICU44PLUS) { 136350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (seconds > HIGHEST_TIME32) { 136450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Avoid transitions beyond signed 32bit max second. 136550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // This may result incorrect offset computation around 136650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // HIGHEST_TIME32. This is a limitation of ICU 136750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // before 4.4. 136850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho seconds = HIGHEST_TIME32; 136950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 137050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 137150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho 1372b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru vector<Transition>::iterator it = 1373b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru find_if(transitions.begin(), transitions.end(), 1374b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru bind2nd(ptr_fun(isAfter), seconds)); 1375b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru transitions.erase(it, transitions.end()); 1376b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1377b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (finalYear != -1) { 1378b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw invalid_argument("Final zone already merged in"); 1379b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1380b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru finalYear = fz.year; 1381b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru finalOffset = fz.offset; 1382b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru finalRuleID = fz.ruleid; 1383b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 1384b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1385b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/** 1386b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Merge the data from the given final zone into the core zone data by 1387b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * calling the ZoneInfo member function mergeFinalData. 1388b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 1389b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid mergeOne(const string& zoneid, const FinalZone& fz) { 1390b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (ZONEINFO.find(zoneid) == ZONEINFO.end()) { 1391b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru throw invalid_argument("Unrecognized final zone ID"); 1392b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1393b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ZONEINFO[zoneid].mergeFinalData(fz); 1394b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 1395b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1396b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/** 1397b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Visitor function that merges the final zone data into the main zone 1398b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * data structures. It calls mergeOne for each final zone and its 1399b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * list of aliases. 1400b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 1401b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid mergeFinalZone(const pair<string,FinalZone>& p) { 1402b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru const string& id = p.first; 1403b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru const FinalZone& fz = p.second; 1404b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1405b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru mergeOne(id, fz); 1406b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 1407b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1408b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/** 1409b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Print this rule in resource bundle format to os. ID and enclosing 1410b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * braces handled elsewhere. 1411b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */ 1412b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid FinalRule::print(ostream& os) const { 1413b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // First print the rule part that enters DST; then the rule part 1414b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // that exits it. 1415b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t whichpart = (part[0].offset != 0) ? 0 : 1; 1416b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru assert(part[whichpart].offset != 0); 1417b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru assert(part[1-whichpart].offset == 0); 1418b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1419b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << " "; 1420b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (int32_t i=0; i<2; ++i) { 1421b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru const FinalRulePart& p = part[whichpart]; 1422b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru whichpart = 1-whichpart; 1423b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << p.month << ", " << p.stz_dowim() << ", " << p.stz_dow() << ", " 1424b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << p.time << ", " << p.timemode() << ", "; 1425b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1426b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru os << part[whichpart].offset << endl; 1427b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 1428b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 142906e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller#define ICU_ZONE_OVERRIDE_SUFFIX "--ICU" 143006e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller#define ICU_ZONE_OVERRIDE_SUFFIX_LEN 5 143106e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller 1432b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruint main(int argc, char *argv[]) { 1433b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru string rootpath, zonetab, version; 143450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho bool validArgs = FALSE; 1435b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 143650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (argc == 4 || argc == 5) { 143750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho validArgs = TRUE; 1438b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru rootpath = argv[1]; 1439b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru zonetab = argv[2]; 1440b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru version = argv[3]; 144150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (argc == 5) { 144250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (strcmp(argv[4], "--old") == 0) { 144350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho ICU44PLUS = FALSE; 144450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho TZ_RESOURCE_NAME = ICU_TZ_RESOURCE_OLD; 144550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 144650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho validArgs = FALSE; 144750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 144850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 144950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 145050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (!validArgs) { 145150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho cout << "Usage: tz2icu <dir> <cmap> <tzver> [--old]" << endl 145250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho << " <dir> path to zoneinfo file tree generated by" << endl 145350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho << " ICU-patched version of zic" << endl 145450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho << " <cmap> country map, from tzdata archive," << endl 145550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho << " typically named \"zone.tab\"" << endl 145650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho << " <tzver> version string, such as \"2003e\"" << endl 145750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho << " --old generating resource format before ICU4.4" << endl; 145850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho exit(1); 1459b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1460b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1461b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru cout << "Olson data version: " << version << endl; 146250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho cout << "ICU 4.4+ format: " << (ICU44PLUS ? "Yes" : "No") << endl; 1463b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1464b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru try { 1465b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ifstream finals(ICU_ZONE_FILE); 1466b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (finals) { 1467b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru readFinalZonesAndRules(finals); 1468b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1469b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru cout << "Finished reading " << finalZones.size() 1470b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << " final zones and " << finalRules.size() 1471b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << " final rules from " ICU_ZONE_FILE << endl; 1472b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else { 1473b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru cerr << "Error: Unable to open " ICU_ZONE_FILE << endl; 1474b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return 1; 1475b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1476b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } catch (const exception& error) { 1477b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru cerr << "Error: While reading " ICU_ZONE_FILE ": " << error.what() << endl; 1478b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return 1; 1479b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1480b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1481b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru try { 1482b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Recursively scan all files below the given path, accumulating 1483b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // their data into ZONEINFO. All files must be TZif files. Any 1484b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // failure along the way will result in a call to exit(1). 1485b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru scandir(rootpath); 1486b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } catch (const exception& error) { 1487b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru cerr << "Error: While scanning " << rootpath << ": " << error.what() << endl; 1488b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return 1; 1489b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1490b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1491b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru cout << "Finished reading " << ZONEINFO.size() << " zoneinfo files [" 1492b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << (ZONEINFO.begin())->first << ".." 1493b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << (--ZONEINFO.end())->first << "]" << endl; 1494b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 149506e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller // Overrides TZ database zones with ICU custom zone definition. 149606e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller // These ICU zone overrides are defined in icuzones, with suffix --ICU. 149706e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller // If there is a matching TZ database zone, the zoneinfo is replaced 149806e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller // with the ICU definition. Then, the zone ID with --ICU suffix 149906e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller // will be deleted from the final list. 150006e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller // For example, zoneinfo for Europe/Dublin imported from the TZ database 150106e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller // will be replaced with the zone definition for Europe/Dublin--ICU 150206e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller // in icuzones. 150306e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller 150406e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller // Collect zone IDs to be modified with ICU definition. 150506e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller vector<string> customZones; 150606e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller for (ZoneMapIter i = ZONEINFO.begin(); i != ZONEINFO.end(); ++i) { 150706e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller const string& id = i->first; 150806e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller size_t idx = id.rfind(ICU_ZONE_OVERRIDE_SUFFIX); 150906e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller if (idx != string::npos && idx == id.length() - ICU_ZONE_OVERRIDE_SUFFIX_LEN) { 151006e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller cout << "ICU zone override: " << id << endl; 151106e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller customZones.push_back(id.substr(0, idx)); 151206e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller } 151306e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller } 151406e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller 151506e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller // 151606e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller // BEGIN ICU Custom ZoneInfo Override Handling 151706e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller // 151806e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller 151906e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller // Replace zoneinfo with ICU definition, then remove ICU zone ID with 152006e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller // the special suffix. 152106e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller for (vector<string>::iterator i = customZones.begin(); i != customZones.end(); i++) { 152206e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller string& origId = *i; 152306e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller string custId = origId + ICU_ZONE_OVERRIDE_SUFFIX; 152406e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller 152506e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller map<string,ZoneInfo>::iterator origZi = ZONEINFO.find(origId); 152606e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller map<string,ZoneInfo>::iterator custZi = ZONEINFO.find(custId); 152706e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller if (origZi != ZONEINFO.end() && custZi != ZONEINFO.end()) { 152806e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller // replace original zone info with custom override, 152906e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller // then delete one custom ID 153006e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller cout << "Replacing ZoneInfo " << origId << " with " << custId << endl; 153106e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller origZi->second = custZi->second; 153206e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller ZONEINFO.erase(custZi); 153306e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller } 153406e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller 153506e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller // Also replace final rule 153606e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller map<string,FinalZone>::iterator origFz = finalZones.find(origId); 153706e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller map<string,FinalZone>::iterator custFz = finalZones.find(custId); 153806e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller if (origFz != finalZones.end() && custFz != finalZones.end()) { 153906e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller // replace original final zone with custom override, 154006e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller // then delete one for custom ID 154106e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller cout << "Replacing FinalZone for " << origId << " with " << custId << endl; 154206e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller origFz->second = custFz->second; 154306e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller finalZones.erase(custFz); 154406e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller } 154506e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller } 154606e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller 154706e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller // Also remove aliases for ICU custom zoneinfo overrides. 154806e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller for (map<string,set<string>>::const_iterator i = links.begin(); i != links.end(); ) { 154906e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller const string& id = i->first; 155006e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller size_t idx = id.rfind(ICU_ZONE_OVERRIDE_SUFFIX); 155106e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller if (idx != string::npos && idx == id.length() - ICU_ZONE_OVERRIDE_SUFFIX_LEN) { 155206e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller const set<string>& aliases = i->second; 155306e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller // Also remove all revserse links 155406e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller for (set<string>::const_iterator j = aliases.begin(); j != aliases.end(); j++) { 155506e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller const string& alias = *j; 155606e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller cout << "Removing alias " << alias << endl; 155706e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller reverseLinks.erase(alias); 155806e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller } 155906e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller 156006e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller links.erase(i++); 156106e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller } else { 156206e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller i++; 156306e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller } 156406e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller } 156506e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller 156606e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller 156706e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller // 156806e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller // END ICU Custom ZoneInfo Override Handling 156906e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller // 157006e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller 1571b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru try { 1572b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for_each(finalZones.begin(), finalZones.end(), mergeFinalZone); 1573b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } catch (const exception& error) { 1574b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru cerr << "Error: While merging final zone data: " << error.what() << endl; 1575b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return 1; 1576b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1577b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1578b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Process links (including ICU aliases). For each link set we have 1579b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // a canonical ID (e.g., America/Los_Angeles) and a set of one or more 1580b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // aliases (e.g., PST, PST8PDT, ...). 1581b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1582b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // 1. Add all aliases as zone objects in ZONEINFO 1583b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (map<string,set<string> >::const_iterator i = links.begin(); 1584b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru i!=links.end(); ++i) { 1585b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru const string& olson = i->first; 1586b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru const set<string>& aliases = i->second; 1587b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (ZONEINFO.find(olson) == ZONEINFO.end()) { 158806e70b6a19bd19489a5b2249c41c3b6cdf2a5ec8Neil Fuller cerr << "Error: Invalid 'Link' to non-existent \"" 1589b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << olson << "\"" << endl; 1590b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return 1; 1591b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1592b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (set<string>::const_iterator j=aliases.begin(); 1593b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru j!=aliases.end(); ++j) { 1594b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ZONEINFO[*j] = ZoneInfo(); 1595b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1596b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1597b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1598b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // 2. Create a mapping from zones to index numbers 0..n-1. 1599b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru map<string,int32_t> zoneIDs; 1600b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru vector<string> zoneIDlist; 1601b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t z=0; 1602b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (ZoneMap::iterator i=ZONEINFO.begin(); i!=ZONEINFO.end(); ++i) { 1603b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru zoneIDs[i->first] = z++; 1604b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru zoneIDlist.push_back(i->first); 1605b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1606b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru assert(z == (int32_t) ZONEINFO.size()); 1607b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1608b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // 3. Merge aliases. Sometimes aliases link to other aliases; we 1609b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // resolve these into simplest possible sets. 1610b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru map<string,set<string> > links2; 1611b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru map<string,string> reverse2; 1612b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (map<string,set<string> >::const_iterator i = links.begin(); 1613b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru i!=links.end(); ++i) { 1614b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru string olson = i->first; 1615b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru while (reverseLinks.find(olson) != reverseLinks.end()) { 1616b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru olson = reverseLinks[olson]; 1617b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1618b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (set<string>::const_iterator j=i->second.begin(); j!=i->second.end(); ++j) { 1619b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru links2[olson].insert(*j); 1620b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru reverse2[*j] = olson; 1621b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1622b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1623b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru links = links2; 1624b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru reverseLinks = reverse2; 1625b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1626b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (false) { // Debugging: Emit link map 1627b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (map<string,set<string> >::const_iterator i = links.begin(); 1628b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru i!=links.end(); ++i) { 1629b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru cout << i->first << ": "; 1630b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (set<string>::const_iterator j=i->second.begin(); j!=i->second.end(); ++j) { 1631b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru cout << *j << ", "; 1632b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1633b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru cout << endl; 1634b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1635b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1636b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1637b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // 4. Update aliases 1638b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (map<string,set<string> >::const_iterator i = links.begin(); 1639b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru i!=links.end(); ++i) { 1640b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru const string& olson = i->first; 1641b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru const set<string>& aliases = i->second; 1642b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ZONEINFO[olson].clearAliases(); 1643b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ZONEINFO[olson].addAlias(zoneIDs[olson]); 1644b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (set<string>::const_iterator j=aliases.begin(); 1645b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru j!=aliases.end(); ++j) { 1646b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru assert(zoneIDs.find(olson) != zoneIDs.end()); 1647b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru assert(zoneIDs.find(*j) != zoneIDs.end()); 1648b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru assert(ZONEINFO.find(*j) != ZONEINFO.end()); 1649b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ZONEINFO[*j].setAliasTo(zoneIDs[olson]); 1650b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ZONEINFO[olson].addAlias(zoneIDs[*j]); 1651b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1652b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1653b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1654b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Once merging of final data is complete, we can optimize the type list 1655b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (ZoneMap::iterator i=ZONEINFO.begin(); i!=ZONEINFO.end(); ++i) { 1656b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru i->second.optimizeTypeList(); 1657b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1658b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1659b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Create the country map 1660fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius map<string, string> icuRegions; // ICU's custom zone -> country override 1661b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru map<string, set<string> > countryMap; // country -> set of zones 1662b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru map<string, string> reverseCountryMap; // zone -> country 1663fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius 1664fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius try { 1665fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius // Read icuregions file to collect ICU's own zone-region mapping data. 1666fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius ifstream frg(ICU_REGIONS); 1667fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius if (frg) { 1668fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius string line; 1669fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius while (getline(frg, line)) { 1670fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius if (line[0] == '#') continue; 1671fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius 1672fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius string zone, country; 1673fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius istringstream is(line); 1674fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius is >> zone >> country; 1675fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius if (zone.size() == 0) continue; 1676fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius if (country.size() < 2) { 1677fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius cerr << "Error: Can't parse " << line << " in " << ICU_REGIONS << endl; 1678fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius return 1; 1679fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 1680fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius icuRegions[zone] = country; 1681fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 1682fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } else { 1683fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius cout << "No custom region map [icuregions]" << endl; 1684fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 1685fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } catch (const exception& error) { 1686fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius cerr << "Error: While reading " << ICU_REGIONS << ": " << error.what() << endl; 1687fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius return 1; 1688fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 1689fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius 1690b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru try { 1691b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ifstream f(zonetab.c_str()); 1692b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (!f) { 1693b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru cerr << "Error: Unable to open " << zonetab << endl; 1694b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return 1; 1695b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1696b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t n = 0; 1697b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru string line; 1698b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru while (getline(f, line)) { 1699b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru string::size_type lb = line.find('#'); 1700b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (lb != string::npos) { 1701b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru line.resize(lb); // trim comments 1702b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1703b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru string country, coord, zone; 1704b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru istringstream is(line); 1705b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru is >> country >> coord >> zone; 1706b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (country.size() == 0) continue; 1707b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (country.size() != 2 || zone.size() < 1) { 1708b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru cerr << "Error: Can't parse " << line << " in " << zonetab << endl; 1709b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return 1; 1710b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1711b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (ZONEINFO.find(zone) == ZONEINFO.end()) { 1712b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru cerr << "Error: Country maps to invalid zone " << zone 1713b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << " in " << zonetab << endl; 1714b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return 1; 1715b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1716fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius if (icuRegions.find(zone) != icuRegions.end()) { 1717fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius // Custom override 1718fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius string customCountry = icuRegions[zone]; 1719fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius cout << "Region Mapping: custom override for " << zone 1720fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius << " " << country << " -> " << customCountry << endl; 1721fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius country = customCountry; 1722fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 1723b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru countryMap[country].insert(zone); 1724b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru reverseCountryMap[zone] = country; 1725b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru //cerr << (n+1) << ": " << country << " <=> " << zone << endl; 1726b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ++n; 1727b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1728b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru cout << "Finished reading " << n 1729b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << " country entries from " << zonetab << endl; 1730b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } catch (const exception& error) { 1731b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru cerr << "Error: While reading " << zonetab << ": " << error.what() << endl; 1732b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return 1; 1733b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1734b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1735fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius // Merge ICU's own zone-region mapping data 1736fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius for (map<string,string>::const_iterator i = icuRegions.begin(); 1737fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius i != icuRegions.end(); ++i) { 1738fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius const string& zid(i->first); 1739fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius if (reverseCountryMap.find(zid) != reverseCountryMap.end()) { 1740fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius continue; 1741fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 1742fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius cout << "Region Mapping: custom data zone=" << zid 1743fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius << ", region=" << i->second << endl; 1744fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius 1745fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius reverseCountryMap[zid] = i->second; 1746fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius countryMap[i->second].insert(zid); 1747fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius } 1748fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius 1749b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Merge ICU aliases into country map. Don't merge any alias 1750b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // that already has a country map, since that doesn't make sense. 1751b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // E.g. "Link Europe/Oslo Arctic/Longyearbyen" doesn't mean we 1752b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // should cross-map the countries between these two zones. 1753b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (map<string,set<string> >::const_iterator i = links.begin(); 1754b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru i!=links.end(); ++i) { 1755b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru const string& olson(i->first); 1756b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (reverseCountryMap.find(olson) == reverseCountryMap.end()) { 1757b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru continue; 1758b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1759b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru string c = reverseCountryMap[olson]; 1760b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru const set<string>& aliases(i->second); 1761b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (set<string>::const_iterator j=aliases.begin(); 1762b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru j != aliases.end(); ++j) { 1763b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (reverseCountryMap.find(*j) == reverseCountryMap.end()) { 1764b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru countryMap[c].insert(*j); 1765b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru reverseCountryMap[*j] = c; 1766b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru //cerr << "Aliased country: " << c << " <=> " << *j << endl; 1767b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1768b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1769b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1770b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1771b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Create a pseudo-country containing all zones belonging to no country 1772b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru set<string> nocountry; 1773b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for (ZoneMap::iterator i=ZONEINFO.begin(); i!=ZONEINFO.end(); ++i) { 1774b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (reverseCountryMap.find(i->first) == reverseCountryMap.end()) { 1775b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru nocountry.insert(i->first); 1776b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1777b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1778b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru countryMap[""] = nocountry; 1779b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1780b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Get local time & year for below 1781b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru time_t sec; 1782b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru time(&sec); 1783b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru struct tm* now = localtime(&sec); 1784b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t thisYear = now->tm_year + 1900; 1785b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 178650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho string filename = TZ_RESOURCE_NAME + ".txt"; 1787b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Write out a resource-bundle source file containing data for 1788b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // all zones. 178950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho ofstream file(filename.c_str()); 1790b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (file) { 1791b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru file << "//---------------------------------------------------------" << endl 179264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert << "// Copyright (C) 2016 and later: Unicode, Inc. and others." << endl 179364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert << "// License & terms of use: http://www.unicode.org/copyright.html#License" << endl 1794b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << "//---------------------------------------------------------" << endl 17951b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert << "// Build tool: tz2icu" << endl 17961b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert << "// Build date: " << asctime(now) /* << endl -- asctime emits CR */ 17971b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert << "// tz database: ftp://ftp.iana.org/tz/" << endl 17981b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert << "// tz version: " << version << endl 1799b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << "// ICU version: " << U_ICU_VERSION << endl 1800b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << "//---------------------------------------------------------" << endl 1801b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << "// >> !!! >> THIS IS A MACHINE-GENERATED FILE << !!! <<" << endl 1802b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << "// >> !!! >>> DO NOT EDIT <<< !!! <<" << endl 1803b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << "//---------------------------------------------------------" << endl 1804b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << endl 180550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho << TZ_RESOURCE_NAME << ":table(nofallback) {" << endl 1806b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << " TZVersion { \"" << version << "\" }" << endl 1807b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << " Zones:array { " << endl 1808b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << ZONEINFO // Zones (the actual data) 1809b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru << " }" << endl; 1810b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1811b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Names correspond to the Zones list, used for binary searching. 1812b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru printStringList ( file, ZONEINFO ); // print the Names list 1813b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1814b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Final Rules are used if requested by the zone 1815b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru file << " Rules { " << endl; 1816b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru // Emit final rules 1817b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru int32_t frc = 0; 1818b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru for(map<string,FinalRule>::iterator i=finalRules.begin(); 1819b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru i!=finalRules.end(); ++i) { 1820b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru const string& id = i->first; 1821b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru const FinalRule& r = i->second; 1822b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru file << " " << id << ":intvector {" << endl; 1823b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru r.print(file); 1824b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru file << " } //_#" << frc++ << endl; 1825b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1826b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru file << " }" << endl; 1827b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 182850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho // Emit country (region) map. 182950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (ICU44PLUS) { 183050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho file << " Regions:array {" << endl; 183150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho int32_t zn = 0; 183250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho for (ZoneMap::iterator i=ZONEINFO.begin(); i!=ZONEINFO.end(); ++i) { 183350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho map<string, string>::iterator cit = reverseCountryMap.find(i->first); 183450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (cit == reverseCountryMap.end()) { 183550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho file << " \"001\","; 183650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 183750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho file << " \"" << cit->second << "\", "; 183850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 183950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho file << "//Z#" << zn++ << " " << i->first << endl; 1840b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 184150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho file << " }" << endl; 184250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } else { 184350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho file << " Regions { " << endl; 184450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho int32_t rc = 0; 184550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho for (map<string, set<string> >::const_iterator i=countryMap.begin(); 184650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho i != countryMap.end(); ++i) { 184750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho string country = i->first; 184850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho const set<string>& zones(i->second); 184950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho file << " "; 185050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if(country[0]==0) { 185150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho file << "Default"; 185250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 185350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho file << country << ":intvector { "; 185450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho bool first = true; 185550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho for (set<string>::const_iterator j=zones.begin(); 185650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho j != zones.end(); ++j) { 185750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (!first) file << ", "; 185850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho first = false; 185950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho if (zoneIDs.find(*j) == zoneIDs.end()) { 186050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho cerr << "Error: Nonexistent zone in country map: " << *j << endl; 186150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho return 1; 186250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho } 186350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho file << zoneIDs[*j]; // emit the zone's index number 1864b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 186550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho file << " } //R#" << rc++ << endl; 1866b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 186750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho file << " }" << endl; 1868b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1869b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1870b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru file << "}" << endl; 1871b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1872b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1873b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru file.close(); 1874b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru 1875b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru if (file) { // recheck error bit 187650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho cout << "Finished writing " << TZ_RESOURCE_NAME << ".txt" << endl; 1877b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } else { 187850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho cerr << "Error: Unable to open/write to " << TZ_RESOURCE_NAME << ".txt" << endl; 1879b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru return 1; 1880b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru } 1881b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} 1882b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//eof 1883