mirror of
https://github.com/revanced/smali.git
synced 2025-05-29 04:10:13 +02:00
Add DexBacked implementation of Method
This commit is contained in:
parent
f3e03c0a94
commit
63d8406703
@ -54,6 +54,14 @@ public class DexFileReader {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getMethodIdItemOffset(int methodIndex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getProtoIdItemOffset(int methodIndex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String getType(int typeIndex) {
|
||||
return null;
|
||||
}
|
||||
|
@ -163,6 +163,52 @@ public class DexBackedClassDef implements ClassDef {
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<? extends Method> getMethods() {
|
||||
return null;
|
||||
if (classDataOffset > 0) {
|
||||
DexFileReader reader = dexFile.readerAt(classDataOffset);
|
||||
int staticFieldCount = reader.readSmallUleb128();
|
||||
int instanceFieldCount = reader.readSmallUleb128();
|
||||
int directMethodCount = reader.readSmallUleb128();
|
||||
int virtualMethodCount = reader.readSmallUleb128();
|
||||
final int methodCount = directMethodCount + virtualMethodCount;
|
||||
if (methodCount > 0) {
|
||||
DexBackedField.skipAllFields(reader, staticFieldCount + instanceFieldCount);
|
||||
|
||||
final int methodsStartOffset = reader.getOffset();
|
||||
|
||||
return new VariableSizeListWithContext<DexBackedMethod>() {
|
||||
@Nonnull
|
||||
@Override
|
||||
public Iterator listIterator() {
|
||||
return new Iterator(dexFile, methodsStartOffset) {
|
||||
private int previousMethodIndex = 0;
|
||||
@Nonnull private final AnnotationsDirectory.AnnotationIterator methodAnnotationIterator =
|
||||
annotationsDirectory.getMethodAnnotationIterator();
|
||||
@Nonnull private final AnnotationsDirectory.AnnotationIterator parameterAnnotationIterator =
|
||||
annotationsDirectory.getParameterAnnotationIterator();
|
||||
@Nonnull private final StaticInitialValueIterator staticInitialValueIterator =
|
||||
StaticInitialValueIterator.newOrEmpty(dexFile, staticInitialValuesOffset);
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
protected DexBackedMethod readItem(DexFileReader reader, int index) {
|
||||
DexBackedMethod item = new DexBackedMethod(reader, previousMethodIndex,
|
||||
methodAnnotationIterator, parameterAnnotationIterator);
|
||||
previousMethodIndex = item.methodIndex;
|
||||
return item;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void skipItem(DexFileReader reader, int index) {
|
||||
previousMethodIndex = DexBackedMethod.skipEncodedMethod(reader, previousMethodIndex);
|
||||
staticInitialValueIterator.skipNext();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override public int size() { return methodCount; }
|
||||
};
|
||||
}
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright 2012, 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.collect.ImmutableList;
|
||||
import org.jf.dexlib2.DexFile;
|
||||
import org.jf.dexlib2.DexFileReader;
|
||||
import org.jf.dexlib2.dexbacked.util.AnnotationsDirectory;
|
||||
import org.jf.dexlib2.dexbacked.util.FixedSizeList;
|
||||
import org.jf.dexlib2.iface.Annotation;
|
||||
import org.jf.dexlib2.iface.Method;
|
||||
import org.jf.dexlib2.iface.MethodImplementation;
|
||||
import org.jf.dexlib2.iface.MethodParameter;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
public class DexBackedMethod implements Method {
|
||||
@Nonnull public final DexFile dexFile;
|
||||
|
||||
@Nonnull public final String name;
|
||||
public final int accessFlags;
|
||||
@Nonnull public final String returnType;
|
||||
|
||||
private final int codeOffset;
|
||||
private final int parametersOffset;
|
||||
private final int methodAnnotationSetOffset;
|
||||
private final List<List<? extends DexBackedAnnotation>> parameterAnnotations;
|
||||
|
||||
public final int methodIndex;
|
||||
|
||||
// method_id_item offsets
|
||||
private static final int PROTO_OFFSET = 2;
|
||||
private static final int NAME_OFFSET = 4;
|
||||
|
||||
// proto_id_item offsets
|
||||
private static final int RETURN_TYPE_OFFSET = 4;
|
||||
private static final int PARAMETERS_OFFSET = 8;
|
||||
|
||||
public DexBackedMethod(@Nonnull DexFileReader dexFileReader,
|
||||
int previousMethodIndex,
|
||||
@Nonnull AnnotationsDirectory.AnnotationIterator methodAnnotationIterator,
|
||||
@Nonnull AnnotationsDirectory.AnnotationIterator paramaterAnnotationIterator) {
|
||||
this.dexFile = dexFileReader.getDexFile();
|
||||
|
||||
int methodIndexDiff = dexFileReader.readSmallUleb128();
|
||||
this.methodIndex = methodIndexDiff + previousMethodIndex;
|
||||
this.accessFlags = dexFileReader.readSmallUleb128();
|
||||
this.codeOffset = dexFileReader.readSmallUleb128();
|
||||
|
||||
this.methodAnnotationSetOffset = methodAnnotationIterator.seekTo(methodIndex);
|
||||
int parameterAnnotationSetListOffset = paramaterAnnotationIterator.seekTo(methodIndex);
|
||||
this.parameterAnnotations =
|
||||
AnnotationsDirectory.getParameterAnnotations(dexFile, parameterAnnotationSetListOffset);
|
||||
|
||||
int methodIdItemOffset = dexFileReader.getMethodIdItemOffset(methodIndex);
|
||||
int protoIndex = dexFileReader.readUshort(methodIdItemOffset + PROTO_OFFSET);
|
||||
int protoIdItemOffset = dexFileReader.getProtoIdItemOffset(protoIndex);
|
||||
|
||||
this.name = dexFileReader.getString(dexFileReader.readSmallUint(methodIdItemOffset + NAME_OFFSET));
|
||||
|
||||
this.returnType = dexFileReader.getString(dexFileReader.readSmallUint(protoIdItemOffset + RETURN_TYPE_OFFSET));
|
||||
this.parametersOffset = dexFileReader.readSmallUint(protoIdItemOffset + PARAMETERS_OFFSET);
|
||||
}
|
||||
|
||||
|
||||
@Nonnull @Override public String getName() { return name; }
|
||||
@Override public int getAccessFlags() { return accessFlags; }
|
||||
@Nonnull @Override public String getReturnType() { return returnType; }
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<? extends MethodParameter> getParameters() {
|
||||
if (parametersOffset > 0) {
|
||||
final int size = dexFile.readSmallUint(parametersOffset);
|
||||
|
||||
return new FixedSizeList<MethodParameter>() {
|
||||
@Override
|
||||
public MethodParameter readItem(final int index) {
|
||||
return new MethodParameter() {
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getType() {
|
||||
int typeIndex = dexFile.readUshort(parametersOffset + 4 + (index * 2));
|
||||
return dexFile.getType(typeIndex);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<? extends Annotation> getAnnotations() {
|
||||
if (index < parameterAnnotations.size()) {
|
||||
return parameterAnnotations.get(index);
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override public int size() { return size; }
|
||||
};
|
||||
}
|
||||
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<? extends Annotation> getAnnotations() {
|
||||
return AnnotationsDirectory.getAnnotations(dexFile, methodAnnotationSetOffset);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public MethodImplementation getImplementation() {
|
||||
if (codeOffset > 0) {
|
||||
return new DexBackedMethodImplementation(dexFile, codeOffset);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips the reader over a single encoded_method structure.
|
||||
* @param dexFileReader The {@code DexFileReader} to skip
|
||||
* @param previousMethodIndex The method index of the previous field, or 0 if this is the first
|
||||
* @return The method index of the field that was skipped
|
||||
*/
|
||||
public static int skipEncodedMethod(@Nonnull DexFileReader dexFileReader, int previousMethodIndex) {
|
||||
int idxDiff = dexFileReader.readSmallUleb128();
|
||||
dexFileReader.skipUleb128();
|
||||
dexFileReader.skipUleb128();
|
||||
return previousMethodIndex + idxDiff;
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2012, 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 org.jf.dexlib2.DexFile;
|
||||
import org.jf.dexlib2.iface.MethodImplementation;
|
||||
import org.jf.dexlib2.iface.TryBlock;
|
||||
import org.jf.dexlib2.iface.instruction.Instruction;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
|
||||
public class DexBackedMethodImplementation implements MethodImplementation {
|
||||
@Nonnull public final DexFile dexFile;
|
||||
|
||||
public DexBackedMethodImplementation(@Nonnull DexFile dexFile,
|
||||
int codeOffset) {
|
||||
this.dexFile = dexFile;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getRegisterCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<? extends Instruction> getInstructions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<? extends TryBlock> getTryBlocks() {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -43,11 +43,15 @@ public abstract class AnnotationsDirectory {
|
||||
@Override public int getFieldAnnotationCount() { return 0; }
|
||||
@Nonnull @Override public List<? extends DexBackedAnnotation> getClassAnnotations() {return ImmutableList.of();}
|
||||
@Nonnull @Override public AnnotationIterator getFieldAnnotationIterator() { return AnnotationIterator.EMPTY; }
|
||||
@Nonnull @Override public AnnotationIterator getMethodAnnotationIterator() { return AnnotationIterator.EMPTY; }
|
||||
@Nonnull @Override public AnnotationIterator getParameterAnnotationIterator() {return AnnotationIterator.EMPTY;}
|
||||
};
|
||||
|
||||
public abstract int getFieldAnnotationCount();
|
||||
@Nonnull public abstract List<? extends DexBackedAnnotation> getClassAnnotations();
|
||||
@Nonnull public abstract AnnotationIterator getFieldAnnotationIterator();
|
||||
@Nonnull public abstract AnnotationIterator getMethodAnnotationIterator();
|
||||
@Nonnull public abstract AnnotationIterator getParameterAnnotationIterator();
|
||||
|
||||
public static AnnotationsDirectory newOrEmpty(@Nonnull DexFile dexFile,
|
||||
int directoryAnnotationsOffset) {
|
||||
@ -85,14 +89,38 @@ public abstract class AnnotationsDirectory {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
public static List<List<? extends DexBackedAnnotation>> getParameterAnnotations(@Nonnull final DexFile dexFile,
|
||||
final int annotationSetListOffset) {
|
||||
if (annotationSetListOffset > 0) {
|
||||
final int size = dexFile.readSmallUint(annotationSetListOffset);
|
||||
|
||||
return new FixedSizeList<List<? extends DexBackedAnnotation>>() {
|
||||
@Override
|
||||
public List<? extends DexBackedAnnotation> readItem(int index) {
|
||||
int annotationSetOffset = dexFile.readSmallUint(annotationSetListOffset + 4 + index * 4);
|
||||
return getAnnotations(dexFile, annotationSetOffset);
|
||||
}
|
||||
|
||||
@Override public int size() { return size; }
|
||||
};
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
private static class AnnotationsDirectoryImpl extends AnnotationsDirectory {
|
||||
@Nonnull public final DexFile dexFile;
|
||||
private final int directoryOffset;
|
||||
|
||||
private static final int FIELD_COUNT_OFFSET = 4;
|
||||
private static final int METHOD_COUNT_OFFSET = 8;
|
||||
private static final int PARAMETER_COUNT_OFFSET = 12;
|
||||
private static final int ANNOTATIONS_START_OFFSET = 16;
|
||||
|
||||
/** The size of a field_annotation structure */
|
||||
private static final int FIELD_ANNOTATION_SIZE = 8;
|
||||
/** The size of a method_annotation structure */
|
||||
private static final int METHOD_ANNOTATION_SIZE = 8;
|
||||
|
||||
public AnnotationsDirectoryImpl(@Nonnull DexFile dexFile,
|
||||
int directoryOffset) {
|
||||
this.dexFile = dexFile;
|
||||
@ -103,6 +131,14 @@ public abstract class AnnotationsDirectory {
|
||||
return dexFile.readSmallUint(directoryOffset + FIELD_COUNT_OFFSET);
|
||||
}
|
||||
|
||||
public int getMethodAnnotationCount() {
|
||||
return dexFile.readSmallUint(directoryOffset + METHOD_COUNT_OFFSET);
|
||||
}
|
||||
|
||||
public int getParameterAnnotationCount() {
|
||||
return dexFile.readSmallUint(directoryOffset + PARAMETER_COUNT_OFFSET);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<? extends DexBackedAnnotation> getClassAnnotations() {
|
||||
return getAnnotations(dexFile, dexFile.readSmallUint(directoryOffset));
|
||||
@ -113,31 +149,49 @@ public abstract class AnnotationsDirectory {
|
||||
return new AnnotationIteratorImpl(directoryOffset + ANNOTATIONS_START_OFFSET, getFieldAnnotationCount());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public AnnotationIterator getMethodAnnotationIterator() {
|
||||
int fieldCount = getFieldAnnotationCount();
|
||||
int methodAnnotationsOffset = directoryOffset + ANNOTATIONS_START_OFFSET +
|
||||
fieldCount * FIELD_ANNOTATION_SIZE;
|
||||
return new AnnotationIteratorImpl(methodAnnotationsOffset, getMethodAnnotationCount());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public AnnotationIterator getParameterAnnotationIterator() {
|
||||
int fieldCount = getFieldAnnotationCount();
|
||||
int methodCount = getMethodAnnotationCount();
|
||||
int parameterAnnotationsOffset = directoryOffset + ANNOTATIONS_START_OFFSET +
|
||||
fieldCount * FIELD_ANNOTATION_SIZE +
|
||||
methodCount + METHOD_ANNOTATION_SIZE;
|
||||
return new AnnotationIteratorImpl(parameterAnnotationsOffset, getParameterAnnotationCount());
|
||||
}
|
||||
|
||||
private class AnnotationIteratorImpl implements AnnotationIterator {
|
||||
private final int startOffset;
|
||||
private final int size;
|
||||
private int currentIndex;
|
||||
private int currentFieldIndex;
|
||||
private int currentItemIndex;
|
||||
|
||||
public AnnotationIteratorImpl(int startOffset, int size) {
|
||||
this.startOffset = startOffset;
|
||||
this.size = size;
|
||||
if (size > 0) {
|
||||
currentFieldIndex = dexFile.readSmallUint(startOffset);
|
||||
currentItemIndex = dexFile.readSmallUint(startOffset);
|
||||
this.currentIndex = 0;
|
||||
} else {
|
||||
currentFieldIndex = -1;
|
||||
currentItemIndex = -1;
|
||||
this.currentIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public int seekTo(int fieldIndex) {
|
||||
while (currentFieldIndex < fieldIndex && (currentIndex+1) < size) {
|
||||
public int seekTo(int itemIndex) {
|
||||
while (currentItemIndex < itemIndex && (currentIndex+1) < size) {
|
||||
currentIndex++;
|
||||
currentFieldIndex = dexFile.readSmallUint(startOffset + (currentIndex*8));
|
||||
currentItemIndex = dexFile.readSmallUint(startOffset + (currentIndex*8));
|
||||
}
|
||||
|
||||
if (currentFieldIndex == fieldIndex) {
|
||||
if (currentItemIndex == itemIndex) {
|
||||
return dexFile.readSmallUint(startOffset + (currentIndex*8)+4);
|
||||
}
|
||||
return 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user