diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/ZipFile.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/ZipFile.java
index 434035793..ae24c178e 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/ZipFile.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/ZipFile.java
@@ -17,100 +17,100 @@ import androidx.annotation.Nullable;
* Utility class for recognition and reading of ZIP archives.
*/
public class ZipFile {
- private static final Logger LOG = LoggerFactory.getLogger(ZipFile.class);
- public static final byte[] ZIP_HEADER = new byte[]{
- 0x50, 0x4B, 0x03, 0x04
- };
+ private static final Logger LOG = LoggerFactory.getLogger(ZipFile.class);
+ public static final byte[] ZIP_HEADER = new byte[]{
+ 0x50, 0x4B, 0x03, 0x04
+ };
- private final byte[] zipBytes;
+ private final byte[] zipBytes;
- /**
- * Open ZIP file from byte array already in memory.
- * @param zipBytes data to handle as a ZIP file.
- */
- public ZipFile(byte[] zipBytes) {
- this.zipBytes = zipBytes;
- }
+ /**
+ * Open ZIP file from byte array already in memory.
+ * @param zipBytes data to handle as a ZIP file.
+ */
+ public ZipFile(byte[] zipBytes) {
+ this.zipBytes = zipBytes;
+ }
- /**
- * Open ZIP file from InputStream.
- * This will read the entire file into memory at once.
- * @param inputStream data to handle as a ZIP file.
- */
- public ZipFile(InputStream inputStream) throws IOException {
- this.zipBytes = readAllBytes(inputStream);
- }
+ /**
+ * Open ZIP file from InputStream.
+ * This will read the entire file into memory at once.
+ * @param inputStream data to handle as a ZIP file.
+ */
+ public ZipFile(InputStream inputStream) throws IOException {
+ this.zipBytes = readAllBytes(inputStream);
+ }
- /**
- * Checks if data resembles a ZIP file.
- * The check is not infallible: it may report self-extracting or other exotic ZIP archives as not a ZIP file, and it may report a corrupted ZIP file as a ZIP file.
- * @param data The data to check.
- * @return Whether data resembles a ZIP file.
- */
- public static boolean isZipFile(byte[] data) {
- return ArrayUtils.equals(data, ZIP_HEADER, 0);
- }
+ /**
+ * Checks if data resembles a ZIP file.
+ * The check is not infallible: it may report self-extracting or other exotic ZIP archives as not a ZIP file, and it may report a corrupted ZIP file as a ZIP file.
+ * @param data The data to check.
+ * @return Whether data resembles a ZIP file.
+ */
+ public static boolean isZipFile(byte[] data) {
+ return ArrayUtils.equals(data, ZIP_HEADER, 0);
+ }
- /**
- * Reads the contents of file at path into a byte array.
- * @param path Path of the file in the ZIP file.
- * @return byte array contatining the contents of the requested file.
- * @throws ZipFileException If the specified path does not exist or references a directory, or if some other I/O error occurs. In other words, if return value would otherwise be null.
- */
- public byte[] getFileFromZip(final String path) throws ZipFileException {
- try (InputStream is = new ByteArrayInputStream(zipBytes); ZipInputStream zipInputStream = new ZipInputStream(is)) {
- ZipEntry zipEntry;
- while ((zipEntry = zipInputStream.getNextEntry()) != null) {
- if (!zipEntry.getName().equals(path)) continue; // TODO: is this always a path? The documentation is very vague.
+ /**
+ * Reads the contents of file at path into a byte array.
+ * @param path Path of the file in the ZIP file.
+ * @return byte array contatining the contents of the requested file.
+ * @throws ZipFileException If the specified path does not exist or references a directory, or if some other I/O error occurs. In other words, if return value would otherwise be null.
+ */
+ public byte[] getFileFromZip(final String path) throws ZipFileException {
+ try (InputStream is = new ByteArrayInputStream(zipBytes); ZipInputStream zipInputStream = new ZipInputStream(is)) {
+ ZipEntry zipEntry;
+ while ((zipEntry = zipInputStream.getNextEntry()) != null) {
+ if (!zipEntry.getName().equals(path)) continue; // TODO: is this always a path? The documentation is very vague.
- if (zipEntry.isDirectory()) {
- throw new ZipFileException(String.format("Path in ZIP file is a directory: %s", path));
+ if (zipEntry.isDirectory()) {
+ throw new ZipFileException(String.format("Path in ZIP file is a directory: %s", path));
+ }
+
+ return readAllBytes(zipInputStream);
}
- return readAllBytes(zipInputStream);
- }
+ throw new ZipFileException(String.format("Path in ZIP file was not found: %s", path));
- throw new ZipFileException(String.format("Path in ZIP file was not found: %s", path));
+ } catch (ZipException e) {
+ throw new ZipFileException("The ZIP file might be corrupted");
+ } catch (IOException e) {
+ throw new ZipFileException("General IO error");
+ }
+ }
- } catch (ZipException e) {
- throw new ZipFileException("The ZIP file might be corrupted");
- } catch (IOException e) {
- throw new ZipFileException("General IO error");
- }
- }
+ /**
+ * Tries to obtain file from ZIP file without much hassle, but is not safe.
+ * Please only use this in place of old code where correctness of the result is checked only later on.
+ * Use getFileFromZip of ZipFile instance instead.
+ * @param zipBytes
+ * @param path Path of the file in the ZIP file.
+ * @return Contents of requested file or null.
+ */
+ @Deprecated
+ @Nullable
+ public static byte[] tryReadFileQuick(final byte[] zipBytes, final String path) {
+ try {
+ return new ZipFile(zipBytes).getFileFromZip(path);
+ } catch (ZipFileException e) {
+ LOG.error("Quick ZIP reading failed.", e);
+ } catch (Exception e) {
+ LOG.error("Unable to close ZipFile.", e);
+ }
- /**
- * Tries to obtain file from ZIP file without much hassle, but is not safe.
- * Please only use this in place of old code where correctness of the result is checked only later on.
- * Use getFileFromZip of ZipFile instance instead.
- * @param zipBytes
- * @param path Path of the file in the ZIP file.
- * @return Contents of requested file or null.
- */
- @Deprecated
- @Nullable
- public static byte[] tryReadFileQuick(final byte[] zipBytes, final String path) {
- try {
- return new ZipFile(zipBytes).getFileFromZip(path);
- } catch (ZipFileException e) {
- LOG.error("Quick ZIP reading failed.", e);
- } catch (Exception e) {
- LOG.error("Unable to close ZipFile.", e);
- }
+ return null;
+ }
- return null;
- }
+ private static byte[] readAllBytes(final InputStream is) throws IOException {
+ final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- private static byte[] readAllBytes(final InputStream is) throws IOException {
- final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ int n;
+ byte[] buf = new byte[16384];
- int n;
- byte[] buf = new byte[16384];
+ while ((n = is.read(buf, 0, buf.length)) != -1) {
+ buffer.write(buf, 0, n);
+ }
- while ((n = is.read(buf, 0, buf.length)) != -1) {
- buffer.write(buf, 0, n);
- }
-
- return buffer.toByteArray();
- }
+ return buffer.toByteArray();
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/ZipFileException.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/ZipFileException.java
index f7c87ceab..1b5d05832 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/ZipFileException.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/ZipFileException.java
@@ -1,7 +1,7 @@
package nodomain.freeyourgadget.gadgetbridge.util;
public class ZipFileException extends Exception {
- public ZipFileException(String message) {
- super(String.format("Error while reading ZIP file: %s", message));
- }
+ public ZipFileException(String message) {
+ super(String.format("Error while reading ZIP file: %s", message));
+ }
}
diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/ZipFileTest.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/ZipFileTest.java
index f342cc413..a78993098 100644
--- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/ZipFileTest.java
+++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/ZipFileTest.java
@@ -16,152 +16,152 @@ import nodomain.freeyourgadget.gadgetbridge.util.ZipFile;
import nodomain.freeyourgadget.gadgetbridge.util.ZipFileException;
public class ZipFileTest extends TestBase {
- private static final String TEST_FILE_NAME = "manifest.json";
- private static final String TEST_NESTED_FILE_NAME = "directory/manifest.json";
- private static final String TEST_FILE_CONTENTS_1 = "{ \"mykey\": \"myvalue\", \"myarr\": [0, 1, 2, 3] }";
- private static final String TEST_FILE_CONTENTS_2 = "{\n" +
- " \"manifest\": {\n" +
- " \"application\": {\n" +
- " \"bin_file\": \"pinetime-mcuboot-app-image-1.10.0.bin\",\n" +
- " \"dat_file\": \"pinetime-mcuboot-app-image-1.10.0.dat\",\n" +
- " \"init_packet_data\": {\n" +
- " \"application_version\": 4294967295,\n" +
- " \"device_revision\": 65535,\n" +
- " \"device_type\": 82,\n" +
- " \"firmware_crc16\": 21770,\n" +
- " \"softdevice_req\": [\n" +
- " 65534\n" +
- " ]\n" +
- " }\n" +
- " },\n" +
- " \"dfu_version\": 0.5\n" +
- " }\n" +
- "}";
+ private static final String TEST_FILE_NAME = "manifest.json";
+ private static final String TEST_NESTED_FILE_NAME = "directory/manifest.json";
+ private static final String TEST_FILE_CONTENTS_1 = "{ \"mykey\": \"myvalue\", \"myarr\": [0, 1, 2, 3] }";
+ private static final String TEST_FILE_CONTENTS_2 = "{\n" +
+ " \"manifest\": {\n" +
+ " \"application\": {\n" +
+ " \"bin_file\": \"pinetime-mcuboot-app-image-1.10.0.bin\",\n" +
+ " \"dat_file\": \"pinetime-mcuboot-app-image-1.10.0.dat\",\n" +
+ " \"init_packet_data\": {\n" +
+ " \"application_version\": 4294967295,\n" +
+ " \"device_revision\": 65535,\n" +
+ " \"device_type\": 82,\n" +
+ " \"firmware_crc16\": 21770,\n" +
+ " \"softdevice_req\": [\n" +
+ " 65534\n" +
+ " ]\n" +
+ " }\n" +
+ " },\n" +
+ " \"dfu_version\": 0.5\n" +
+ " }\n" +
+ "}";
- @Test
- public void testZipSize1() throws IOException, ZipFileException {
- final String contents = TEST_FILE_CONTENTS_1;
+ @Test
+ public void testZipSize1() throws IOException, ZipFileException {
+ final String contents = TEST_FILE_CONTENTS_1;
- byte[] zipArchive = createZipArchive(TEST_FILE_NAME, contents);
+ byte[] zipArchive = createZipArchive(TEST_FILE_NAME, contents);
- ZipFile zipFile = new ZipFile(zipArchive);
- String readContents = new String(zipFile.getFileFromZip(TEST_FILE_NAME));
+ ZipFile zipFile = new ZipFile(zipArchive);
+ String readContents = new String(zipFile.getFileFromZip(TEST_FILE_NAME));
- Assert.assertEquals(contents, readContents);
- }
-
- @Test
- public void testZipSize2() throws IOException, ZipFileException {
- final String contents = TEST_FILE_CONTENTS_2;
-
- byte[] zipArchive = createZipArchive(TEST_FILE_NAME, contents);
-
- ZipFile zipFile = new ZipFile(zipArchive);
- String readContents = new String(zipFile.getFileFromZip(TEST_FILE_NAME));
-
- Assert.assertEquals(contents, readContents);
- }
-
- @Test
- public void testZipSize3() throws IOException, ZipFileException, JSONException {
- String contents = makeLargeJsonObject(new JSONObject(TEST_FILE_CONTENTS_2), 4).toString(4);
-
- byte[] zipArchive = createZipArchive(TEST_FILE_NAME, contents);
-
- ZipFile zipFile = new ZipFile(zipArchive);
- String readContents = new String(zipFile.getFileFromZip(TEST_FILE_NAME));
-
- Assert.assertEquals(contents, readContents);
- }
-
- @Test
- public void testZipSize4() throws IOException, ZipFileException, JSONException {
- String contents = makeLargeJsonObject(new JSONObject(TEST_FILE_CONTENTS_2), 32).toString(4);
-
- byte[] zipArchive = createZipArchive(TEST_FILE_NAME, contents);
-
- ZipFile zipFile = new ZipFile(zipArchive);
- String readContents = new String(zipFile.getFileFromZip(TEST_FILE_NAME));
-
- Assert.assertEquals(contents, readContents);
- }
-
- @Test
- public void testZipFileInDir() throws IOException, ZipFileException {
- String contents = TEST_FILE_CONTENTS_1;
-
- byte[] zipArchive = createZipArchive(TEST_NESTED_FILE_NAME, contents);
-
- ZipFile zipFile = new ZipFile(zipArchive);
- String readContents = new String(zipFile.getFileFromZip(TEST_NESTED_FILE_NAME));
-
- Assert.assertEquals(contents, readContents);
- }
-
- @Test
- public void testZipFilesUnorderedAccess() throws IOException, ZipFileException {
- String contents1 = TEST_FILE_CONTENTS_1;
- String contents2 = TEST_FILE_CONTENTS_2;
- String contents3 = "zbuMyWvIxeKgcWnsSYOd8CTLgjc9x7ti21OlLlGduMJVXlKc835WEUKJ3xR6GDA5d0tHSXnYxZkDlznFQVyueHhwYywsMO9PlkJqjOCA2Mn8uTuTliIKUNPBraFipOodb6rW31HdKLOd7gmniLF5mvdRPHOUKIXSMciqogOsZnvGXylMx6TegesGBWAeHFhTSQ5xXOrOEUsDHK78M3A0yFXzLE0XgwI90Tl87OHyWfE0y0yINv5PjxgGCLUB7mHYFpgPW1C5yyIkb2JA6CePE3hHv369khwmLumW7P9ErZhzdGgeskz6Os0p5HMrTFuySc0PWxsIfru1HldIH9TZTSMCbd91G5jCCikyx2zrzDKaasuQZyBGZcMjr1zcCLpPQiKT7ELSoUBCKhiFODxbFA06MC5bLXh2WvyP8W2kVxT2T4AnDX6pwf1BKs4nbHpAjvMmHrzlhQp7Q6VWBEiniY5M9QW4ExRcMGIBYXvY7vu5p";
-
- final ByteArrayOutputStream baos = new ByteArrayOutputStream();
- final ZipOutputStream zipWriteStream = new ZipOutputStream(baos);
-
- writeFileToZip(contents1, "file1", zipWriteStream);
- writeFileToZip(contents2, "file2", zipWriteStream);
- writeFileToZip(contents3, "file3", zipWriteStream);
- zipWriteStream.close();
-
- ZipFile zipFile = new ZipFile(baos.toByteArray());
- String readContents2 = new String(zipFile.getFileFromZip("file2"));
- String readContents1 = new String(zipFile.getFileFromZip("file1"));
- String readContents3 = new String(zipFile.getFileFromZip("file3"));
-
- Assert.assertEquals(contents1, readContents1);
- Assert.assertEquals(contents2, readContents2);
- Assert.assertEquals(contents3, readContents3);
- }
-
- /**
- * Create a ZIP archive with a single text file.
- * The archive will not be saved to a file, it is kept in memory.
- *
- * @return the ZIP archive
- */
- private byte[] createZipArchive(String path, String fileContents) throws IOException {
- final ByteArrayOutputStream baos = new ByteArrayOutputStream();
- final ZipOutputStream zipFile = new ZipOutputStream(baos);
-
- writeFileToZip(fileContents, path, zipFile);
- zipFile.close();
-
- return baos.toByteArray();
- }
-
- /**
- * Make a larger JSON object for testing purposes, based on a preexisting JSON object.
- */
- private JSONObject makeLargeJsonObject(JSONObject base, int repetitions) throws JSONException {
- JSONObject manifestObj = base.getJSONObject("manifest");
- JSONArray array = new JSONArray();
-
- for (int i = 0; i < repetitions; i++) {
- array.put(manifestObj);
+ Assert.assertEquals(contents, readContents);
}
- return base.put("array", array);
- }
+ @Test
+ public void testZipSize2() throws IOException, ZipFileException {
+ final String contents = TEST_FILE_CONTENTS_2;
- /**
- * Write given data to file at given path into an already opened ZIP archive.
- * Allows to create an archive with multiple files.
- */
- private void writeFileToZip(String fileContents, String path, ZipOutputStream zipFile) throws IOException {
- byte[] data = fileContents.getBytes(StandardCharsets.UTF_8);
+ byte[] zipArchive = createZipArchive(TEST_FILE_NAME, contents);
- ZipEntry zipEntry = new ZipEntry(path);
- zipFile.putNextEntry(zipEntry);
- zipFile.write(data, 0, fileContents.length());
- zipFile.closeEntry();
- }
+ ZipFile zipFile = new ZipFile(zipArchive);
+ String readContents = new String(zipFile.getFileFromZip(TEST_FILE_NAME));
+
+ Assert.assertEquals(contents, readContents);
+ }
+
+ @Test
+ public void testZipSize3() throws IOException, ZipFileException, JSONException {
+ String contents = makeLargeJsonObject(new JSONObject(TEST_FILE_CONTENTS_2), 4).toString(4);
+
+ byte[] zipArchive = createZipArchive(TEST_FILE_NAME, contents);
+
+ ZipFile zipFile = new ZipFile(zipArchive);
+ String readContents = new String(zipFile.getFileFromZip(TEST_FILE_NAME));
+
+ Assert.assertEquals(contents, readContents);
+ }
+
+ @Test
+ public void testZipSize4() throws IOException, ZipFileException, JSONException {
+ String contents = makeLargeJsonObject(new JSONObject(TEST_FILE_CONTENTS_2), 32).toString(4);
+
+ byte[] zipArchive = createZipArchive(TEST_FILE_NAME, contents);
+
+ ZipFile zipFile = new ZipFile(zipArchive);
+ String readContents = new String(zipFile.getFileFromZip(TEST_FILE_NAME));
+
+ Assert.assertEquals(contents, readContents);
+ }
+
+ @Test
+ public void testZipFileInDir() throws IOException, ZipFileException {
+ String contents = TEST_FILE_CONTENTS_1;
+
+ byte[] zipArchive = createZipArchive(TEST_NESTED_FILE_NAME, contents);
+
+ ZipFile zipFile = new ZipFile(zipArchive);
+ String readContents = new String(zipFile.getFileFromZip(TEST_NESTED_FILE_NAME));
+
+ Assert.assertEquals(contents, readContents);
+ }
+
+ @Test
+ public void testZipFilesUnorderedAccess() throws IOException, ZipFileException {
+ String contents1 = TEST_FILE_CONTENTS_1;
+ String contents2 = TEST_FILE_CONTENTS_2;
+ String contents3 = "zbuMyWvIxeKgcWnsSYOd8CTLgjc9x7ti21OlLlGduMJVXlKc835WEUKJ3xR6GDA5d0tHSXnYxZkDlznFQVyueHhwYywsMO9PlkJqjOCA2Mn8uTuTliIKUNPBraFipOodb6rW31HdKLOd7gmniLF5mvdRPHOUKIXSMciqogOsZnvGXylMx6TegesGBWAeHFhTSQ5xXOrOEUsDHK78M3A0yFXzLE0XgwI90Tl87OHyWfE0y0yINv5PjxgGCLUB7mHYFpgPW1C5yyIkb2JA6CePE3hHv369khwmLumW7P9ErZhzdGgeskz6Os0p5HMrTFuySc0PWxsIfru1HldIH9TZTSMCbd91G5jCCikyx2zrzDKaasuQZyBGZcMjr1zcCLpPQiKT7ELSoUBCKhiFODxbFA06MC5bLXh2WvyP8W2kVxT2T4AnDX6pwf1BKs4nbHpAjvMmHrzlhQp7Q6VWBEiniY5M9QW4ExRcMGIBYXvY7vu5p";
+
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ final ZipOutputStream zipWriteStream = new ZipOutputStream(baos);
+
+ writeFileToZip(contents1, "file1", zipWriteStream);
+ writeFileToZip(contents2, "file2", zipWriteStream);
+ writeFileToZip(contents3, "file3", zipWriteStream);
+ zipWriteStream.close();
+
+ ZipFile zipFile = new ZipFile(baos.toByteArray());
+ String readContents2 = new String(zipFile.getFileFromZip("file2"));
+ String readContents1 = new String(zipFile.getFileFromZip("file1"));
+ String readContents3 = new String(zipFile.getFileFromZip("file3"));
+
+ Assert.assertEquals(contents1, readContents1);
+ Assert.assertEquals(contents2, readContents2);
+ Assert.assertEquals(contents3, readContents3);
+ }
+
+ /**
+ * Create a ZIP archive with a single text file.
+ * The archive will not be saved to a file, it is kept in memory.
+ *
+ * @return the ZIP archive
+ */
+ private byte[] createZipArchive(String path, String fileContents) throws IOException {
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ final ZipOutputStream zipFile = new ZipOutputStream(baos);
+
+ writeFileToZip(fileContents, path, zipFile);
+ zipFile.close();
+
+ return baos.toByteArray();
+ }
+
+ /**
+ * Make a larger JSON object for testing purposes, based on a preexisting JSON object.
+ */
+ private JSONObject makeLargeJsonObject(JSONObject base, int repetitions) throws JSONException {
+ JSONObject manifestObj = base.getJSONObject("manifest");
+ JSONArray array = new JSONArray();
+
+ for (int i = 0; i < repetitions; i++) {
+ array.put(manifestObj);
+ }
+
+ return base.put("array", array);
+ }
+
+ /**
+ * Write given data to file at given path into an already opened ZIP archive.
+ * Allows to create an archive with multiple files.
+ */
+ private void writeFileToZip(String fileContents, String path, ZipOutputStream zipFile) throws IOException {
+ byte[] data = fileContents.getBytes(StandardCharsets.UTF_8);
+
+ ZipEntry zipEntry = new ZipEntry(path);
+ zipFile.putNextEntry(zipEntry);
+ zipFile.write(data, 0, fileContents.length());
+ zipFile.closeEntry();
+ }
}