50 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
51 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
52 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
53 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
54 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
55 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 */
57 package build.tools.tzdb;
58
59 import static build.tools.tzdb.Utils.*;
60
61 import java.io.ByteArrayOutputStream;
62 import java.io.DataOutputStream;
63 import java.nio.charset.StandardCharsets;
64 import java.nio.file.Files;
65 import java.nio.file.Path;
66 import java.nio.file.Paths;
67 import java.text.ParsePosition;
68 import java.util.ArrayList;
69 import java.util.Arrays;
70 import java.util.HashMap;
71 import java.util.HashSet;
72 import java.util.List;
73 import java.util.Map;
74 import java.util.NoSuchElementException;
75 import java.util.Scanner;
76 import java.util.SortedMap;
77 import java.util.TreeMap;
78 import java.util.regex.Matcher;
79 import java.util.regex.MatchResult;
80 import java.util.regex.Pattern;
81
82 /**
83 * A compiler that reads a set of TZDB time-zone files and builds a single
84 * combined TZDB data file.
85 *
86 * @since 1.8
87 */
88 public final class TzdbZoneRulesCompiler {
89
90 public static void main(String[] args) {
91 new TzdbZoneRulesCompiler().compile(args);
216 * Outputs the file.
217 */
218 private void outputFile(Path dstFile, String version,
219 SortedMap<String, ZoneRules> builtZones,
220 Map<String, String> links) {
221 try (DataOutputStream out = new DataOutputStream(Files.newOutputStream(dstFile))) {
222 // file version
223 out.writeByte(1);
224 // group
225 out.writeUTF("TZDB");
226 // versions
227 out.writeShort(1);
228 out.writeUTF(version);
229 // regions
230 String[] regionArray = builtZones.keySet().toArray(new String[builtZones.size()]);
231 out.writeShort(regionArray.length);
232 for (String regionId : regionArray) {
233 out.writeUTF(regionId);
234 }
235 // rules -- hashset -> remove the dup
236 List<ZoneRules> rulesList = new ArrayList<>(new HashSet<>(builtZones.values()));
237 out.writeShort(rulesList.size());
238 ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
239 for (ZoneRules rules : rulesList) {
240 baos.reset();
241 DataOutputStream dataos = new DataOutputStream(baos);
242 rules.writeExternal(dataos);
243 dataos.close();
244 byte[] bytes = baos.toByteArray();
245 out.writeShort(bytes.length);
246 out.write(bytes);
247 }
248 // link version-region-rules
249 out.writeShort(builtZones.size());
250 for (Map.Entry<String, ZoneRules> entry : builtZones.entrySet()) {
251 int regionIndex = Arrays.binarySearch(regionArray, entry.getKey());
252 int rulesIndex = rulesList.indexOf(entry.getValue());
253 out.writeShort(regionIndex);
254 out.writeShort(rulesIndex);
255 }
256 // alias-region
258 for (Map.Entry<String, String> entry : links.entrySet()) {
259 int aliasIndex = Arrays.binarySearch(regionArray, entry.getKey());
260 int regionIndex = Arrays.binarySearch(regionArray, entry.getValue());
261 out.writeShort(aliasIndex);
262 out.writeShort(regionIndex);
263 }
264 out.flush();
265 } catch (Exception ex) {
266 System.out.println("Failed: " + ex.toString());
267 ex.printStackTrace();
268 System.exit(1);
269 }
270 }
271
272 private static final Pattern YEAR = Pattern.compile("(?i)(?<min>min)|(?<max>max)|(?<only>only)|(?<year>[0-9]+)");
273 private static final Pattern MONTH = Pattern.compile("(?i)(jan)|(feb)|(mar)|(apr)|(may)|(jun)|(jul)|(aug)|(sep)|(oct)|(nov)|(dec)");
274 private static final Matcher DOW = Pattern.compile("(?i)(mon)|(tue)|(wed)|(thu)|(fri)|(sat)|(sun)").matcher("");
275 private static final Matcher TIME = Pattern.compile("(?<neg>-)?+(?<hour>[0-9]{1,2})(:(?<minute>[0-5][0-9]))?+(:(?<second>[0-5][0-9]))?+").matcher("");
276
277 /** The TZDB rules. */
278 private final Map<String, List<TZDBRule>> rules = new HashMap<>();
279
280 /** The TZDB zones. */
281 private final Map<String, List<TZDBZone>> zones = new HashMap<>();
282
283 /** The TZDB links. */
284 private final Map<String, String> links = new HashMap<>();
285
286 /** The built zones. */
287 private final SortedMap<String, ZoneRules> builtZones = new TreeMap<>();
288
289 /** Whether to output verbose messages. */
290 private boolean verbose;
291
292 /**
293 * private contructor
294 */
295 private TzdbZoneRulesCompiler() {
296 }
297
298 /**
299 * Parses a source file.
300 *
301 * @param file the file being read, not null
302 * @throws Exception if an error occurs
303 */
304 private void parseFile(Path file) throws Exception {
|
50 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
51 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
52 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
53 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
54 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
55 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 */
57 package build.tools.tzdb;
58
59 import static build.tools.tzdb.Utils.*;
60
61 import java.io.ByteArrayOutputStream;
62 import java.io.DataOutputStream;
63 import java.nio.charset.StandardCharsets;
64 import java.nio.file.Files;
65 import java.nio.file.Path;
66 import java.nio.file.Paths;
67 import java.text.ParsePosition;
68 import java.util.ArrayList;
69 import java.util.Arrays;
70 import java.util.LinkedHashMap;
71 import java.util.LinkedHashSet;
72 import java.util.List;
73 import java.util.Map;
74 import java.util.NoSuchElementException;
75 import java.util.Scanner;
76 import java.util.SortedMap;
77 import java.util.TreeMap;
78 import java.util.regex.Matcher;
79 import java.util.regex.MatchResult;
80 import java.util.regex.Pattern;
81
82 /**
83 * A compiler that reads a set of TZDB time-zone files and builds a single
84 * combined TZDB data file.
85 *
86 * @since 1.8
87 */
88 public final class TzdbZoneRulesCompiler {
89
90 public static void main(String[] args) {
91 new TzdbZoneRulesCompiler().compile(args);
216 * Outputs the file.
217 */
218 private void outputFile(Path dstFile, String version,
219 SortedMap<String, ZoneRules> builtZones,
220 Map<String, String> links) {
221 try (DataOutputStream out = new DataOutputStream(Files.newOutputStream(dstFile))) {
222 // file version
223 out.writeByte(1);
224 // group
225 out.writeUTF("TZDB");
226 // versions
227 out.writeShort(1);
228 out.writeUTF(version);
229 // regions
230 String[] regionArray = builtZones.keySet().toArray(new String[builtZones.size()]);
231 out.writeShort(regionArray.length);
232 for (String regionId : regionArray) {
233 out.writeUTF(regionId);
234 }
235 // rules -- hashset -> remove the dup
236 List<ZoneRules> rulesList = new ArrayList<>(new LinkedHashSet<>(builtZones.values()));
237 out.writeShort(rulesList.size());
238 ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
239 for (ZoneRules rules : rulesList) {
240 baos.reset();
241 DataOutputStream dataos = new DataOutputStream(baos);
242 rules.writeExternal(dataos);
243 dataos.close();
244 byte[] bytes = baos.toByteArray();
245 out.writeShort(bytes.length);
246 out.write(bytes);
247 }
248 // link version-region-rules
249 out.writeShort(builtZones.size());
250 for (Map.Entry<String, ZoneRules> entry : builtZones.entrySet()) {
251 int regionIndex = Arrays.binarySearch(regionArray, entry.getKey());
252 int rulesIndex = rulesList.indexOf(entry.getValue());
253 out.writeShort(regionIndex);
254 out.writeShort(rulesIndex);
255 }
256 // alias-region
258 for (Map.Entry<String, String> entry : links.entrySet()) {
259 int aliasIndex = Arrays.binarySearch(regionArray, entry.getKey());
260 int regionIndex = Arrays.binarySearch(regionArray, entry.getValue());
261 out.writeShort(aliasIndex);
262 out.writeShort(regionIndex);
263 }
264 out.flush();
265 } catch (Exception ex) {
266 System.out.println("Failed: " + ex.toString());
267 ex.printStackTrace();
268 System.exit(1);
269 }
270 }
271
272 private static final Pattern YEAR = Pattern.compile("(?i)(?<min>min)|(?<max>max)|(?<only>only)|(?<year>[0-9]+)");
273 private static final Pattern MONTH = Pattern.compile("(?i)(jan)|(feb)|(mar)|(apr)|(may)|(jun)|(jul)|(aug)|(sep)|(oct)|(nov)|(dec)");
274 private static final Matcher DOW = Pattern.compile("(?i)(mon)|(tue)|(wed)|(thu)|(fri)|(sat)|(sun)").matcher("");
275 private static final Matcher TIME = Pattern.compile("(?<neg>-)?+(?<hour>[0-9]{1,2})(:(?<minute>[0-5][0-9]))?+(:(?<second>[0-5][0-9]))?+").matcher("");
276
277 /** The TZDB rules. */
278 private final Map<String, List<TZDBRule>> rules = new LinkedHashMap<>();
279
280 /** The TZDB zones. */
281 private final Map<String, List<TZDBZone>> zones = new LinkedHashMap<>();
282
283 /** The TZDB links. */
284 private final Map<String, String> links = new LinkedHashMap<>();
285
286 /** The built zones. */
287 private final SortedMap<String, ZoneRules> builtZones = new TreeMap<>();
288
289 /** Whether to output verbose messages. */
290 private boolean verbose;
291
292 /**
293 * private contructor
294 */
295 private TzdbZoneRulesCompiler() {
296 }
297
298 /**
299 * Parses a source file.
300 *
301 * @param file the file being read, not null
302 * @throws Exception if an error occurs
303 */
304 private void parseFile(Path file) throws Exception {
|