Use collections instead of lists for variable size "lists" in the dex file

Only things that can be accessed in the dex file in a random access manner
should be exposed as a list. If the list must be read sequentially, it is
exposed in the interface as a Collection if the size is available up-front
or as an Iterable if the size can only be determined by iterating over the
list.
This commit is contained in:
Ben Gruver 2012-11-11 14:18:10 -08:00
parent 65d969c23b
commit 12b970ed4d
37 changed files with 203 additions and 374 deletions

View File

@ -33,7 +33,7 @@ import org.jf.dexlib2.iface.value.AnnotationEncodedValue;
import org.jf.util.IndentingWriter;
import java.io.IOException;
import java.util.List;
import java.util.Collection;
public abstract class AnnotationEncodedValueAdaptor {
@ -47,8 +47,8 @@ public abstract class AnnotationEncodedValueAdaptor {
writer.write(".end subannotation");
}
public static void writeElementsTo(IndentingWriter writer, List<? extends AnnotationElement> annotationElements)
throws IOException {
public static void writeElementsTo(IndentingWriter writer,
Collection<? extends AnnotationElement> annotationElements) throws IOException {
writer.indent(4);
for (AnnotationElement annotationElement: annotationElements) {
writer.write(annotationElement.getName());

View File

@ -33,12 +33,12 @@ import org.jf.dexlib2.iface.value.ArrayEncodedValue;
import org.jf.dexlib2.iface.value.EncodedValue;
import java.io.IOException;
import java.util.List;
import java.util.Collection;
public class ArrayEncodedValueAdaptor {
public static void writeTo(IndentingWriter writer, ArrayEncodedValue arrayEncodedValue) throws IOException {
writer.write('{');
List<? extends EncodedValue> values = arrayEncodedValue.getValue();
Collection<? extends EncodedValue> values = arrayEncodedValue.getValue();
if (values.size() == 0) {
writer.write('}');
return;

View File

@ -31,12 +31,11 @@
package org.jf.dexlib2.dexbacked;
import org.jf.dexlib2.dexbacked.util.VariableSizeList;
import org.jf.dexlib2.dexbacked.util.VariableSizeCollection;
import org.jf.dexlib2.iface.Annotation;
import org.jf.dexlib2.iface.AnnotationElement;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.Collection;
public class DexBackedAnnotation implements Annotation {
@Nonnull public final DexBuffer dexBuf;
@ -60,23 +59,16 @@ public class DexBackedAnnotation implements Annotation {
@Nonnull
@Override
public List<? extends AnnotationElement> getElements() {
public Collection<? extends DexBackedAnnotationElement> getElements() {
DexReader reader = dexBuf.readerAt(elementsOffset);
final int size = reader.readSmallUleb128();
return new VariableSizeList<AnnotationElement>(dexBuf, reader.getOffset()) {
return new VariableSizeCollection<DexBackedAnnotationElement>(dexBuf, reader.getOffset(), size) {
@Nonnull
@Override
protected AnnotationElement readItem(@Nonnull DexReader reader, int index) {
protected DexBackedAnnotationElement readNextItem(@Nonnull DexReader reader, int index) {
return new DexBackedAnnotationElement(reader);
}
@Override
protected void skipItem(@Nonnull DexReader reader, int index) {
DexBackedAnnotationElement.skipFrom(reader);
}
@Override public int size() { return size;}
};
}
}

View File

@ -48,11 +48,6 @@ public class DexBackedAnnotationElement implements AnnotationElement {
this.value = DexBackedEncodedValue.readFrom(reader);
}
public static void skipFrom(@Nonnull DexReader reader) {
reader.skipUleb128();
DexBackedEncodedValue.skipFrom(reader);
}
@Nonnull @Override public String getName() { return dexBuffer.getString(nameIndex); }
@Nonnull @Override public EncodedValue getValue() { return value; }
}

View File

@ -45,6 +45,4 @@ public class DexBackedCatchAllExceptionHandler implements ExceptionHandler {
@Nullable @Override public String getExceptionType() { return null; }
@Override public int getHandlerCodeOffset() { return handlerCodeOffset; }
public static void skipFrom(@Nonnull DexReader reader) { reader.skipUleb128(); }
}

View File

@ -33,14 +33,14 @@ package org.jf.dexlib2.dexbacked;
import com.google.common.collect.ImmutableList;
import org.jf.dexlib2.base.reference.BaseTypeReference;
import org.jf.dexlib2.dexbacked.util.AnnotationsDirectory;
import org.jf.dexlib2.dexbacked.util.FixedSizeList;
import org.jf.dexlib2.dexbacked.util.StaticInitialValueIterator;
import org.jf.dexlib2.dexbacked.util.VariableSizeListWithContext;
import org.jf.dexlib2.dexbacked.util.*;
import org.jf.dexlib2.iface.ClassDef;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.AbstractCollection;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
public class DexBackedClassDef extends BaseTypeReference implements ClassDef {
@ -117,7 +117,7 @@ public class DexBackedClassDef extends BaseTypeReference implements ClassDef {
@Nonnull
@Override
public List<? extends DexBackedField> getFields() {
public Collection<? extends DexBackedField> getFields() {
int classDataOffset = getClassDataOffset();
if (getClassDataOffset() != 0) {
DexReader reader = dexBuf.readerAt(classDataOffset);
@ -133,11 +133,11 @@ public class DexBackedClassDef extends BaseTypeReference implements ClassDef {
dexBuf.readSmallUint(classDefOffset + STATIC_INITIAL_VALUES_OFFSET);
final int fieldsStartOffset = reader.getOffset();
return new VariableSizeListWithContext<DexBackedField>() {
return new AbstractCollection<DexBackedField>() {
@Nonnull
@Override
public VariableSizeListIterator listIterator() {
return new VariableSizeListIterator(dexBuf, fieldsStartOffset) {
public Iterator<DexBackedField> iterator() {
return new VariableSizeIterator<DexBackedField>(dexBuf, fieldsStartOffset, fieldCount) {
private int previousFieldIndex = 0;
@Nonnull private final AnnotationsDirectory.AnnotationIterator annotationIterator =
annotationsDirectory.getFieldAnnotationIterator();
@ -146,7 +146,7 @@ public class DexBackedClassDef extends BaseTypeReference implements ClassDef {
@Nonnull
@Override
protected DexBackedField readItem(@Nonnull DexReader reader, int index) {
protected DexBackedField readNextItem(@Nonnull DexReader reader, int index) {
if (index == staticFieldCount) {
// We reached the end of the static field, restart the numbering for
// instance fields
@ -158,18 +158,6 @@ public class DexBackedClassDef extends BaseTypeReference implements ClassDef {
previousFieldIndex = item.fieldIndex;
return item;
}
@Override
protected void skipItem(@Nonnull DexReader reader, int index) {
if (index == staticFieldCount) {
// We reached the end of the static field, restart the numbering for
// instance fields
previousFieldIndex = 0;
annotationIterator.reset();
}
previousFieldIndex = DexBackedField.skipEncodedField(reader, previousFieldIndex);
staticInitialValueIterator.skipNext();
}
};
}
@ -182,7 +170,7 @@ public class DexBackedClassDef extends BaseTypeReference implements ClassDef {
@Nonnull
@Override
public List<? extends DexBackedMethod> getMethods() {
public Collection<? extends DexBackedMethod> getMethods() {
int classDataOffset = getClassDataOffset();
if (classDataOffset > 0) {
DexReader reader = dexBuf.readerAt(classDataOffset);
@ -197,11 +185,11 @@ public class DexBackedClassDef extends BaseTypeReference implements ClassDef {
final AnnotationsDirectory annotationsDirectory = getAnnotationsDirectory();
final int methodsStartOffset = reader.getOffset();
return new VariableSizeListWithContext<DexBackedMethod>() {
return new AbstractCollection<DexBackedMethod>() {
@Nonnull
@Override
public VariableSizeListIterator listIterator() {
return new VariableSizeListIterator(dexBuf, methodsStartOffset) {
public Iterator<DexBackedMethod> iterator() {
return new VariableSizeIterator<DexBackedMethod>(dexBuf, methodsStartOffset, methodCount) {
private int previousMethodIndex = 0;
@Nonnull private final AnnotationsDirectory.AnnotationIterator methodAnnotationIterator =
annotationsDirectory.getMethodAnnotationIterator();
@ -210,7 +198,7 @@ public class DexBackedClassDef extends BaseTypeReference implements ClassDef {
@Nonnull
@Override
protected DexBackedMethod readItem(@Nonnull DexReader reader, int index) {
protected DexBackedMethod readNextItem(@Nonnull DexReader reader, int index) {
if (index == directMethodCount) {
// We reached the end of the direct methods, restart the numbering for
// virtual methods
@ -223,18 +211,6 @@ public class DexBackedClassDef extends BaseTypeReference implements ClassDef {
previousMethodIndex = item.methodIndex;
return item;
}
@Override
protected void skipItem(@Nonnull DexReader reader, int index) {
if (index == directMethodCount) {
// We reached the end of the direct methods, restart the numbering for
// virtual methods
previousMethodIndex = 0;
methodAnnotationIterator.reset();
parameterAnnotationIterator.reset();
}
previousMethodIndex = DexBackedMethod.skipEncodedMethod(reader, previousMethodIndex);
}
};
}

View File

@ -49,9 +49,4 @@ public class DexBackedExceptionHandler implements ExceptionHandler {
@Nonnull @Override public String getExceptionType() { return dexBuf.getType(typeId); }
@Override public int getHandlerCodeOffset() { return handlerCodeOffset; }
public static void skipFrom(@Nonnull DexReader reader) {
reader.skipUleb128();
reader.skipUleb128();
}
}

View File

@ -96,18 +96,6 @@ public class DexBackedField extends BaseFieldReference implements Field {
return AnnotationsDirectory.getAnnotations(dexBuf, annotationSetOffset);
}
/**
* Skips the reader over a single encoded_field structure.
* @param reader The {@code DexFileReader} to skip
* @param previousFieldIndex The field index of the previous field, or 0 if this is the first
* @return The field index of the field that was skipped
*/
public static int skipEncodedField(@Nonnull DexReader reader, int previousFieldIndex) {
int idxDiff = reader.readSmallUleb128();
reader.skipUleb128();
return previousFieldIndex + idxDiff;
}
/**
* Skips the reader over the specified number of encoded_field structures
*

View File

@ -41,6 +41,7 @@ import org.jf.dexlib2.iface.MethodParameter;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.List;
public class DexBackedMethod extends BaseMethodReference implements Method {
@ -116,7 +117,7 @@ public class DexBackedMethod extends BaseMethodReference implements Method {
@Nonnull
@Override
public List<? extends MethodParameter> getParameters() {
public Collection<? extends MethodParameter> getParameters() {
if (getParametersOffset() > 0) {
DexBackedMethodImplementation methodImpl = getImplementation();
if (methodImpl != null) {
@ -205,17 +206,4 @@ public class DexBackedMethod extends BaseMethodReference implements Method {
}
return parametersOffset;
}
/**
* Skips the reader over a single encoded_method structure.
* @param reader 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 DexReader reader, int previousMethodIndex) {
int idxDiff = reader.readSmallUleb128();
reader.skipUleb128();
reader.skipUleb128();
return previousMethodIndex + idxDiff;
}
}

View File

@ -44,6 +44,7 @@ import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.util.AlignmentUtils;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
@ -131,7 +132,7 @@ public class DexBackedMethodImplementation implements MethodImplementation {
}
@Nonnull
public List<? extends MethodParameter> getParametersWithNames() {
public Collection<? extends MethodParameter> getParametersWithNames() {
return getDebugInfo().getParametersWithNames();
}
}

View File

@ -31,12 +31,12 @@
package org.jf.dexlib2.dexbacked;
import org.jf.dexlib2.dexbacked.util.VariableSizeList;
import org.jf.dexlib2.dexbacked.util.VariableSizeCollection;
import org.jf.dexlib2.iface.ExceptionHandler;
import org.jf.dexlib2.iface.TryBlock;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.Collection;
public class DexBackedTryBlock implements TryBlock {
@Nonnull public final DexBuffer dexBuf;
@ -60,52 +60,33 @@ public class DexBackedTryBlock implements TryBlock {
@Nonnull
@Override
public List<? extends ExceptionHandler> getExceptionHandlers() {
public Collection<? extends ExceptionHandler> getExceptionHandlers() {
DexReader reader =
dexBuf.readerAt(handlersStartOffset + dexBuf.readUshort(tryItemOffset + HANDLER_OFFSET_OFFSET));
final int encodedSize = reader.readSleb128();
if (encodedSize > 0) {
//no catch-all
return new VariableSizeList<ExceptionHandler>(dexBuf, reader.getOffset()) {
return new VariableSizeCollection<ExceptionHandler>(dexBuf, reader.getOffset(), encodedSize) {
@Nonnull
@Override
protected ExceptionHandler readItem(@Nonnull DexReader reader, int index) {
protected DexBackedExceptionHandler readNextItem(@Nonnull DexReader reader, int index) {
return new DexBackedExceptionHandler(reader);
}
@Override
protected void skipItem(@Nonnull DexReader dexReader, int index) {
DexBackedExceptionHandler.skipFrom(dexReader);
}
@Override public int size() { return encodedSize; }
};
} else {
//with catch-all
final int sizeWithCatchAll = (-1 * encodedSize) + 1;
return new VariableSizeList<ExceptionHandler>(dexBuf, reader.getOffset()) {
return new VariableSizeCollection<ExceptionHandler>(dexBuf, reader.getOffset(), sizeWithCatchAll) {
@Nonnull
@Override
protected ExceptionHandler readItem(@Nonnull DexReader dexReader, int index) {
protected ExceptionHandler readNextItem(@Nonnull DexReader dexReader, int index) {
if (index == sizeWithCatchAll-1) {
return new DexBackedCatchAllExceptionHandler(dexReader);
} else {
return new DexBackedExceptionHandler(dexReader);
}
}
@Override
protected void skipItem(@Nonnull DexReader dexReader, int index) {
if (index == sizeWithCatchAll-1) {
DexBackedCatchAllExceptionHandler.skipFrom(dexReader);
} else {
DexBackedExceptionHandler.skipFrom(dexReader);
}
}
@Override public int size() { return sizeWithCatchAll; }
};
}
}

View File

@ -74,6 +74,8 @@ public class DexBackedMethodReference extends BaseMethodReference {
@Nonnull
@Override
public TypeReference readItem(final int index) {
// Can't use DexBackedTypeReference, because we don't want to read in the type index until it
// is asked for
return new TypeReference() {
@Nonnull
@Override

View File

@ -48,11 +48,12 @@ import org.jf.dexlib2.immutable.debug.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
public abstract class DebugInfo implements Iterable<DebugItem> {
@Nonnull public abstract List<? extends MethodParameter> getParametersWithNames();
@Nonnull public abstract Collection<? extends MethodParameter> getParametersWithNames();
public static DebugInfo newOrEmpty(@Nonnull DexBuffer dexBuf, int debugInfoOffset,
@Nonnull DexBackedMethodImplementation methodImpl) {
@ -102,8 +103,8 @@ public abstract class DebugInfo implements Iterable<DebugItem> {
final LocalInfo[] locals = new LocalInfo[registerCount];
Arrays.fill(locals, EMPTY_LOCAL_INFO);
VariableSizeList<? extends MethodParameter> parameters = getParametersWithNames();
final VariableSizeList<? extends MethodParameter>.Iterator parameterIterator = parameters.listIterator();
final VariableSizeIterator<? extends MethodParameter> parameterIterator =
getParametersWithNames().iterator();
// first, we grab all the parameters and temporarily store them at the beginning of locals,
// disregarding any wide types
@ -232,7 +233,7 @@ public abstract class DebugInfo implements Iterable<DebugItem> {
@Nonnull
@Override
public VariableSizeList<MethodParameter> getParametersWithNames() {
public VariableSizeCollection<MethodParameter> getParametersWithNames() {
DexReader reader = dexBuf.readerAt(debugInfoOffset);
reader.skipUleb128();
final int parameterNameCount = reader.readSmallUleb128();
@ -240,10 +241,11 @@ public abstract class DebugInfo implements Iterable<DebugItem> {
methodImpl.method.getParametersWithoutNames();
//TODO: make sure dalvik doesn't allow more parameter names than we have parameters
return new VariableSizeList<MethodParameter>(dexBuf, reader.getOffset()) {
return new VariableSizeCollection<MethodParameter>(dexBuf, reader.getOffset(),
methodParametersWithoutNames.size()) {
@Nonnull
@Override
protected MethodParameter readItem(@Nonnull DexReader reader, int index) {
protected MethodParameter readNextItem(@Nonnull DexReader reader, int index) {
final MethodParameter methodParameter = methodParametersWithoutNames.get(index);
String _name = null;
if (index < parameterNameCount) {
@ -260,8 +262,6 @@ public abstract class DebugInfo implements Iterable<DebugItem> {
}
};
}
@Override public int size() { return methodParametersWithoutNames.size(); }
};
}
}

View File

@ -33,78 +33,34 @@ package org.jf.dexlib2.dexbacked.util;
import org.jf.dexlib2.dexbacked.DexBuffer;
import org.jf.dexlib2.dexbacked.DexReader;
import org.jf.util.AbstractListIterator;
import javax.annotation.Nonnull;
import java.util.AbstractSequentialList;
import java.util.NoSuchElementException;
import java.util.AbstractCollection;
import java.util.Iterator;
/**
* Provides a base class for a list that is backed by variable size items in a dex file
* @param <T> The type of the item that this list contains
*/
public abstract class VariableSizeList<T> extends AbstractSequentialList<T> {
public abstract class VariableSizeCollection<T> extends AbstractCollection<T> {
@Nonnull private final DexBuffer dexBuf;
private final int offset;
private final int size;
public VariableSizeList(@Nonnull DexBuffer dexBuf, int offset) {
public VariableSizeCollection(@Nonnull DexBuffer dexBuf, int offset, int size) {
this.dexBuf = dexBuf;
this.offset = offset;
this.size = size;
}
@Nonnull
protected abstract T readItem(@Nonnull DexReader reader, int index);
@Nonnull protected abstract T readNextItem(@Nonnull DexReader reader, int index);
protected void skipItem(@Nonnull DexReader reader, int index) {
readItem(reader, index);
}
@Nonnull
@Override
public Iterator listIterator(int startIndex) {
Iterator iterator = listIterator();
if (startIndex < 0 || startIndex >= size()) {
throw new IndexOutOfBoundsException();
}
for (int i=0; i<startIndex; i++) {
iterator.skip();
}
return iterator;
}
@Nonnull
@Override
public Iterator listIterator() {
return new Iterator();
}
public class Iterator extends AbstractListIterator<T> {
private int index = 0;
@Nonnull private final DexReader reader = dexBuf.readerAt(offset);
@Override public boolean hasNext() { return index < size(); }
@Override public int nextIndex() { return index; }
protected void checkBounds(int index) {
if (index >= size()) {
throw new NoSuchElementException();
public VariableSizeIterator<T> iterator() {
return new VariableSizeIterator<T>(dexBuf, offset, size) {
@Nonnull
@Override
protected T readNextItem(@Nonnull DexReader reader, int index) {
return VariableSizeCollection.this.readNextItem(reader, index);
}
}
@Nonnull
@Override
public T next() {
checkBounds(index);
return readItem(reader, index++);
}
public void skip() {
checkBounds(index);
skipItem(reader, index++);
}
public int getReaderOffset() {
return reader.getOffset();
}
};
}
@Override public int size() { return size; }
}

View File

@ -0,0 +1,81 @@
/*
* 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.util;
import org.jf.dexlib2.dexbacked.DexBuffer;
import org.jf.dexlib2.dexbacked.DexReader;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Iterator;
import java.util.NoSuchElementException;
public abstract class VariableSizeIterator<T> implements Iterator<T> {
@Nonnull private final DexReader reader;
protected final int size;
private int index;
protected VariableSizeIterator(@Nonnull DexBuffer dexBuf, int offset, int size) {
this.reader = dexBuf.readerAt(offset);
this.size = size;
}
/**
* Reads the next item from reader.
*
* @param reader The {@code DexReader} to read the next item from
* @param index The index of the item being read. This is guaranteed to be less than {@code size}
* @return The item that was read
*/
@Nonnull protected abstract T readNextItem(@Nonnull DexReader reader, int index);
public int getReaderOffset() {
return reader.getOffset();
}
@Override
public boolean hasNext() {
return index < size;
}
@Override
@Nonnull
public T next() {
if (index >= size) {
throw new NoSuchElementException();
}
return readNextItem(reader, index++);
}
@Override public void remove() { throw new UnsupportedOperationException(); }
}

View File

@ -1,117 +0,0 @@
/*
* 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.util;
import org.jf.dexlib2.dexbacked.DexBuffer;
import org.jf.dexlib2.dexbacked.DexReader;
import org.jf.util.AbstractListIterator;
import javax.annotation.Nonnull;
import java.util.AbstractSequentialList;
import java.util.NoSuchElementException;
/**
* Provides a base class for a list that is backed by variable size items in a dex file.
*
* This class is similar to VariableSizeList, except that it requires the implementing
* class to implement {@code listIterator}. This allows the base class to extend
* {@code Iterator}, when it needs to store additional context while iterating the list.
*
* @param <T> The type of the item that this list contains
*/
public abstract class VariableSizeListWithContext<T> extends AbstractSequentialList<T> {
@Nonnull
@Override
public VariableSizeListIterator listIterator(int startIndex) {
VariableSizeListIterator iterator = listIterator();
if (startIndex < 0 || startIndex >= size()) {
throw new IndexOutOfBoundsException();
}
for (int i=0; i<startIndex; i++) {
iterator.skip();
}
return iterator;
}
@Nonnull @Override public abstract VariableSizeListIterator listIterator();
public abstract class VariableSizeListIterator extends AbstractListIterator<T> {
private int index = 0;
@Nonnull private final DexReader reader;
public VariableSizeListIterator(@Nonnull DexBuffer dexBuf, int offset) {
this.reader = dexBuf.readerAt(offset);
}
/**
* Read the next item from {@code reader}.
*
* The index field will contain the index of the item being read.
*
* @return The next item that was read from {@code reader}
*/
@Nonnull protected abstract T readItem(@Nonnull DexReader reader, int index);
/**
* Skip the next item in {@code reader}.
*
* The default implementation simply calls readNextItem and throws away the result. This
* can be overridden if skipping an item can be implemented more efficiently than reading
* the same item.
*/
protected void skipItem(@Nonnull DexReader reader, int index) {
readItem(reader, index);
}
@Override public boolean hasNext() { return index < size(); }
@Override public int nextIndex() { return index; }
protected void checkBounds(int index) {
if (index >= size()) {
throw new NoSuchElementException();
}
}
@Nonnull
@Override
public T next() {
checkBounds(index);
return readItem(reader, index++);
}
public void skip() {
checkBounds(index);
skipItem(reader, index++);
}
}
}

View File

@ -31,37 +31,37 @@
package org.jf.dexlib2.dexbacked.value;
import org.jf.dexlib2.ValueType;
import org.jf.dexlib2.base.value.BaseAnnotationEncodedValue;
import org.jf.dexlib2.dexbacked.DexBackedAnnotationElement;
import org.jf.dexlib2.dexbacked.DexBuffer;
import org.jf.dexlib2.dexbacked.DexReader;
import org.jf.dexlib2.dexbacked.util.VariableSizeList;
import org.jf.dexlib2.iface.AnnotationElement;
import org.jf.dexlib2.dexbacked.util.VariableSizeCollection;
import org.jf.dexlib2.iface.value.AnnotationEncodedValue;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.Collection;
public class DexBackedAnnotationEncodedValue extends BaseAnnotationEncodedValue implements AnnotationEncodedValue {
@Nonnull public final DexBuffer dexBuf;
@Nonnull public final String type;
private final int elementCount;
private final int elementsOffset;
public DexBackedAnnotationEncodedValue(@Nonnull DexReader reader) {
this.dexBuf = reader.getDexBuffer();
this.type = reader.getType(reader.readSmallUleb128());
this.elementCount = reader.readSmallUleb128();
this.elementsOffset = reader.getOffset();
skipElements(reader);
skipElements(reader, elementCount);
}
public static void skipFrom(@Nonnull DexReader reader) {
reader.skipUleb128();
skipElements(reader);
reader.skipUleb128(); // type
int elementCount = reader.readSmallUleb128();
skipElements(reader, elementCount);
}
private static void skipElements(@Nonnull DexReader reader) {
int elementCount = reader.readSmallUleb128();
private static void skipElements(@Nonnull DexReader reader, int elementCount) {
for (int i=0; i<elementCount; i++) {
reader.skipUleb128();
DexBackedEncodedValue.skipFrom(reader);
@ -72,23 +72,13 @@ public class DexBackedAnnotationEncodedValue extends BaseAnnotationEncodedValue
@Nonnull
@Override
public List<? extends AnnotationElement> getElements() {
DexReader reader = dexBuf.readerAt(elementsOffset);
final int size = reader.readSmallUleb128();
return new VariableSizeList<AnnotationElement>(dexBuf, reader.getOffset()) {
public Collection<? extends DexBackedAnnotationElement> getElements() {
return new VariableSizeCollection<DexBackedAnnotationElement>(dexBuf, elementsOffset, elementCount) {
@Nonnull
@Override
protected AnnotationElement readItem(@Nonnull DexReader dexReader, int index) {
protected DexBackedAnnotationElement readNextItem(@Nonnull DexReader dexReader, int index) {
return new DexBackedAnnotationElement(dexReader);
}
@Override
protected void skipItem(@Nonnull DexReader reader, int index) {
DexBackedAnnotationElement.skipFrom(reader);
}
@Override public int size() { return size;}
};
}
}

View File

@ -31,29 +31,34 @@
package org.jf.dexlib2.dexbacked.value;
import org.jf.dexlib2.ValueType;
import org.jf.dexlib2.base.value.BaseArrayEncodedValue;
import org.jf.dexlib2.dexbacked.DexBuffer;
import org.jf.dexlib2.dexbacked.DexReader;
import org.jf.dexlib2.dexbacked.util.VariableSizeList;
import org.jf.dexlib2.dexbacked.util.VariableSizeCollection;
import org.jf.dexlib2.iface.value.ArrayEncodedValue;
import org.jf.dexlib2.iface.value.EncodedValue;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.Collection;
public class DexBackedArrayEncodedValue extends BaseArrayEncodedValue implements ArrayEncodedValue {
@Nonnull public final DexBuffer dexBuf;
private final int elementCount;
private final int encodedArrayOffset;
public DexBackedArrayEncodedValue(@Nonnull DexReader reader) {
this.dexBuf = reader.getDexBuffer();
this.elementCount = reader.readSmallUleb128();
this.encodedArrayOffset = reader.getOffset();
skipFrom(reader);
skipElementsFrom(reader, elementCount);
}
public static void skipFrom(@Nonnull DexReader reader) {
int elementCount = reader.readSmallUleb128();
skipElementsFrom(reader, elementCount);
}
private static void skipElementsFrom(@Nonnull DexReader reader, int elementCount) {
for (int i=0; i<elementCount; i++) {
DexBackedEncodedValue.skipFrom(reader);
}
@ -61,23 +66,13 @@ public class DexBackedArrayEncodedValue extends BaseArrayEncodedValue implements
@Nonnull
@Override
public List<? extends EncodedValue> getValue() {
DexReader reader = dexBuf.readerAt(encodedArrayOffset);
final int size = reader.readSmallUleb128();
return new VariableSizeList<EncodedValue>(dexBuf, reader.getOffset()) {
public Collection<? extends EncodedValue> getValue() {
return new VariableSizeCollection<EncodedValue>(dexBuf, encodedArrayOffset, elementCount) {
@Nonnull
@Override
protected EncodedValue readItem(@Nonnull DexReader dexReader, int index) {
protected EncodedValue readNextItem(@Nonnull DexReader dexReader, int index) {
return DexBackedEncodedValue.readFrom(dexReader);
}
@Override
protected void skipItem(@Nonnull DexReader reader, int index) {
DexBackedEncodedValue.skipFrom(reader);
}
@Override public int size() { return size;}
};
}
}

View File

@ -32,6 +32,7 @@
package org.jf.dexlib2.iface;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.List;
public interface Annotation {
@ -42,5 +43,5 @@ public interface Annotation {
int getVisibility();
@Nonnull String getType();
@Nonnull List<? extends AnnotationElement> getElements();
@Nonnull Collection<? extends AnnotationElement> getElements();
}

View File

@ -35,6 +35,7 @@ import org.jf.dexlib2.iface.reference.TypeReference;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.List;
public interface ClassDef extends TypeReference {
@ -44,6 +45,6 @@ public interface ClassDef extends TypeReference {
@Nonnull List<String> getInterfaces();
@Nullable String getSourceFile();
@Nonnull List<? extends Annotation> getAnnotations();
@Nonnull List<? extends Field> getFields();
@Nonnull List<? extends Method> getMethods();
@Nonnull Collection<? extends Field> getFields();
@Nonnull Collection<? extends Method> getMethods();
}

View File

@ -35,12 +35,13 @@ import org.jf.dexlib2.iface.reference.MethodReference;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.List;
public interface Method extends MethodReference {
@Nonnull String getContainingClass();
@Nonnull String getName();
@Nonnull List<? extends MethodParameter> getParameters();
@Nonnull Collection<? extends MethodParameter> getParameters();
@Nonnull String getReturnType();
int getAccessFlags();
@Nonnull List<? extends Annotation> getAnnotations();

View File

@ -34,9 +34,9 @@ package org.jf.dexlib2.iface;
import org.jf.dexlib2.iface.reference.TypeReference;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.Collection;
public interface MethodPrototype {
@Nonnull List<? extends TypeReference> getParameters();
@Nonnull Collection<? extends TypeReference> getParameters();
@Nonnull String getReturnType();
}

View File

@ -32,10 +32,10 @@
package org.jf.dexlib2.iface;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.Collection;
public interface TryBlock {
int getStartCodeOffset();
int getCodeUnitCount();
@Nonnull List<? extends ExceptionHandler> getExceptionHandlers();
@Nonnull Collection<? extends ExceptionHandler> getExceptionHandlers();
}

View File

@ -34,11 +34,11 @@ package org.jf.dexlib2.iface.reference;
import org.jf.dexlib2.iface.MethodPrototype;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.Collection;
public interface MethodReference extends Reference, MethodPrototype {
@Nonnull String getContainingClass();
@Nonnull String getName();
@Nonnull List<? extends TypeReference> getParameters();
@Nonnull Collection<? extends TypeReference> getParameters();
@Nonnull String getReturnType();
}

View File

@ -34,9 +34,10 @@ package org.jf.dexlib2.iface.value;
import org.jf.dexlib2.iface.AnnotationElement;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.List;
public interface AnnotationEncodedValue extends EncodedValue {
@Nonnull String getType();
@Nonnull List<? extends AnnotationElement> getElements();
@Nonnull Collection<? extends AnnotationElement> getElements();
}

View File

@ -32,8 +32,9 @@
package org.jf.dexlib2.iface.value;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.List;
public interface ArrayEncodedValue extends EncodedValue {
@Nonnull List<? extends EncodedValue> getValue();
@Nonnull Collection<? extends EncodedValue> getValue();
}

View File

@ -39,6 +39,7 @@ import org.jf.util.ImmutableListUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.List;
public class ImmutableAnnotation implements Annotation {
@ -48,7 +49,7 @@ public class ImmutableAnnotation implements Annotation {
public ImmutableAnnotation(int visibility,
@Nonnull String type,
@Nullable List<? extends AnnotationElement> elements) {
@Nullable Collection<? extends AnnotationElement> elements) {
this.visibility = visibility;
this.type = type;
this.elements = ImmutableAnnotationElement.immutableListOf(elements);

View File

@ -72,7 +72,7 @@ public class ImmutableAnnotationElement implements AnnotationElement {
@Nonnull
public static ImmutableList<ImmutableAnnotationElement> immutableListOf(
@Nullable List<? extends AnnotationElement> list) {
@Nullable Iterable<? extends AnnotationElement> list) {
return CONVERTER.convert(list);
}

View File

@ -42,6 +42,7 @@ import org.jf.util.ImmutableListUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.List;
public class ImmutableClassDef extends BaseTypeReference implements ClassDef {
@ -60,8 +61,8 @@ public class ImmutableClassDef extends BaseTypeReference implements ClassDef {
@Nullable List<String> interfaces,
@Nullable String sourceFile,
@Nullable List<? extends Annotation> annotations,
@Nullable List<? extends Field> fields,
@Nullable List<? extends Method> methods) {
@Nullable Collection<? extends Field> fields,
@Nullable Collection<? extends Method> methods) {
this.type = type;
this.accessFlags = accessFlags;
this.superclass = superclass;

View File

@ -37,7 +37,6 @@ import org.jf.util.ImmutableListConverter;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
public class ImmutableExceptionHandler implements ExceptionHandler {
@Nullable public final String exceptionType;
@ -63,7 +62,7 @@ public class ImmutableExceptionHandler implements ExceptionHandler {
@Nonnull
public static ImmutableList<ImmutableExceptionHandler> immutableListOf(
@Nullable List<? extends ExceptionHandler> list) {
@Nullable Iterable<? extends ExceptionHandler> list) {
return CONVERTER.convert(list);
}

View File

@ -102,7 +102,7 @@ public class ImmutableField extends BaseFieldReference implements Field {
@Nonnull @Override public ImmutableList<? extends ImmutableAnnotation> getAnnotations() { return annotations; }
@Nonnull
public static ImmutableList<ImmutableField> immutableListOf(@Nullable List<? extends Field> list) {
public static ImmutableList<ImmutableField> immutableListOf(@Nullable Iterable<? extends Field> list) {
return CONVERTER.convert(list);
}

View File

@ -42,6 +42,7 @@ import org.jf.util.ImmutableListUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.List;
public class ImmutableMethod extends BaseMethodReference implements Method {
@ -55,7 +56,7 @@ public class ImmutableMethod extends BaseMethodReference implements Method {
public ImmutableMethod(@Nonnull String containingClass,
@Nonnull String name,
@Nullable List<? extends MethodParameter> parameters,
@Nullable Collection<? extends MethodParameter> parameters,
@Nonnull String returnType,
int accessFlags,
@Nullable List<? extends Annotation> annotations,
@ -108,7 +109,7 @@ public class ImmutableMethod extends BaseMethodReference implements Method {
@Nullable public ImmutableMethodImplementation getImplementation() { return methodImplementation; }
@Nonnull
public static ImmutableList<ImmutableMethod> immutableListOf(@Nullable List<? extends Method> list) {
public static ImmutableList<ImmutableMethod> immutableListOf(@Nullable Iterable<? extends Method> list) {
return CONVERTER.convert(list);
}

View File

@ -82,7 +82,7 @@ public class ImmutableMethodParameter extends BaseTypeReference implements Metho
@Nonnull
public static ImmutableList<ImmutableMethodParameter> immutableListOf(
@Nullable List<? extends MethodParameter> list) {
@Nullable Iterable<? extends MethodParameter> list) {
return CONVERTER.convert(list);
}

View File

@ -39,6 +39,7 @@ import org.jf.util.ImmutableListUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.List;
public class ImmutableTryBlock implements TryBlock {
@ -48,7 +49,7 @@ public class ImmutableTryBlock implements TryBlock {
public ImmutableTryBlock(int startCodeOffset,
int codeUnitCount,
@Nullable List<? extends ExceptionHandler> exceptionHandlers) {
@Nullable Collection<? extends ExceptionHandler> exceptionHandlers) {
this.startCodeOffset = startCodeOffset;
this.codeUnitCount = codeUnitCount;
this.exceptionHandlers = ImmutableExceptionHandler.immutableListOf(exceptionHandlers);

View File

@ -40,7 +40,7 @@ import org.jf.util.ImmutableListUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Collection;
public class ImmutableAnnotationEncodedValue extends BaseAnnotationEncodedValue
implements ImmutableEncodedValue, AnnotationEncodedValue {
@ -48,7 +48,7 @@ public class ImmutableAnnotationEncodedValue extends BaseAnnotationEncodedValue
@Nonnull public final ImmutableList<? extends ImmutableAnnotationElement> elements;
public ImmutableAnnotationEncodedValue(@Nonnull String type,
@Nullable List<? extends AnnotationElement> elements) {
@Nullable Collection<? extends AnnotationElement> elements) {
this.type = type;
this.elements = ImmutableAnnotationElement.immutableListOf(elements);
}

View File

@ -37,13 +37,13 @@ import org.jf.dexlib2.iface.value.ArrayEncodedValue;
import org.jf.dexlib2.iface.value.EncodedValue;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.Collection;
public class ImmutableArrayEncodedValue extends BaseArrayEncodedValue
implements ImmutableEncodedValue, ArrayEncodedValue {
@Nonnull public final ImmutableList<? extends ImmutableEncodedValue> value;
public ImmutableArrayEncodedValue(@Nonnull List<? extends EncodedValue> value) {
public ImmutableArrayEncodedValue(@Nonnull Collection<? extends EncodedValue> value) {
this.value = ImmutableEncodedValueFactory.immutableListOf(value);
}

View File

@ -39,7 +39,6 @@ import org.jf.util.ImmutableListConverter;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
public class ImmutableEncodedValueFactory {
@Nullable
@ -87,7 +86,8 @@ public class ImmutableEncodedValueFactory {
}
@Nonnull
public static ImmutableList<ImmutableEncodedValue> immutableListOf(@Nullable List<? extends EncodedValue> list) {
public static ImmutableList<ImmutableEncodedValue> immutableListOf
(@Nullable Iterable<? extends EncodedValue> list) {
return CONVERTER.convert(list);
}