Tweak the tzdata format for future changes am: 4da0af149c am: 6672af7f23
Original change: https://android-review.googlesource.com/c/platform/system/timezone/+/1314835
Change-Id: I9bcc1cc5c139d60e2ec996d3d186ef45a98d6ad4
diff --git a/debug_tools/host/main/java/ZoneSplitter.java b/debug_tools/host/main/java/ZoneSplitter.java
index a8b72e6..cc00254 100644
--- a/debug_tools/host/main/java/ZoneSplitter.java
+++ b/debug_tools/host/main/java/ZoneSplitter.java
@@ -63,6 +63,7 @@
// int index_offset
// int data_offset
// int zonetab_offset
+ // int final_offset
writeVersionFile(mappedFile, outputDir);
final int fileSize = (int) tzData.length();
@@ -72,18 +73,30 @@
validateOffset(data_offset, fileSize);
int zonetab_offset = mappedFile.getInt();
validateOffset(zonetab_offset, fileSize);
+ int final_offset = mappedFile.getInt();
- if (index_offset >= data_offset || data_offset >= zonetab_offset) {
+ if (index_offset >= data_offset
+ || data_offset >= zonetab_offset
+ || zonetab_offset >= final_offset
+ || final_offset > fileSize) {
throw new IOException("Invalid offset: index_offset=" + index_offset
+ ", data_offset=" + data_offset + ", zonetab_offset=" + zonetab_offset
- + ", fileSize=" + fileSize);
+ + ", final_offset=" + final_offset + ", fileSize=" + fileSize);
}
File zicFilesDir = new File(outputDir, "zones");
zicFilesDir.mkdir();
extractZicFiles(mappedFile, index_offset, data_offset, zicFilesDir);
- writeZoneTabFile(mappedFile, zonetab_offset, fileSize - zonetab_offset, outputDir);
+ writeZoneTabFile(mappedFile, zonetab_offset, final_offset - zonetab_offset,
+ outputDir);
+
+ if (final_offset != fileSize) {
+ // This isn't an error, but it's worth noting: it suggests the file may be in a newer
+ // format than the current branch.
+ System.out.println(
+ "final_offset (" + final_offset + ") != fileSize (" + fileSize + ")");
+ }
}
static MappedByteBuffer createMappedByteBuffer(File tzData) throws IOException {
@@ -174,7 +187,8 @@
if (ids[i].compareTo(ids[i - 1]) <= 0) {
throw new IOException(
"Index not sorted or contains multiple entries with the same ID"
- + ", index=" + i + ", ids[i]=" + ids[i] + ", ids[i - 1]=" + ids[i - 1]);
+ + ", index=" + i + ", ids[i]=" + ids[i]
+ + ", ids[i - 1]=" + ids[i - 1]);
}
}
}
diff --git a/input_tools/android/zone_compactor/main/java/ZoneCompactor.java b/input_tools/android/zone_compactor/main/java/ZoneCompactor.java
index c3c1089..81873aa 100644
--- a/input_tools/android/zone_compactor/main/java/ZoneCompactor.java
+++ b/input_tools/android/zone_compactor/main/java/ZoneCompactor.java
@@ -43,13 +43,13 @@
private static final int MAXNAME = 40;
// Zone name synonyms.
- private Map<String,String> links = new HashMap<String,String>();
+ private Map<String,String> links = new HashMap<>();
// File offsets by zone name.
- private Map<String,Integer> offsets = new HashMap<String,Integer>();
+ private Map<String,Integer> offsets = new HashMap<>();
// File lengths by zone name.
- private Map<String,Integer> lengths = new HashMap<String,Integer>();
+ private Map<String,Integer> lengths = new HashMap<>();
// Concatenate the contents of 'inFile' onto 'out'.
private static void copyFile(File inFile, OutputStream out) throws Exception {
@@ -80,19 +80,20 @@
int offset = 0;
while ((s = reader.readLine()) != null) {
s = s.trim();
- if (s.startsWith("Link")) {
- StringTokenizer st = new StringTokenizer(s);
- st.nextToken();
+ StringTokenizer st = new StringTokenizer(s);
+ String lineType = st.nextToken();
+ if (lineType.startsWith("Link")) {
String to = st.nextToken();
String from = st.nextToken();
links.put(from, to);
- } else {
- String link = links.get(s);
+ } else if (lineType.startsWith("Zone")) {
+ String zoneId = st.nextToken();
+ String link = links.get(zoneId);
if (link == null) {
- File sourceFile = new File(dataDirectory, s);
+ File sourceFile = new File(dataDirectory, zoneId);
long length = sourceFile.length();
- offsets.put(s, offset);
- lengths.put(s, (int) length);
+ offsets.put(zoneId, offset);
+ lengths.put(zoneId, (int) length);
offset += length;
copyFile(sourceFile, allData);
@@ -102,9 +103,7 @@
reader.close();
// Fill in fields for links.
- Iterator<String> it = links.keySet().iterator();
- while (it.hasNext()) {
- String from = it.next();
+ for (String from : links.keySet()) {
String to = links.get(from);
offsets.put(from, offsets.get(to));
@@ -121,11 +120,12 @@
// int index_offset -- so we can slip in extra header fields in a backwards-compatible way
// int data_offset
// int zonetab_offset
+ // int final_offset
// tzdata_version
f.write(toAscii(new byte[12], version));
- // Write dummy values for the three offsets, and remember where we need to seek back to later
+ // Write dummy values for the offsets, and remember where we need to seek back to later
// when we have the real values.
int index_offset_offset = (int) f.getFilePointer();
f.writeInt(0);
@@ -133,6 +133,12 @@
f.writeInt(0);
int zonetab_offset_offset = (int) f.getFilePointer();
f.writeInt(0);
+ // The final offset serves as a placeholder for sections that might be added in future and
+ // ensures we know the size of the final "real" section. Relying on the last section ending at
+ // EOF would make it harder to append sections to the end of the file in a backward compatible
+ // way.
+ int final_offset_offset = (int) f.getFilePointer();
+ f.writeInt(0);
int index_offset = (int) f.getFilePointer();
@@ -140,9 +146,7 @@
ArrayList<String> sortedOlsonIds = new ArrayList<String>();
sortedOlsonIds.addAll(offsets.keySet());
Collections.sort(sortedOlsonIds);
- it = sortedOlsonIds.iterator();
- while (it.hasNext()) {
- String zoneName = it.next();
+ for (String zoneName : sortedOlsonIds) {
if (zoneName.length() >= MAXNAME) {
throw new RuntimeException("zone filename too long: " + zoneName.length());
}
@@ -176,6 +180,8 @@
}
reader.close();
+ int final_offset = (int) f.getFilePointer();
+
// Go back and fix up the offsets in the header.
f.seek(index_offset_offset);
f.writeInt(index_offset);
@@ -183,6 +189,8 @@
f.writeInt(data_offset);
f.seek(zonetab_offset_offset);
f.writeInt(zonetab_offset);
+ f.seek(final_offset_offset);
+ f.writeInt(final_offset);
f.close();
}
@@ -199,7 +207,8 @@
public static void main(String[] args) throws Exception {
if (args.length != 5) {
- System.err.println("usage: java ZoneCompactor <setup file> <data directory> <zone.tab file> <output directory> <tzdata version>");
+ System.err.println("usage: java ZoneCompactor <setup file> <data directory> <zone.tab file>"
+ + " <output directory> <tzdata version>");
System.exit(0);
}
new ZoneCompactor(args[0], args[1], args[2], args[3], args[4]);
diff --git a/output_data/distro/distro.zip b/output_data/distro/distro.zip
index 4306024..c22c454 100644
--- a/output_data/distro/distro.zip
+++ b/output_data/distro/distro.zip
Binary files differ
diff --git a/output_data/iana/tzdata b/output_data/iana/tzdata
index 301e264..372a82a 100644
--- a/output_data/iana/tzdata
+++ b/output_data/iana/tzdata
Binary files differ
diff --git a/testing/data/test1/output_data/distro/distro.zip b/testing/data/test1/output_data/distro/distro.zip
index eeff942..4a852a6 100644
--- a/testing/data/test1/output_data/distro/distro.zip
+++ b/testing/data/test1/output_data/distro/distro.zip
Binary files differ
diff --git a/testing/data/test1/output_data/iana/tzdata b/testing/data/test1/output_data/iana/tzdata
index c5a28a4..badbbc5 100644
--- a/testing/data/test1/output_data/iana/tzdata
+++ b/testing/data/test1/output_data/iana/tzdata
Binary files differ
diff --git a/testing/data/test2/output_data/distro/distro.zip b/testing/data/test2/output_data/distro/distro.zip
index 375d438..efd5c23 100644
--- a/testing/data/test2/output_data/distro/distro.zip
+++ b/testing/data/test2/output_data/distro/distro.zip
Binary files differ
diff --git a/testing/data/test2/output_data/iana/tzdata b/testing/data/test2/output_data/iana/tzdata
index c2d09f8..4efdbf1 100644
--- a/testing/data/test2/output_data/iana/tzdata
+++ b/testing/data/test2/output_data/iana/tzdata
Binary files differ
diff --git a/testing/data/test3/output_data/distro/distro.zip b/testing/data/test3/output_data/distro/distro.zip
index b3a284f..ec45f61 100644
--- a/testing/data/test3/output_data/distro/distro.zip
+++ b/testing/data/test3/output_data/distro/distro.zip
Binary files differ
diff --git a/testing/data/test3/output_data/iana/tzdata b/testing/data/test3/output_data/iana/tzdata
index c5a28a4..badbbc5 100644
--- a/testing/data/test3/output_data/iana/tzdata
+++ b/testing/data/test3/output_data/iana/tzdata
Binary files differ
diff --git a/testing/src/main/java/libcore/timezone/testing/ZoneInfoTestHelper.java b/testing/src/main/java/libcore/timezone/testing/ZoneInfoTestHelper.java
index 224b193..20b86b0 100644
--- a/testing/src/main/java/libcore/timezone/testing/ZoneInfoTestHelper.java
+++ b/testing/src/main/java/libcore/timezone/testing/ZoneInfoTestHelper.java
@@ -226,6 +226,7 @@
private Integer indexOffsetOverride;
private Integer dataOffsetOverride;
private Integer zoneTabOffsetOverride;
+ private Integer finalOffsetOverride;
public TzDataBuilder() {}
@@ -250,6 +251,11 @@
return this;
}
+ public TzDataBuilder setFinalOffsetOverride(int finalOffset) {
+ this.finalOffsetOverride = finalOffset;
+ return this;
+ }
+
/**
* Adds data for a new zone. These must be added in ID string order to generate
* a valid file.
@@ -290,6 +296,8 @@
writeInt(baos, 0);
int zoneTabOffsetOffset = baos.size();
writeInt(baos, 0);
+ int finalOffsetOffset = baos.size();
+ writeInt(baos, 0);
// Construct the data section in advance, so we know the offsets.
ByteArrayOutputStream dataBytes = new ByteArrayOutputStream();
@@ -328,6 +336,8 @@
byte[] zoneTabBytes = zoneTab.getBytes(StandardCharsets.US_ASCII);
writeByteArray(baos, zoneTabBytes);
+ int finalOffset = baos.size();
+
byte[] bytes = baos.toByteArray();
setInt(bytes, indexOffsetOffset,
indexOffsetOverride != null ? indexOffsetOverride : indexOffset);
@@ -335,6 +345,8 @@
dataOffsetOverride != null ? dataOffsetOverride : dataOffset);
setInt(bytes, zoneTabOffsetOffset,
zoneTabOffsetOverride != null ? zoneTabOffsetOverride : zoneTabOffset);
+ setInt(bytes, finalOffsetOffset,
+ finalOffsetOverride != null ? finalOffsetOverride : finalOffset);
return bytes;
}
diff --git a/update-tzdata.py b/update-tzdata.py
index ee370c1..9a9bd2f 100755
--- a/update-tzdata.py
+++ b/update-tzdata.py
@@ -72,15 +72,30 @@
for line in open(zic_input_file):
fields = line.split()
if fields:
- if fields[0] == 'Link':
- links.append('%s %s %s' % (fields[0], fields[1], fields[2]))
- zones.append(fields[2])
- elif fields[0] == 'Zone':
- zones.append(fields[1])
- zones.sort()
+ line_type = fields[0]
+ if line_type == 'Link':
+ # Each "Link" line requires the creation of a link from an old tz ID to
+ # a new tz ID, and implies the existence of a zone with the old tz ID.
+ #
+ # IANA terminology:
+ # TARGET = the new tz ID, LINK-NAME = the old tz ID
+ target = fields[1]
+ link_name = fields[2]
+ links.append('Link %s %s' % (target, link_name))
+ zones.append('Zone %s' % link_name)
+ elif line_type == 'Zone':
+ # Each "Zone" line indicates the existence of a tz ID.
+ #
+ # IANA terminology:
+ # NAME is the tz ID, other fields like STDOFF, RULES, FORMAT,[UNTIL] are
+ # ignored.
+ name = fields[1]
+ zones.append('Zone %s' % name)
zone_compactor_setup_file = '%s/setup' % tmp_dir
setup = open(zone_compactor_setup_file, 'w')
+
+ # Ordering requirement from ZoneCompactor: Links must come first.
for link in sorted(set(links)):
setup.write('%s\n' % link)
for zone in sorted(set(zones)):