1 /*
   2  * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import java.io.BufferedReader;
  25 import java.io.FileReader;
  26 import java.io.FileNotFoundException;
  27 import java.io.IOException;
  28 import java.util.ArrayList;
  29 import java.util.HashMap;
  30 import java.util.HashSet;
  31 import java.util.List;
  32 import java.util.Map;
  33 import java.util.Set;
  34 import java.util.StringTokenizer;
  35 
  36 /**
  37  * ZoneRec hold information of time zone corresponding to each text
  38  * line of the "Zone" part.
  39  *
  40  * @since 1.4
  41  */
  42 class ZoneRec {
  43     private int gmtOffset;
  44     private String ruleName;
  45     private int directSave;
  46     private Rule ruleRef;
  47     private String format;
  48     private boolean hasUntil;
  49     private int untilYear;
  50     private Month untilMonth;
  51     private RuleDay untilDay;
  52     private Time untilTime;
  53     private long untilInMillis;
  54     private String line;
  55 
  56     /**
  57      * @return the "UNTIL" value in milliseconds
  58      */
  59     Time getUntilTime() {
  60         return untilTime;
  61     }
  62 
  63     /**
  64      * @return the GMT offset value in milliseconds
  65      */
  66     int getGmtOffset() {
  67         return gmtOffset;
  68     }
  69 
  70     /**
  71      * @return the rule name to which this zone record refers
  72      */
  73     String getRuleName() {
  74         return ruleName;
  75     }
  76 
  77     /**
  78      * @return the amount of saving time directly defined in the
  79      * "RULES/SAVE" field.
  80      */
  81     int getDirectSave() {
  82         return directSave;
  83     }
  84 
  85     /**
  86      * @return true if this zone record has a reference to a rule
  87      */
  88     boolean hasRuleReference() {
  89         return ruleRef != null;
  90     }
  91 
  92     /**
  93      * Returns the "FORMAT" field string of this zone record. This
  94      * @return the "FORMAT" field
  95      */
  96     String getFormat() {
  97         return format;
  98     }
  99 
 100     /**
 101      * @return the year in the "UNTIL" field
 102      */
 103     int getUntilYear() {
 104         return untilYear;
 105     }
 106 
 107     /**
 108      * Returns the "UNTIL" field value in milliseconds from Janurary
 109      * 1, 1970 0:00 GMT.
 110      * @param currentSave the amount of daylight saving in
 111      * milliseconds that is used to adjust wall-clock time.
 112      * @return the milliseconds value of the "UNTIL" field
 113      */
 114     long getUntilTime(int currentSave) {
 115         if (untilTime.isWall()) {
 116             return untilInMillis - currentSave;
 117         }
 118         return untilInMillis;
 119     }
 120 
 121     /**
 122      * Returns the "UNTIL" time in milliseconds without adjusting GMT
 123      * offsets or daylight saving.
 124      * @return local "UNTIL" time in milliseconds
 125      */
 126     long getLocalUntilTime() {
 127         return Time.getLocalTime(untilYear,
 128                                  untilMonth,
 129                                  untilDay,
 130                                  untilTime.getTime());
 131     }
 132 
 133     /**
 134      * Returns the "UNTIL" time in milliseconds with adjusting GMT offsets and daylight saving.
 135      * @return the "UNTIL" time after the adjustment
 136      */
 137     long getLocalUntilTime(int save, int gmtOffset) {
 138         return Time.getLocalTime(untilYear,
 139                                  untilMonth,
 140                                  untilDay,
 141                                  save,
 142                                  gmtOffset,
 143                                  untilTime);
 144     }
 145 
 146     /**
 147      * @return the text line of this zone record
 148      */
 149     String getLine() {
 150         return line;
 151     }
 152 
 153     /**
 154      * Sets the specified text line to this zone record
 155      */
 156     void setLine(String line) {
 157         this.line = line;
 158     }
 159 
 160     /**
 161      * @return true if this zone record has the "UNTIL" field
 162      */
 163     boolean hasUntil() {
 164         return this.hasUntil;
 165     }
 166 
 167     /**
 168      * Adjusts the "UNTIL" time to GMT offset if this zone record has
 169      * it.  <code>untilTime</code> is not adjusted to daylight saving
 170      * in this method.
 171      */
 172     void adjustTime() {
 173         if (!hasUntil()) {
 174             return;
 175         }
 176         if (untilTime.isSTD() || untilTime.isWall()) {
 177             // adjust to gmt offset only here.  adjust to real
 178             // wall-clock time when tracking rules
 179             untilInMillis -= gmtOffset;
 180         }
 181     }
 182 
 183     /**
 184      * @return the reference to the Rule object
 185      */
 186     Rule getRuleRef() {
 187         return ruleRef;
 188     }
 189 
 190     /**
 191      * Resolves the reference to a Rule and adjusts its "UNTIL" time
 192      * to GMT offset.
 193      */
 194     void resolve(Zoneinfo zi) {
 195         if (ruleName != null && (!"-".equals(ruleName))) {
 196                 ruleRef = zi.getRule(ruleName);
 197         }
 198         adjustTime();
 199     }
 200 
 201     /**
 202      * Parses a Zone text line that is described by a StringTokenizer.
 203      * @param tokens represents tokens of a Zone text line
 204      * @return the zone record produced by parsing the text
 205      */
 206     static ZoneRec parse(StringTokenizer tokens) {
 207         ZoneRec rec = new ZoneRec();
 208         try {
 209             rec.gmtOffset = (int) Time.parse(tokens.nextToken()).getTime();
 210             String token = tokens.nextToken();
 211             char c = token.charAt(0);
 212             if (c >= '0' && c <= '9') {
 213                 rec.directSave = (int) Time.parse(token).getTime();
 214             } else {
 215                 rec.ruleName = token;
 216             }
 217             rec.format = tokens.nextToken();
 218             if (tokens.hasMoreTokens()) {
 219                 rec.hasUntil = true;
 220                 rec.untilYear = Integer.parseInt(tokens.nextToken());
 221                 if (tokens.hasMoreTokens()) {
 222                     rec.untilMonth = Month.parse(tokens.nextToken());
 223                 } else {
 224                     rec.untilMonth = Month.JANUARY;
 225                 }
 226                 if (tokens.hasMoreTokens()) {
 227                     rec.untilDay = RuleDay.parse(tokens.nextToken());
 228                 } else {
 229                     rec.untilDay = new RuleDay(1);
 230                 }
 231                 if (tokens.hasMoreTokens()) {
 232                     rec.untilTime = Time.parse(tokens.nextToken());
 233                 } else {
 234                     rec.untilTime = Time.parse("0:00");
 235                 }
 236                 rec.untilInMillis = rec.getLocalUntilTime();
 237             }
 238         } catch (Exception e) {
 239             // TODO: error reporting
 240             e.printStackTrace();
 241         }
 242         return rec;
 243     }
 244 
 245     private static void panic(String msg) {
 246         Main.panic(msg);
 247     }
 248 }