Home | History | Annotate | Download | only in dexbacked
      1 /*
      2  * Copyright 2013, Google Inc.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are
      7  * met:
      8  *
      9  *     * Redistributions of source code must retain the above copyright
     10  * notice, this list of conditions and the following disclaimer.
     11  *     * Redistributions in binary form must reproduce the above
     12  * copyright notice, this list of conditions and the following disclaimer
     13  * in the documentation and/or other materials provided with the
     14  * distribution.
     15  *     * Neither the name of Google Inc. nor the names of its
     16  * contributors may be used to endorse or promote products derived from
     17  * this software without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 package org.jf.dexlib2.dexbacked;
     33 
     34 import com.google.common.io.ByteStreams;
     35 import org.jf.dexlib2.Opcodes;
     36 import org.jf.dexlib2.dexbacked.raw.OdexHeaderItem;
     37 import org.jf.dexlib2.dexbacked.util.VariableSizeList;
     38 import org.jf.dexlib2.util.DexUtil;
     39 
     40 import javax.annotation.Nonnull;
     41 import java.io.IOException;
     42 import java.io.InputStream;
     43 import java.io.UnsupportedEncodingException;
     44 import java.util.List;
     45 
     46 public class DexBackedOdexFile extends DexBackedDexFile {
     47     private static final int DEPENDENCY_COUNT_OFFSET = 12;
     48     private static final int DEPENDENCY_START_OFFSET = 16;
     49 
     50     private final byte[] odexBuf;
     51 
     52     public DexBackedOdexFile(@Nonnull Opcodes opcodes, @Nonnull byte[] odexBuf, byte[] dexBuf) {
     53         super(opcodes, dexBuf);
     54 
     55         this.odexBuf = odexBuf;
     56     }
     57 
     58     @Override public boolean isOdexFile() {
     59         return true;
     60     }
     61 
     62     @Override public boolean hasOdexOpcodes() {
     63         return true;
     64     }
     65 
     66     @Nonnull public List<String> getDependencies() {
     67         final int dexOffset = OdexHeaderItem.getDexOffset(odexBuf);
     68         final int dependencyOffset = OdexHeaderItem.getDependenciesOffset(odexBuf) - dexOffset;
     69 
     70         BaseDexBuffer buf = new BaseDexBuffer(this.buf);
     71         int dependencyCount = buf.readInt(dependencyOffset + DEPENDENCY_COUNT_OFFSET);
     72 
     73         return new VariableSizeList<String>(this, dependencyOffset + DEPENDENCY_START_OFFSET, dependencyCount) {
     74             @Override protected String readNextItem(@Nonnull DexReader reader, int index) {
     75                 int length = reader.readInt();
     76                 int offset = reader.getOffset();
     77                 reader.moveRelative(length + 20);
     78                 try {
     79                     return new String(DexBackedOdexFile.this.buf, offset, length-1, "US-ASCII");
     80                 } catch (UnsupportedEncodingException ex) {
     81                     throw new RuntimeException(ex);
     82                 }
     83             }
     84         };
     85     }
     86 
     87     @Nonnull public static DexBackedOdexFile fromInputStream(@Nonnull Opcodes opcodes, @Nonnull InputStream is)
     88             throws IOException {
     89         DexUtil.verifyOdexHeader(is);
     90 
     91         is.reset();
     92         byte[] odexBuf = new byte[OdexHeaderItem.ITEM_SIZE];
     93         ByteStreams.readFully(is, odexBuf);
     94         int dexOffset = OdexHeaderItem.getDexOffset(odexBuf);
     95         if (dexOffset > OdexHeaderItem.ITEM_SIZE) {
     96             ByteStreams.skipFully(is, dexOffset - OdexHeaderItem.ITEM_SIZE);
     97         }
     98 
     99         byte[] dexBuf = ByteStreams.toByteArray(is);
    100 
    101         return new DexBackedOdexFile(opcodes, odexBuf, dexBuf);
    102     }
    103 
    104     public int getOdexVersion() {
    105         return OdexHeaderItem.getVersion(odexBuf, 0);
    106     }
    107 
    108     public static class NotAnOdexFile extends RuntimeException {
    109         public NotAnOdexFile() {
    110         }
    111 
    112         public NotAnOdexFile(Throwable cause) {
    113             super(cause);
    114         }
    115 
    116         public NotAnOdexFile(String message) {
    117             super(message);
    118         }
    119 
    120         public NotAnOdexFile(String message, Throwable cause) {
    121             super(message, cause);
    122         }
    123     }
    124 }
    125