Home | History | Annotate | Download | only in multidex
      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 android.support.multidex;
     22 
     23 import java.io.IOException;
     24 import java.nio.ByteBuffer;
     25 import java.nio.charset.Charset;
     26 import java.util.Calendar;
     27 import java.util.GregorianCalendar;
     28 import java.util.zip.ZipEntry;
     29 import java.util.zip.ZipException;
     30 
     31 class ZipEntryReader {
     32     static final Charset UTF_8 = Charset.forName("UTF-8");
     33    /**
     34      * General Purpose Bit Flags, Bit 0.
     35      * If set, indicates that the file is encrypted.
     36      */
     37     private static final int GPBF_ENCRYPTED_FLAG = 1 << 0;
     38 
     39     /**
     40      * Supported General Purpose Bit Flags Mask.
     41      * Bit mask of bits not supported.
     42      * Note: The only bit that we will enforce at this time
     43      * is the encrypted bit. Although other bits are not supported,
     44      * we must not enforce them as this could break some legitimate
     45      * use cases (See http://b/8617715).
     46      */
     47     private static final int GPBF_UNSUPPORTED_MASK = GPBF_ENCRYPTED_FLAG;
     48     private static final long CENSIG = 0x2014b50;
     49 
     50     static ZipEntry readEntry(ByteBuffer in) throws IOException {
     51 
     52         int sig = in.getInt();
     53         if (sig != CENSIG) {
     54              throw new ZipException("Central Directory Entry not found");
     55         }
     56 
     57         in.position(8);
     58         int gpbf = in.getShort() & 0xffff;
     59 
     60         if ((gpbf & GPBF_UNSUPPORTED_MASK) != 0) {
     61             throw new ZipException("Invalid General Purpose Bit Flag: " + gpbf);
     62         }
     63 
     64         int compressionMethod = in.getShort() & 0xffff;
     65         int time = in.getShort() & 0xffff;
     66         int modDate = in.getShort() & 0xffff;
     67 
     68         // These are 32-bit values in the file, but 64-bit fields in this object.
     69         long crc = ((long) in.getInt()) & 0xffffffffL;
     70         long compressedSize = ((long) in.getInt()) & 0xffffffffL;
     71         long size = ((long) in.getInt()) & 0xffffffffL;
     72 
     73         int nameLength = in.getShort() & 0xffff;
     74         int extraLength = in.getShort() & 0xffff;
     75         int commentByteCount = in.getShort() & 0xffff;
     76 
     77         // This is a 32-bit value in the file, but a 64-bit field in this object.
     78         in.position(42);
     79         long localHeaderRelOffset = ((long) in.getInt()) & 0xffffffffL;
     80 
     81         byte[] nameBytes = new byte[nameLength];
     82         in.get(nameBytes, 0, nameBytes.length);
     83         String name = new String(nameBytes, 0, nameBytes.length, UTF_8);
     84 
     85         ZipEntry entry = new ZipEntry(name);
     86         entry.setMethod(compressionMethod);
     87         entry.setTime(getTime(time, modDate));
     88 
     89         entry.setCrc(crc);
     90         entry.setCompressedSize(compressedSize);
     91         entry.setSize(size);
     92 
     93         // The RI has always assumed UTF-8. (If GPBF_UTF8_FLAG isn't set, the encoding is
     94         // actually IBM-437.)
     95         if (commentByteCount > 0) {
     96             byte[] commentBytes = new byte[commentByteCount];
     97             in.get(commentBytes, 0, commentByteCount);
     98             entry.setComment(new String(commentBytes, 0, commentBytes.length, UTF_8));
     99         }
    100 
    101         if (extraLength > 0) {
    102             byte[] extra = new byte[extraLength];
    103             in.get(extra, 0, extraLength);
    104             entry.setExtra(extra);
    105         }
    106 
    107         return entry;
    108 
    109     }
    110 
    111     private static long getTime(int time, int modDate) {
    112         GregorianCalendar cal = new GregorianCalendar();
    113         cal.set(Calendar.MILLISECOND, 0);
    114         cal.set(1980 + ((modDate >> 9) & 0x7f), ((modDate >> 5) & 0xf) - 1,
    115                 modDate & 0x1f, (time >> 11) & 0x1f, (time >> 5) & 0x3f,
    116                 (time & 0x1f) << 1);
    117         return cal.getTime().getTime();
    118     }
    119 
    120 }
    121