diff options
Diffstat (limited to 'library/src/androidx/multidex/ZipUtil.java')
-rw-r--r-- | library/src/androidx/multidex/ZipUtil.java | 125 |
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(); + } +} |