AI2 Component  (Version nb184)
ZipUtil.java
Go to the documentation of this file.
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 /* Apache Harmony HEADER because the code in this class comes mostly from ZipFile, ZipEntry and
18  * ZipConstants from android libcore.
19  */
20 
21 package com.google.appinventor.components.runtime.multidex;
22 
23 import java.io.File;
24 import java.io.IOException;
25 import java.io.RandomAccessFile;
26 import java.util.zip.CRC32;
27 import java.util.zip.ZipException;
28 
32 final class ZipUtil {
33  static class CentralDirectory {
34  long offset;
35  long size;
36  }
37 
38  /* redefine those constant here because of bug 13721174 preventing to compile using the
39  * constants defined in ZipFile */
40  private static final int ENDHDR = 22;
41  private static final int ENDSIG = 0x6054b50;
42 
46  private static final int BUFFER_SIZE = 0x4000;
47 
54  static long getZipCrc(File apk) throws IOException {
55  RandomAccessFile raf = new RandomAccessFile(apk, "r");
56  try {
57  CentralDirectory dir = findCentralDirectory(raf);
58 
59  return computeCrcOfCentralDir(raf, dir);
60  } finally {
61  raf.close();
62  }
63  }
64 
65  /* Package visible for testing */
66  static CentralDirectory findCentralDirectory(RandomAccessFile raf) throws IOException,
67  ZipException {
68  long scanOffset = raf.length() - ENDHDR;
69  if (scanOffset < 0) {
70  throw new ZipException("File too short to be a zip file: " + raf.length());
71  }
72 
73  long stopOffset = scanOffset - 0x10000 /* ".ZIP file comment"'s max length */;
74  if (stopOffset < 0) {
75  stopOffset = 0;
76  }
77 
78  int endSig = Integer.reverseBytes(ENDSIG);
79  while (true) {
80  raf.seek(scanOffset);
81  if (raf.readInt() == endSig) {
82  break;
83  }
84 
85  scanOffset--;
86  if (scanOffset < stopOffset) {
87  throw new ZipException("End Of Central Directory signature not found");
88  }
89  }
90  // Read the End Of Central Directory. ENDHDR includes the signature
91  // bytes,
92  // which we've already read.
93 
94  // Pull out the information we need.
95  raf.skipBytes(2); // diskNumber
96  raf.skipBytes(2); // diskWithCentralDir
97  raf.skipBytes(2); // numEntries
98  raf.skipBytes(2); // totalNumEntries
99  CentralDirectory dir = new CentralDirectory();
100  dir.size = Integer.reverseBytes(raf.readInt()) & 0xFFFFFFFFL;
101  dir.offset = Integer.reverseBytes(raf.readInt()) & 0xFFFFFFFFL;
102  return dir;
103  }
104 
105  /* Package visible for testing */
106  static long computeCrcOfCentralDir(RandomAccessFile raf, CentralDirectory dir)
107  throws IOException {
108  CRC32 crc = new CRC32();
109  long stillToRead = dir.size;
110  raf.seek(dir.offset);
111  int length = (int) Math.min(BUFFER_SIZE, stillToRead);
112  byte[] buffer = new byte[BUFFER_SIZE];
113  length = raf.read(buffer, 0, length);
114  while (length != -1) {
115  crc.update(buffer, 0, length);
116  stillToRead -= length;
117  if (stillToRead == 0) {
118  break;
119  }
120  length = (int) Math.min(BUFFER_SIZE, stillToRead);
121  length = raf.read(buffer, 0, length);
122  }
123  return crc.getValue();
124  }
125 }