1602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel/* 2602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel * Licensed to the Apache Software Foundation (ASF) under one or more 3602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel * contributor license agreements. See the NOTICE file distributed with 4602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel * this work for additional information regarding copyright ownership. 5602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel * The ASF licenses this file to You under the Apache License, Version 2.0 6602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel * (the "License"); you may not use this file except in compliance with 7602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel * the License. You may obtain a copy of the License at 8602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel * 9602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel * http://www.apache.org/licenses/LICENSE-2.0 10602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel * 11602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel * Unless required by applicable law or agreed to in writing, software 12602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel * distributed under the License is distributed on an "AS IS" BASIS, 13602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel * See the License for the specific language governing permissions and 15602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel * limitations under the License. 16602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel */ 17602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel/* Apache Harmony HEADER because the code in this class comes mostly from ZipFile, ZipEntry and 18602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel * ZipConstants from android libcore. 19602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel */ 20602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel 21602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Rousselpackage android.support.multidex; 22602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel 23602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Rousselimport java.io.File; 24602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Rousselimport java.io.IOException; 25602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Rousselimport java.io.RandomAccessFile; 26602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Rousselimport java.util.zip.CRC32; 27602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Rousselimport java.util.zip.ZipException; 28602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel 29602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel/** 30602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel * Tools to build a quick partial crc of zip files. 31602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel */ 32602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Rousselfinal class ZipUtil { 33602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel static class CentralDirectory { 34602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel long offset; 35602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel long size; 36602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel } 37602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel 38602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel /* redefine those constant here because of bug 13721174 preventing to compile using the 39602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel * constants defined in ZipFile */ 40602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel private static final int ENDHDR = 22; 41602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel private static final int ENDSIG = 0x6054b50; 42602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel 43602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel /** 44602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel * Size of reading buffers. 45602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel */ 46602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel private static final int BUFFER_SIZE = 0x4000; 47602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel 48602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel /** 49602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel * Compute crc32 of the central directory of an apk. The central directory contains 50602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel * the crc32 of each entries in the zip so the computed result is considered valid for the whole 51602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel * zip file. Does not support zip64 nor multidisk but it should be OK for now since ZipFile does 52602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel * not either. 53602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel */ 54602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel static long getZipCrc(File apk) throws IOException { 55602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel RandomAccessFile raf = new RandomAccessFile(apk, "r"); 56602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel try { 57602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel CentralDirectory dir = findCentralDirectory(raf); 58602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel 59602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel return computeCrcOfCentralDir(raf, dir); 60602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel } finally { 61602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel raf.close(); 62602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel } 63602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel } 64602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel 65602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel /* Package visible for testing */ 66602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel static CentralDirectory findCentralDirectory(RandomAccessFile raf) throws IOException, 67602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel ZipException { 68602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel long scanOffset = raf.length() - ENDHDR; 69602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel if (scanOffset < 0) { 70602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel throw new ZipException("File too short to be a zip file: " + raf.length()); 71602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel } 72602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel 73602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel long stopOffset = scanOffset - 0x10000 /* ".ZIP file comment"'s max length */; 74602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel if (stopOffset < 0) { 75602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel stopOffset = 0; 76602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel } 77602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel 78602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel int endSig = Integer.reverseBytes(ENDSIG); 79602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel while (true) { 80602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel raf.seek(scanOffset); 81602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel if (raf.readInt() == endSig) { 82602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel break; 83602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel } 84602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel 85602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel scanOffset--; 86602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel if (scanOffset < stopOffset) { 87602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel throw new ZipException("End Of Central Directory signature not found"); 88602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel } 89602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel } 90602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel // Read the End Of Central Directory. ENDHDR includes the signature 91602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel // bytes, 92602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel // which we've already read. 93602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel 94602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel // Pull out the information we need. 95602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel raf.skipBytes(2); // diskNumber 96602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel raf.skipBytes(2); // diskWithCentralDir 97602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel raf.skipBytes(2); // numEntries 98602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel raf.skipBytes(2); // totalNumEntries 99602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel CentralDirectory dir = new CentralDirectory(); 100602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel dir.size = Integer.reverseBytes(raf.readInt()) & 0xFFFFFFFFL; 101602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel dir.offset = Integer.reverseBytes(raf.readInt()) & 0xFFFFFFFFL; 102602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel return dir; 103602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel } 104602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel 105602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel /* Package visible for testing */ 106602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel static long computeCrcOfCentralDir(RandomAccessFile raf, CentralDirectory dir) 107602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel throws IOException { 108602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel CRC32 crc = new CRC32(); 109602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel long stillToRead = dir.size; 110602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel raf.seek(dir.offset); 111602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel int length = (int) Math.min(BUFFER_SIZE, stillToRead); 112602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel byte[] buffer = new byte[BUFFER_SIZE]; 113602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel length = raf.read(buffer, 0, length); 114602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel while (length != -1) { 115602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel crc.update(buffer, 0, length); 116602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel stillToRead -= length; 117602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel if (stillToRead == 0) { 118602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel break; 119602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel } 120602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel length = (int) Math.min(BUFFER_SIZE, stillToRead); 121602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel length = raf.read(buffer, 0, length); 122602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel } 123602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel return crc.getValue(); 124602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel } 125602c6ca8cae4718ba8ff9f65e53305d002479359Yohann Roussel} 126