/* * Copyright 2013, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.jf.dexlib2.dexbacked; import com.google.common.io.ByteStreams; import org.jf.dexlib2.Opcodes; import org.jf.dexlib2.dexbacked.raw.OdexHeaderItem; import org.jf.dexlib2.dexbacked.util.VariableSizeList; import javax.annotation.Nonnull; import java.io.EOFException; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; public class DexBackedOdexFile extends DexBackedDexFile { private static final int DEPENDENCY_COUNT_OFFSET = 12; private static final int DEPENDENCY_START_OFFSET = 16; private final byte[] odexBuf; public DexBackedOdexFile(Opcodes opcodes, MemoryDexFileItemPointer pointer, MemoryReader reader) { super(opcodes, pointer, reader); this.odexBuf = null; } public DexBackedOdexFile(@Nonnull Opcodes opcodes, @Nonnull byte[] odexBuf, byte[] dexBuf) { super(opcodes, dexBuf); this.odexBuf = odexBuf; } @Override public boolean isOdexFile() { return true; } public List<String> getDependencies() { if (this.getReader() == null) { final int dexOffset = OdexHeaderItem.getDexOffset(odexBuf); final int dependencyOffset = OdexHeaderItem .getDependenciesOffset(odexBuf) - dexOffset; BaseDexBuffer buf = new BaseDexBuffer(this.buf); int dependencyCount = buf.readInt(dependencyOffset + DEPENDENCY_COUNT_OFFSET); return new VariableSizeList<String>(this, dependencyOffset + DEPENDENCY_START_OFFSET, dependencyCount) { @Override protected String readNextItem(@Nonnull DexReader reader, int index) { int length = reader.readInt(); int offset = reader.getOffset(); reader.moveRelative(length + 20); try { return new String(DexBackedOdexFile.this.buf, offset, length - 1, "US-ASCII"); } catch (UnsupportedEncodingException ex) { throw new RuntimeException(ex); } } }; } else { File file = new File("/system/framework/"); File[] filelist = file.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { // TODO Auto-generated method stub if(pathname.getAbsolutePath().endsWith(".jar")) return true; else return false; } }); List<String> list = new ArrayList<String>(filelist.length); for(int i = 0; i<filelist.length; i++){ list.add(filelist[i].getAbsolutePath()); } return list; } } public static DexBackedOdexFile fromInputStream(@Nonnull Opcodes opcodes, @Nonnull InputStream is) throws IOException { if (!is.markSupported()) { throw new IllegalArgumentException("InputStream must support mark"); } is.mark(8); byte[] partialHeader = new byte[8]; try { ByteStreams.readFully(is, partialHeader); } catch (EOFException ex) { throw new NotADexFile("File is too short"); } finally { is.reset(); } verifyMagic(partialHeader); is.reset(); byte[] odexBuf = new byte[OdexHeaderItem.ITEM_SIZE]; ByteStreams.readFully(is, odexBuf); int dexOffset = OdexHeaderItem.getDexOffset(odexBuf); if (dexOffset > OdexHeaderItem.ITEM_SIZE) { ByteStreams.skipFully(is, dexOffset - OdexHeaderItem.ITEM_SIZE); } byte[] dexBuf = ByteStreams.toByteArray(is); return new DexBackedOdexFile(opcodes, odexBuf, dexBuf); } private static void verifyMagic(byte[] buf) { if (!OdexHeaderItem.verifyMagic(buf)) { StringBuilder sb = new StringBuilder("Invalid magic value:"); for (int i = 0; i < 8; i++) { sb.append(String.format(" %02x", buf[i])); } throw new NotAnOdexFile(sb.toString()); } } public int getOdexVersion() { return OdexHeaderItem.getVersion(odexBuf); } public static class NotAnOdexFile extends RuntimeException { public NotAnOdexFile() { } public NotAnOdexFile(Throwable cause) { super(cause); } public NotAnOdexFile(String message) { super(message); } public NotAnOdexFile(String message, Throwable cause) { super(message, cause); } } }