summaryrefslogtreecommitdiff
path: root/library/src/androidx/multidex/ZipUtil.java
diff options
context:
space:
mode:
Diffstat (limited to 'library/src/androidx/multidex/ZipUtil.java')
-rw-r--r--library/src/androidx/multidex/ZipUtil.java125
1 files changed, 125 insertions, 0 deletions
diff --git a/library/src/androidx/multidex/ZipUtil.java b/library/src/androidx/multidex/ZipUtil.java
new file mode 100644
index 0000000..fc33623
--- /dev/null
+++ b/library/src/androidx/multidex/ZipUtil.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/* Apache Harmony HEADER because the code in this class comes mostly from ZipFile, ZipEntry and
+ * ZipConstants from android libcore.
+ */
+
+package androidx.multidex;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.zip.CRC32;
+import java.util.zip.ZipException;
+
+/**
+ * Tools to build a quick partial crc of zip files.
+ */
+final class ZipUtil {
+ static class CentralDirectory {
+ long offset;
+ long size;
+ }
+
+ /* redefine those constant here because of bug 13721174 preventing to compile using the
+ * constants defined in ZipFile */
+ private static final int ENDHDR = 22;
+ private static final int ENDSIG = 0x6054b50;
+
+ /**
+ * Size of reading buffers.
+ */
+ private static final int BUFFER_SIZE = 0x4000;
+
+ /**
+ * Compute crc32 of the central directory of an apk. The central directory contains
+ * the crc32 of each entries in the zip so the computed result is considered valid for the whole
+ * zip file. Does not support zip64 nor multidisk but it should be OK for now since ZipFile does
+ * not either.
+ */
+ static long getZipCrc(File apk) throws IOException {
+ RandomAccessFile raf = new RandomAccessFile(apk, "r");
+ try {
+ CentralDirectory dir = findCentralDirectory(raf);
+
+ return computeCrcOfCentralDir(raf, dir);
+ } finally {
+ raf.close();
+ }
+ }
+
+ /* Package visible for testing */
+ static CentralDirectory findCentralDirectory(RandomAccessFile raf) throws IOException,
+ ZipException {
+ long scanOffset = raf.length() - ENDHDR;
+ if (scanOffset < 0) {
+ throw new ZipException("File too short to be a zip file: " + raf.length());
+ }
+
+ long stopOffset = scanOffset - 0x10000 /* ".ZIP file comment"'s max length */;
+ if (stopOffset < 0) {
+ stopOffset = 0;
+ }
+
+ int endSig = Integer.reverseBytes(ENDSIG);
+ while (true) {
+ raf.seek(scanOffset);
+ if (raf.readInt() == endSig) {
+ break;
+ }
+
+ scanOffset--;
+ if (scanOffset < stopOffset) {
+ throw new ZipException("End Of Central Directory signature not found");
+ }
+ }
+ // Read the End Of Central Directory. ENDHDR includes the signature
+ // bytes,
+ // which we've already read.
+
+ // Pull out the information we need.
+ raf.skipBytes(2); // diskNumber
+ raf.skipBytes(2); // diskWithCentralDir
+ raf.skipBytes(2); // numEntries
+ raf.skipBytes(2); // totalNumEntries
+ CentralDirectory dir = new CentralDirectory();
+ dir.size = Integer.reverseBytes(raf.readInt()) & 0xFFFFFFFFL;
+ dir.offset = Integer.reverseBytes(raf.readInt()) & 0xFFFFFFFFL;
+ return dir;
+ }
+
+ /* Package visible for testing */
+ static long computeCrcOfCentralDir(RandomAccessFile raf, CentralDirectory dir)
+ throws IOException {
+ CRC32 crc = new CRC32();
+ long stillToRead = dir.size;
+ raf.seek(dir.offset);
+ int length = (int) Math.min(BUFFER_SIZE, stillToRead);
+ byte[] buffer = new byte[BUFFER_SIZE];
+ length = raf.read(buffer, 0, length);
+ while (length != -1) {
+ crc.update(buffer, 0, length);
+ stillToRead -= length;
+ if (stillToRead == 0) {
+ break;
+ }
+ length = (int) Math.min(BUFFER_SIZE, stillToRead);
+ length = raf.read(buffer, 0, length);
+ }
+ return crc.getValue();
+ }
+}