/*
* 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);
}
}
}