191c98d778c80e53a7f458264233375f982dcae14Neil Fuller/*
291c98d778c80e53a7f458264233375f982dcae14Neil Fuller * Copyright (C) 2015 The Android Open Source Project
391c98d778c80e53a7f458264233375f982dcae14Neil Fuller *
491c98d778c80e53a7f458264233375f982dcae14Neil Fuller * Licensed under the Apache License, Version 2.0 (the "License");
591c98d778c80e53a7f458264233375f982dcae14Neil Fuller * you may not use this file except in compliance with the License.
691c98d778c80e53a7f458264233375f982dcae14Neil Fuller * You may obtain a copy of the License at
791c98d778c80e53a7f458264233375f982dcae14Neil Fuller *
891c98d778c80e53a7f458264233375f982dcae14Neil Fuller *      http://www.apache.org/licenses/LICENSE-2.0
991c98d778c80e53a7f458264233375f982dcae14Neil Fuller *
1091c98d778c80e53a7f458264233375f982dcae14Neil Fuller * Unless required by applicable law or agreed to in writing, software
1191c98d778c80e53a7f458264233375f982dcae14Neil Fuller * distributed under the License is distributed on an "AS IS" BASIS,
1291c98d778c80e53a7f458264233375f982dcae14Neil Fuller * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1391c98d778c80e53a7f458264233375f982dcae14Neil Fuller * See the License for the specific language governing permissions and
1491c98d778c80e53a7f458264233375f982dcae14Neil Fuller * limitations under the License.
1591c98d778c80e53a7f458264233375f982dcae14Neil Fuller */
1691c98d778c80e53a7f458264233375f982dcae14Neil Fullerpackage libcore.tzdata.update.tools;
1791c98d778c80e53a7f458264233375f982dcae14Neil Fuller
1891c98d778c80e53a7f458264233375f982dcae14Neil Fullerimport java.io.ByteArrayOutputStream;
1991c98d778c80e53a7f458264233375f982dcae14Neil Fullerimport java.io.File;
2091c98d778c80e53a7f458264233375f982dcae14Neil Fullerimport java.io.FileInputStream;
2191c98d778c80e53a7f458264233375f982dcae14Neil Fullerimport java.io.IOException;
2291c98d778c80e53a7f458264233375f982dcae14Neil Fullerimport java.nio.charset.StandardCharsets;
2391c98d778c80e53a7f458264233375f982dcae14Neil Fullerimport java.util.zip.ZipEntry;
2491c98d778c80e53a7f458264233375f982dcae14Neil Fullerimport java.util.zip.ZipOutputStream;
2591c98d778c80e53a7f458264233375f982dcae14Neil Fullerimport libcore.tzdata.update.ConfigBundle;
2691c98d778c80e53a7f458264233375f982dcae14Neil Fuller
2791c98d778c80e53a7f458264233375f982dcae14Neil Fuller/**
2891c98d778c80e53a7f458264233375f982dcae14Neil Fuller * A class for creating a {@link ConfigBundle} containing timezone update data.
2991c98d778c80e53a7f458264233375f982dcae14Neil Fuller */
3091c98d778c80e53a7f458264233375f982dcae14Neil Fullerpublic final class TzDataBundleBuilder {
3191c98d778c80e53a7f458264233375f982dcae14Neil Fuller
3291c98d778c80e53a7f458264233375f982dcae14Neil Fuller    private String tzDataVersion;
3391c98d778c80e53a7f458264233375f982dcae14Neil Fuller    private StringBuilder checksumsFileContent = new StringBuilder();
3491c98d778c80e53a7f458264233375f982dcae14Neil Fuller    private File zoneInfoFile;
3591c98d778c80e53a7f458264233375f982dcae14Neil Fuller    private File icuTzDataFile;
3691c98d778c80e53a7f458264233375f982dcae14Neil Fuller
3791c98d778c80e53a7f458264233375f982dcae14Neil Fuller    public TzDataBundleBuilder setTzDataVersion(String tzDataVersion) {
3891c98d778c80e53a7f458264233375f982dcae14Neil Fuller        this.tzDataVersion = tzDataVersion;
3991c98d778c80e53a7f458264233375f982dcae14Neil Fuller        return this;
4091c98d778c80e53a7f458264233375f982dcae14Neil Fuller    }
4191c98d778c80e53a7f458264233375f982dcae14Neil Fuller
4291c98d778c80e53a7f458264233375f982dcae14Neil Fuller    public TzDataBundleBuilder addChecksum(String fileName, long checksum) {
4391c98d778c80e53a7f458264233375f982dcae14Neil Fuller        checksumsFileContent.append(Long.toString(checksum))
4491c98d778c80e53a7f458264233375f982dcae14Neil Fuller                .append(',')
4591c98d778c80e53a7f458264233375f982dcae14Neil Fuller                .append(fileName)
4691c98d778c80e53a7f458264233375f982dcae14Neil Fuller                .append('\n');
4791c98d778c80e53a7f458264233375f982dcae14Neil Fuller        return this;
4891c98d778c80e53a7f458264233375f982dcae14Neil Fuller    }
4991c98d778c80e53a7f458264233375f982dcae14Neil Fuller
5091c98d778c80e53a7f458264233375f982dcae14Neil Fuller    public TzDataBundleBuilder addBionicTzData(File zoneInfoFile) {
5191c98d778c80e53a7f458264233375f982dcae14Neil Fuller        this.zoneInfoFile = zoneInfoFile;
5291c98d778c80e53a7f458264233375f982dcae14Neil Fuller        return this;
5391c98d778c80e53a7f458264233375f982dcae14Neil Fuller    }
5491c98d778c80e53a7f458264233375f982dcae14Neil Fuller
5591c98d778c80e53a7f458264233375f982dcae14Neil Fuller    public TzDataBundleBuilder addIcuTzData(File icuTzDataFile) {
5691c98d778c80e53a7f458264233375f982dcae14Neil Fuller        this.icuTzDataFile = icuTzDataFile;
5791c98d778c80e53a7f458264233375f982dcae14Neil Fuller        return this;
5891c98d778c80e53a7f458264233375f982dcae14Neil Fuller    }
5991c98d778c80e53a7f458264233375f982dcae14Neil Fuller
6091c98d778c80e53a7f458264233375f982dcae14Neil Fuller    /**
6191c98d778c80e53a7f458264233375f982dcae14Neil Fuller     * Builds a {@link libcore.tzdata.update.ConfigBundle}.
6291c98d778c80e53a7f458264233375f982dcae14Neil Fuller     */
6391c98d778c80e53a7f458264233375f982dcae14Neil Fuller    public ConfigBundle build() throws IOException {
6491c98d778c80e53a7f458264233375f982dcae14Neil Fuller        if (tzDataVersion == null) {
6591c98d778c80e53a7f458264233375f982dcae14Neil Fuller            throw new IllegalStateException("Missing tzDataVersion");
6691c98d778c80e53a7f458264233375f982dcae14Neil Fuller        }
6791c98d778c80e53a7f458264233375f982dcae14Neil Fuller        if (zoneInfoFile == null) {
6891c98d778c80e53a7f458264233375f982dcae14Neil Fuller            throw new IllegalStateException("Missing zoneInfo file");
6991c98d778c80e53a7f458264233375f982dcae14Neil Fuller        }
7091c98d778c80e53a7f458264233375f982dcae14Neil Fuller
7191c98d778c80e53a7f458264233375f982dcae14Neil Fuller        return buildUnvalidated();
7291c98d778c80e53a7f458264233375f982dcae14Neil Fuller    }
7391c98d778c80e53a7f458264233375f982dcae14Neil Fuller
7491c98d778c80e53a7f458264233375f982dcae14Neil Fuller    // For use in tests.
7591c98d778c80e53a7f458264233375f982dcae14Neil Fuller    public TzDataBundleBuilder clearChecksumEntries() {
7691c98d778c80e53a7f458264233375f982dcae14Neil Fuller        checksumsFileContent.setLength(0);
7791c98d778c80e53a7f458264233375f982dcae14Neil Fuller        return this;
7891c98d778c80e53a7f458264233375f982dcae14Neil Fuller    }
7991c98d778c80e53a7f458264233375f982dcae14Neil Fuller
8091c98d778c80e53a7f458264233375f982dcae14Neil Fuller    // For use in tests.
8191c98d778c80e53a7f458264233375f982dcae14Neil Fuller    public TzDataBundleBuilder clearBionicTzData() {
8291c98d778c80e53a7f458264233375f982dcae14Neil Fuller        this.zoneInfoFile = null;
8391c98d778c80e53a7f458264233375f982dcae14Neil Fuller        return this;
8491c98d778c80e53a7f458264233375f982dcae14Neil Fuller    }
8591c98d778c80e53a7f458264233375f982dcae14Neil Fuller
8691c98d778c80e53a7f458264233375f982dcae14Neil Fuller    /**
8791c98d778c80e53a7f458264233375f982dcae14Neil Fuller     * For use in tests. Use {@link #build()}.
8891c98d778c80e53a7f458264233375f982dcae14Neil Fuller     */
8991c98d778c80e53a7f458264233375f982dcae14Neil Fuller    public ConfigBundle buildUnvalidated() throws IOException {
9091c98d778c80e53a7f458264233375f982dcae14Neil Fuller        ByteArrayOutputStream baos = new ByteArrayOutputStream();
9191c98d778c80e53a7f458264233375f982dcae14Neil Fuller        try (ZipOutputStream zos = new ZipOutputStream(baos)) {
9291c98d778c80e53a7f458264233375f982dcae14Neil Fuller            addZipEntry(zos, ConfigBundle.CHECKSUMS_FILE_NAME,
9391c98d778c80e53a7f458264233375f982dcae14Neil Fuller                    checksumsFileContent.toString().getBytes(StandardCharsets.UTF_8));
9491c98d778c80e53a7f458264233375f982dcae14Neil Fuller            if (tzDataVersion != null) {
9591c98d778c80e53a7f458264233375f982dcae14Neil Fuller                addZipEntry(zos, ConfigBundle.TZ_DATA_VERSION_FILE_NAME,
9691c98d778c80e53a7f458264233375f982dcae14Neil Fuller                        tzDataVersion.getBytes(StandardCharsets.UTF_8));
9791c98d778c80e53a7f458264233375f982dcae14Neil Fuller            }
9891c98d778c80e53a7f458264233375f982dcae14Neil Fuller            if (zoneInfoFile != null) {
9991c98d778c80e53a7f458264233375f982dcae14Neil Fuller                addZipEntry(zos, ConfigBundle.ZONEINFO_FILE_NAME,
10091c98d778c80e53a7f458264233375f982dcae14Neil Fuller                        readFileAsByteArray(zoneInfoFile));
10191c98d778c80e53a7f458264233375f982dcae14Neil Fuller            }
10291c98d778c80e53a7f458264233375f982dcae14Neil Fuller            if (icuTzDataFile != null) {
10391c98d778c80e53a7f458264233375f982dcae14Neil Fuller                addZipEntry(zos, ConfigBundle.ICU_DATA_FILE_NAME,
10491c98d778c80e53a7f458264233375f982dcae14Neil Fuller                        readFileAsByteArray(icuTzDataFile));
10591c98d778c80e53a7f458264233375f982dcae14Neil Fuller            }
10691c98d778c80e53a7f458264233375f982dcae14Neil Fuller        }
10791c98d778c80e53a7f458264233375f982dcae14Neil Fuller        return new ConfigBundle(baos.toByteArray());
10891c98d778c80e53a7f458264233375f982dcae14Neil Fuller    }
10991c98d778c80e53a7f458264233375f982dcae14Neil Fuller
11091c98d778c80e53a7f458264233375f982dcae14Neil Fuller    private static void addZipEntry(ZipOutputStream zos, String name, byte[] content)
11191c98d778c80e53a7f458264233375f982dcae14Neil Fuller            throws IOException {
11291c98d778c80e53a7f458264233375f982dcae14Neil Fuller        ZipEntry zipEntry = new ZipEntry(name);
11391c98d778c80e53a7f458264233375f982dcae14Neil Fuller        zipEntry.setSize(content.length);
11491c98d778c80e53a7f458264233375f982dcae14Neil Fuller        zos.putNextEntry(zipEntry);
11591c98d778c80e53a7f458264233375f982dcae14Neil Fuller        zos.write(content);
11691c98d778c80e53a7f458264233375f982dcae14Neil Fuller        zos.closeEntry();
11791c98d778c80e53a7f458264233375f982dcae14Neil Fuller    }
11891c98d778c80e53a7f458264233375f982dcae14Neil Fuller
11991c98d778c80e53a7f458264233375f982dcae14Neil Fuller    /**
12091c98d778c80e53a7f458264233375f982dcae14Neil Fuller     * Returns the contents of 'path' as a byte array.
12191c98d778c80e53a7f458264233375f982dcae14Neil Fuller     */
12291c98d778c80e53a7f458264233375f982dcae14Neil Fuller    public static byte[] readFileAsByteArray(File file) throws IOException {
12391c98d778c80e53a7f458264233375f982dcae14Neil Fuller        byte[] buffer = new byte[8192];
12491c98d778c80e53a7f458264233375f982dcae14Neil Fuller        ByteArrayOutputStream baos = new ByteArrayOutputStream();
12591c98d778c80e53a7f458264233375f982dcae14Neil Fuller        try (FileInputStream  fis = new FileInputStream(file)) {
12691c98d778c80e53a7f458264233375f982dcae14Neil Fuller            int count;
12791c98d778c80e53a7f458264233375f982dcae14Neil Fuller            while ((count = fis.read(buffer)) != -1) {
12891c98d778c80e53a7f458264233375f982dcae14Neil Fuller                baos.write(buffer, 0, count);
12991c98d778c80e53a7f458264233375f982dcae14Neil Fuller            }
13091c98d778c80e53a7f458264233375f982dcae14Neil Fuller        }
13191c98d778c80e53a7f458264233375f982dcae14Neil Fuller        return baos.toByteArray();
13291c98d778c80e53a7f458264233375f982dcae14Neil Fuller    }
13391c98d778c80e53a7f458264233375f982dcae14Neil Fuller}
13491c98d778c80e53a7f458264233375f982dcae14Neil Fuller
135