mirror of
https://github.com/revanced/smali.git
synced 2025-05-09 10:54:29 +02:00
Move new dexlib to trunk
git-svn-id: https://smali.googlecode.com/svn/trunk@355 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
parent
02017677b7
commit
83b80f81d3
337
dexlib/src/main/java/org/jf/dexlib/AnnotationDirectoryItem.java
Normal file
337
dexlib/src/main/java/org/jf/dexlib/AnnotationDirectoryItem.java
Normal file
@ -0,0 +1,337 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.EncodedValue.AnnotationEncodedSubValue;
|
||||
import org.jf.dexlib.Util.ArrayUtils;
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class AnnotationDirectoryItem extends Item<AnnotationDirectoryItem> {
|
||||
private AnnotationSetItem classAnnotations;
|
||||
|
||||
private FieldIdItem[] fieldAnnotationFields;
|
||||
private AnnotationSetItem[] fieldAnnotations;
|
||||
|
||||
private MethodIdItem[] methodAnnotationMethods;
|
||||
private AnnotationSetItem[] methodAnnotations;
|
||||
|
||||
private MethodIdItem[] parameterAnnotationMethods;
|
||||
private AnnotationSetRefList[] parameterAnnotations;
|
||||
|
||||
/**
|
||||
* typically each AnnotationDirectoryItem will have a distinct parent. The only case that isn't true is when
|
||||
* the AnnotationDirectoryItem *only* contains class annotations, with no other type of annotation. In that
|
||||
* case, the same AnnotationDirectoryItem could be referenced from multiple classes.
|
||||
* This isn't a problem though, because this field is only used in compareTo to determine the sort order,
|
||||
* which handles it as a special case
|
||||
*/
|
||||
private ClassDefItem parent = null;
|
||||
|
||||
/**
|
||||
* Creates a new uninitialized <code>AnnotationDirectoryItem</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
*/
|
||||
protected AnnotationDirectoryItem(DexFile dexFile) {
|
||||
super(dexFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>AnnotationDirectoryItem</code> with the given values
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param classAnnotations The annotations associated with the overall class
|
||||
* @param fieldAnnotationFields An array of <code>FieldIdItem</code> objects that the annotations in
|
||||
* <code>fieldAnnotations</code> are associated with
|
||||
* @param fieldAnnotations An array of <code>AnnotationSetItem</code> objects that contain the annotations for the
|
||||
* fields in <code>fieldAnnotationFields</code>
|
||||
* @param methodAnnotationMethods An array of <code>MethodIdItem</code> objects that the annotations in
|
||||
* <code>methodAnnotations</code> are associated with
|
||||
* @param methodAnnotations An array of <code>AnnotationSetItem</code> objects that contain the annotations for the
|
||||
* methods in <code>methodAnnotationMethods</code>
|
||||
* @param parameterAnnotationMethods An array of <code>MethodIdItem</code> objects that the annotations in
|
||||
* <code>parameterAnnotations</code> are associated with
|
||||
* @param parameterAnnotations An array of <code>AnnotationSetRefList</code> objects that contain the parameter
|
||||
* annotations for the methods in <code>parameterAnnotationMethods</code>
|
||||
*/
|
||||
private AnnotationDirectoryItem(DexFile dexFile, AnnotationSetItem classAnnotations,
|
||||
FieldIdItem[] fieldAnnotationFields, AnnotationSetItem[] fieldAnnotations,
|
||||
MethodIdItem[] methodAnnotationMethods, AnnotationSetItem[] methodAnnotations,
|
||||
MethodIdItem[] parameterAnnotationMethods,
|
||||
AnnotationSetRefList[] parameterAnnotations) {
|
||||
super(dexFile);
|
||||
this.classAnnotations = classAnnotations;
|
||||
this.fieldAnnotationFields = fieldAnnotationFields;
|
||||
this.fieldAnnotations = fieldAnnotations;
|
||||
this.methodAnnotationMethods = methodAnnotationMethods;
|
||||
this.methodAnnotations = methodAnnotations;
|
||||
this.parameterAnnotationMethods = parameterAnnotationMethods;
|
||||
this.parameterAnnotations = parameterAnnotations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an <code>AnnotationDirectoryItem</code> for the given values, and that has been interned into the given
|
||||
* <code>DexFile</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param classAnnotations The annotations associated with the class
|
||||
* @param fieldAnnotationFields An array of <code>FieldIdItem</code> objects that the annotations in
|
||||
* <code>fieldAnnotations</code> are associated with
|
||||
* @param fieldAnnotations An array of <code>AnnotationSetItem</code> objects that contain the annotations for the
|
||||
* fields in <code>fieldAnnotationFields</code>
|
||||
* @param methodAnnotationMethods An array of <code>MethodIdItem</code> objects that the annotations in
|
||||
* <code>methodAnnotations</code> are associated with
|
||||
* @param methodAnnotations An array of <code>AnnotationSetItem</code> objects that contain the annotations for the
|
||||
* methods in <code>methodAnnotationMethods</code>
|
||||
* @param parameterAnnotationMethods An array of <code>MethodIdItem</code> objects that the annotations in
|
||||
* <code>parameterAnnotations</code> are associated with
|
||||
* @param parameterAnnotations An array of <code>AnnotationSetRefList</code> objects that contain the parameter
|
||||
* annotations for the methods in <code>parameterAnnotationMethods</code>
|
||||
* @return an <code>AnnotationItem</code> for the given values, and that has been interned into the given
|
||||
* <code>DexFile</code>
|
||||
*/
|
||||
public static AnnotationDirectoryItem getInternedAnnotationDirectoryItem(DexFile dexFile,
|
||||
AnnotationSetItem classAnnotations,
|
||||
FieldIdItem[] fieldAnnotationFields, AnnotationSetItem[] fieldAnnotations,
|
||||
MethodIdItem[] methodAnnotationMethods, AnnotationSetItem[] methodAnnotations,
|
||||
MethodIdItem[] parameterAnnotationMethods,
|
||||
AnnotationSetRefList[] parameterAnnotations) {
|
||||
AnnotationDirectoryItem annotationDirectoryItem = new AnnotationDirectoryItem(dexFile, classAnnotations,
|
||||
fieldAnnotationFields, fieldAnnotations, methodAnnotationMethods, methodAnnotations,
|
||||
parameterAnnotationMethods, parameterAnnotations);
|
||||
return dexFile.AnnotationDirectoriesSection.intern(annotationDirectoryItem);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void readItem(Input in, ReadContext readContext) {
|
||||
readContext.getOffsettedItemByOffset(ItemType.TYPE_ANNOTATION_SET_ITEM, in.readInt());
|
||||
fieldAnnotationFields = new FieldIdItem[in.readInt()];
|
||||
fieldAnnotations = new AnnotationSetItem[fieldAnnotationFields.length];
|
||||
|
||||
methodAnnotationMethods = new MethodIdItem[in.readInt()];
|
||||
methodAnnotations = new AnnotationSetItem[methodAnnotationMethods.length];
|
||||
|
||||
parameterAnnotationMethods = new MethodIdItem[in.readInt()];
|
||||
parameterAnnotations = new AnnotationSetRefList[parameterAnnotationMethods.length];
|
||||
|
||||
for (int i=0; i<fieldAnnotations.length; i++) {
|
||||
fieldAnnotationFields[i] = dexFile.FieldIdsSection.getItemByIndex(in.readInt());
|
||||
fieldAnnotations[i] = (AnnotationSetItem)readContext.getOffsettedItemByOffset(
|
||||
ItemType.TYPE_ANNOTATION_SET_ITEM, in.readInt());
|
||||
}
|
||||
|
||||
for (int i=0; i<methodAnnotations.length; i++) {
|
||||
methodAnnotationMethods[i] = dexFile.MethodIdsSection.getItemByIndex(in.readInt());
|
||||
methodAnnotations[i] = (AnnotationSetItem)readContext.getOffsettedItemByOffset(
|
||||
ItemType.TYPE_ANNOTATION_SET_ITEM, in.readInt());
|
||||
}
|
||||
|
||||
for (int i=0; i<parameterAnnotations.length; i++) {
|
||||
parameterAnnotationMethods[i] = dexFile.MethodIdsSection.getItemByIndex(in.readInt());
|
||||
parameterAnnotations[i] = (AnnotationSetRefList)readContext.getOffsettedItemByOffset(
|
||||
ItemType.TYPE_ANNOTATION_SET_REF_LIST, in.readInt());
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int placeItem(int offset) {
|
||||
if (!dexFile.getInplace()) {
|
||||
ArrayUtils.sortTwoArrays(fieldAnnotationFields, fieldAnnotations);
|
||||
ArrayUtils.sortTwoArrays(methodAnnotationMethods, methodAnnotations);
|
||||
ArrayUtils.sortTwoArrays(parameterAnnotationMethods, parameterAnnotations);
|
||||
}
|
||||
|
||||
return offset + 16 + fieldAnnotations.length * 8 + methodAnnotations.length * 8 +
|
||||
parameterAnnotations.length * 8;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void writeItem(AnnotatedOutput out) {
|
||||
if (out.annotates()) {
|
||||
out.annotate(4, "class_annotations_off");
|
||||
out.annotate(4, "annotated_fields_size");
|
||||
out.annotate(4, "annotated_methods_size");
|
||||
out.annotate(4, "annotated_parameters_size");
|
||||
|
||||
|
||||
for (int i=0; i<fieldAnnotations.length; i++) {
|
||||
out.annotate(4, "field_idx");
|
||||
out.annotate(4, "annotations_off");
|
||||
}
|
||||
|
||||
for (int i=0; i<methodAnnotations.length; i++) {
|
||||
out.annotate(4, "method_idx");
|
||||
out.annotate(4, "annotations_off");
|
||||
}
|
||||
|
||||
for (int i=0; i<parameterAnnotations.length; i++) {
|
||||
out.annotate(4, "method_idx");
|
||||
out.annotate(4, "annotations_off");
|
||||
}
|
||||
}
|
||||
|
||||
out.writeInt(classAnnotations==null?0:classAnnotations.getOffset());
|
||||
|
||||
for (int i=0; i<fieldAnnotations.length; i++) {
|
||||
out.writeInt(fieldAnnotationFields[i].getIndex());
|
||||
out.writeInt(fieldAnnotations[i].getOffset());
|
||||
}
|
||||
|
||||
for (int i=0; i<methodAnnotations.length; i++) {
|
||||
out.writeInt(methodAnnotationMethods[i].getIndex());
|
||||
out.writeInt(methodAnnotations[i].getOffset());
|
||||
}
|
||||
|
||||
for (int i=0; i<parameterAnnotations.length; i++) {
|
||||
out.writeInt(parameterAnnotationMethods[i].getIndex());
|
||||
out.writeInt(parameterAnnotations[i].getOffset());
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */public ItemType getItemType() {
|
||||
return ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String getConciseIdentity() {
|
||||
return "annotation_directory_item @0x" + Integer.toHexString(getOffset());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int compareTo(AnnotationDirectoryItem o) {
|
||||
if (!isInternable()) {
|
||||
if (!o.isInternable()) {
|
||||
return parent.compareTo(o.parent);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!o.isInternable()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return classAnnotations.compareTo(o.classAnnotations);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The annotations associated with the class
|
||||
*/
|
||||
public AnnotationSetItem getClassAnnotations() {
|
||||
return classAnnotations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over the field annotations, calling delegate.processFieldAnnotations for each
|
||||
* @param delegate the delegate to call
|
||||
*/
|
||||
public void iterateFieldAnnotations(FieldAnnotationIteratorDelegate delegate) {
|
||||
for (int i=0; i<fieldAnnotationFields.length; i++) {
|
||||
delegate.processFieldAnnotations(fieldAnnotationFields[i], fieldAnnotations[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static interface FieldAnnotationIteratorDelegate {
|
||||
void processFieldAnnotations(FieldIdItem field, AnnotationSetItem fieldAnnotations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over the method annotations, calling delegate.processMethodAnnotations for each
|
||||
* @param delegate the delegate to call
|
||||
*/
|
||||
public void iterateMethodAnnotations(MethodAnnotationIteratorDelegate delegate) {
|
||||
for (int i=0; i<methodAnnotationMethods.length; i++) {
|
||||
delegate.processMethodAnnotations(methodAnnotationMethods[i], methodAnnotations[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static interface MethodAnnotationIteratorDelegate {
|
||||
void processMethodAnnotations(MethodIdItem method, AnnotationSetItem methodAnnotations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over the parameter annotations, calling delegate.processParameterAnnotations for each
|
||||
* @param delegate the delegate to call
|
||||
*/
|
||||
public void iteratParameterAnnotations(ParameterAnnotationIteratorDelegate delegate) {
|
||||
for (int i=0; i<parameterAnnotationMethods.length; i++) {
|
||||
delegate.processParameterAnnotations(parameterAnnotationMethods[i], parameterAnnotations[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static interface ParameterAnnotationIteratorDelegate {
|
||||
void processParameterAnnotations(MethodIdItem method, AnnotationSetRefList parameterAnnotations);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this <code>AnnotationDirectoryItem</code> is internable. It is only internable if it has
|
||||
* only class annotations, but no field, method or parameter annotations
|
||||
*/
|
||||
private boolean isInternable() {
|
||||
return classAnnotations != null &&
|
||||
fieldAnnotations.length == 0 &&
|
||||
methodAnnotations.length == 0 &&
|
||||
parameterAnnotations.length == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the <code>ClassDefItem</code> that this <code>AnnotationDirectoryItem</code> is associated with.
|
||||
* This is only applicable if this AnnotationDirectoryItem contains only class annotations, and no field, method
|
||||
* or parameter annotations.
|
||||
* @param classDefItem the <code>ClassDefItem</code> that this <code>AnnotationDirectoryItem</code> is associated
|
||||
* with
|
||||
*/
|
||||
protected void setParent(ClassDefItem classDefItem) {
|
||||
this.parent = classDefItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
//an instance is only internable if it has only class annotations, but
|
||||
//no other type of annotation
|
||||
if (!isInternable()) {
|
||||
return super.hashCode();
|
||||
}
|
||||
return classAnnotations.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this==o) {
|
||||
return true;
|
||||
}
|
||||
if (o==null || !this.getClass().equals(o.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AnnotationDirectoryItem other = (AnnotationDirectoryItem)o;
|
||||
return (this.compareTo(other) == 0);
|
||||
}
|
||||
}
|
163
dexlib/src/main/java/org/jf/dexlib/AnnotationItem.java
Normal file
163
dexlib/src/main/java/org/jf/dexlib/AnnotationItem.java
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.EncodedValue.AnnotationEncodedSubValue;
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
public class AnnotationItem extends Item<AnnotationItem> {
|
||||
private int hashCode = 0;
|
||||
|
||||
private AnnotationVisibility visibility;
|
||||
private AnnotationEncodedSubValue annotationValue;
|
||||
|
||||
/**
|
||||
* Creates a new uninitialized <code>AnnotationItem</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
*/
|
||||
protected AnnotationItem(DexFile dexFile) {
|
||||
super(dexFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>AnnotationItem</code> with the given values
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param visibility The visibility of this annotation
|
||||
* @param annotationValue The value of this annotation
|
||||
*/
|
||||
private AnnotationItem(DexFile dexFile, AnnotationVisibility visibility,
|
||||
AnnotationEncodedSubValue annotationValue) {
|
||||
super(dexFile);
|
||||
this.visibility = visibility;
|
||||
this.annotationValue = annotationValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an <code>AnnotationItem</code> for the given values, and that has been interned into the given
|
||||
* <code>DexFile</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param visibility The visibility of this annotation
|
||||
* @param annotationValue The value of this annotation
|
||||
* @return an <code>AnnotationItem</code> for the given values, and that has been interned into the given
|
||||
* <code>DexFile</code>
|
||||
*/
|
||||
public static AnnotationItem getInternedAnnotationItem(DexFile dexFile, AnnotationVisibility visibility,
|
||||
AnnotationEncodedSubValue annotationValue) {
|
||||
AnnotationItem annotationItem = new AnnotationItem(dexFile, visibility, annotationValue);
|
||||
return dexFile.AnnotationsSection.intern(annotationItem);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void readItem(Input in, ReadContext readContext) {
|
||||
visibility = AnnotationVisibility.fromByte(in.readByte());
|
||||
annotationValue = new AnnotationEncodedSubValue(dexFile, in);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int placeItem(int offset) {
|
||||
return annotationValue.placeValue(offset + 1);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void writeItem(AnnotatedOutput out) {
|
||||
if (out.annotates()) {
|
||||
out.annotate("visibility");
|
||||
out.writeByte(visibility.value);
|
||||
out.annotate("annotation");
|
||||
annotationValue.writeValue(out);
|
||||
}else {
|
||||
out.writeByte(visibility.value);
|
||||
annotationValue.writeValue(out);
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_ANNOTATION_ITEM;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String getConciseIdentity() {
|
||||
return "annotation_item @0x" + Integer.toHexString(getOffset());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int compareTo(AnnotationItem o) {
|
||||
int comp = visibility.value - o.visibility.value;
|
||||
if (comp == 0) {
|
||||
comp = annotationValue.compareTo(o.annotationValue);
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The visibility of this annotation
|
||||
*/
|
||||
public AnnotationVisibility getVisibility() {
|
||||
return visibility;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The encoded annotation value of this annotation
|
||||
*/
|
||||
public AnnotationEncodedSubValue getEncodedAnnotation() {
|
||||
return annotationValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate and cache the hashcode
|
||||
*/
|
||||
private void calcHashCode() {
|
||||
hashCode = visibility.value;
|
||||
hashCode = hashCode * 31 + annotationValue.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
//there's a small possibility that the actual hash code will be 0. If so, we'll
|
||||
//just end up recalculating it each time
|
||||
if (hashCode == 0)
|
||||
calcHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this==o) {
|
||||
return true;
|
||||
}
|
||||
if (o==null || !this.getClass().equals(o.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AnnotationItem other = (AnnotationItem)o;
|
||||
return visibility == other.visibility && annotationValue.equals(other.annotationValue);
|
||||
}
|
||||
}
|
164
dexlib/src/main/java/org/jf/dexlib/AnnotationSetItem.java
Normal file
164
dexlib/src/main/java/org/jf/dexlib/AnnotationSetItem.java
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
public class AnnotationSetItem extends Item<AnnotationSetItem> {
|
||||
private int hashCode = 0;
|
||||
|
||||
private AnnotationItem[] annotations;
|
||||
|
||||
/**
|
||||
* Creates a new uninitialized <code>AnnotationSetItem</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
*/
|
||||
protected AnnotationSetItem(DexFile dexFile) {
|
||||
super(dexFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>AnnotationSetItem</code> for the given annotations
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param annotations The annotations for this <code>AnnotationSetItem</code>
|
||||
*/
|
||||
private AnnotationSetItem(DexFile dexFile, AnnotationItem[] annotations) {
|
||||
super(dexFile);
|
||||
this.annotations = annotations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an <code>AnnotationSetItem</code> for the given annotations, and that has been interned into the given
|
||||
* <code>DexFile</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param annotations The annotations for this <code>AnnotationSetItem</code>
|
||||
* @return an <code>AnnotationSetItem</code> for the given annotations
|
||||
*/
|
||||
public static AnnotationSetItem getInternedAnnotationSetItem(DexFile dexFile, AnnotationItem[] annotations) {
|
||||
AnnotationSetItem annotationSetItem = new AnnotationSetItem(dexFile, annotations);
|
||||
return dexFile.AnnotationSetsSection.intern(annotationSetItem);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void readItem(Input in, ReadContext readContext) {
|
||||
annotations = new AnnotationItem[in.readInt()];
|
||||
|
||||
for (int i=0; i<annotations.length; i++) {
|
||||
annotations[i] = (AnnotationItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_ANNOTATION_ITEM,
|
||||
in.readInt());
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int placeItem(int offset) {
|
||||
return offset + 4 + annotations.length * 4;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void writeItem(AnnotatedOutput out) {
|
||||
if (out.annotates()) {
|
||||
out.annotate(4, "size");
|
||||
for (int i=0; i<annotations.length; i++) {
|
||||
out.annotate(4, "annotation_off");
|
||||
}
|
||||
}
|
||||
out.writeInt(annotations.length);
|
||||
for (AnnotationItem annotationItem: annotations) {
|
||||
out.writeInt(annotationItem.getOffset());
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_ANNOTATION_SET_ITEM;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String getConciseIdentity() {
|
||||
return "annotation_set_item @0x" + Integer.toHexString(getOffset());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int compareTo(AnnotationSetItem o) {
|
||||
if (o == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int comp = annotations.length - o.annotations.length;
|
||||
if (comp == 0) {
|
||||
for (int i=0; i<annotations.length; i++) {
|
||||
comp = annotations[i].compareTo(o.annotations[i]);
|
||||
if (comp != 0) {
|
||||
return comp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return An array of the <code>AnnotationItem</code> objects in this <code>AnnotationSetItem</code>
|
||||
*/
|
||||
public AnnotationItem[] getAnnotations() {
|
||||
return annotations;
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate and cache the hashcode
|
||||
*/
|
||||
private void calcHashCode() {
|
||||
hashCode = 0;
|
||||
for (AnnotationItem annotationItem: annotations) {
|
||||
hashCode = hashCode * 31 + annotationItem.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
//there's a small possibility that the actual hash code will be 0. If so, we'll
|
||||
//just end up recalculating it each time
|
||||
if (hashCode == 0)
|
||||
calcHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this==o) {
|
||||
return true;
|
||||
}
|
||||
if (o==null || !this.getClass().equals(o.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AnnotationSetItem other = (AnnotationSetItem)o;
|
||||
return (this.compareTo(other) == 0);
|
||||
}
|
||||
}
|
165
dexlib/src/main/java/org/jf/dexlib/AnnotationSetRefList.java
Normal file
165
dexlib/src/main/java/org/jf/dexlib/AnnotationSetRefList.java
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
public class AnnotationSetRefList extends Item<AnnotationSetRefList> {
|
||||
private int hashCode = 0;
|
||||
|
||||
private AnnotationSetItem[] annotationSets;
|
||||
|
||||
/**
|
||||
* Creates a new uninitialized <code>AnnotationSetRefList</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
*/
|
||||
protected AnnotationSetRefList(DexFile dexFile) {
|
||||
super(dexFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>AnnotationSetRefList</code> for the given annotation sets
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param annotationSets The annotationSets for this <code>AnnotationSetRefList</code>
|
||||
*/
|
||||
private AnnotationSetRefList(DexFile dexFile, AnnotationSetItem[] annotationSets) {
|
||||
super(dexFile);
|
||||
this.annotationSets = annotationSets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an <code>AnnotationSetRefList</code> for the given annotation sets, and that has been interned into the
|
||||
* given <code>DexFile</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param annotationSets The annotation sets for this <code>AnnotationSetRefList</code>
|
||||
* @return an <code>AnnotationSetItem</code> for the given annotations
|
||||
*/
|
||||
public static AnnotationSetRefList getInternedAnnotationSetRefList(DexFile dexFile,
|
||||
AnnotationSetItem[] annotationSets) {
|
||||
AnnotationSetRefList annotationSetRefList = new AnnotationSetRefList(dexFile, annotationSets);
|
||||
return dexFile.AnnotationSetRefListsSection.intern(annotationSetRefList);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void readItem(Input in, ReadContext readContext) {
|
||||
annotationSets = new AnnotationSetItem[in.readInt()];
|
||||
|
||||
for (int i=0; i<annotationSets.length; i++) {
|
||||
annotationSets[i] = (AnnotationSetItem)readContext.getOffsettedItemByOffset(
|
||||
ItemType.TYPE_ANNOTATION_SET_ITEM, in.readInt());
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int placeItem(int offset) {
|
||||
return offset + 4 + annotationSets.length * 4;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void writeItem(AnnotatedOutput out) {
|
||||
if (out.annotates()) {
|
||||
out.annotate(4, "size");
|
||||
for (AnnotationSetItem annotationSetItem: annotationSets) {
|
||||
out.annotate(4, "annotation_set_off");
|
||||
}
|
||||
}
|
||||
out.writeInt(annotationSets.length);
|
||||
for (AnnotationSetItem annotationSetItem: annotationSets) {
|
||||
out.writeInt(annotationSetItem.getOffset());
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_ANNOTATION_SET_REF_LIST;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String getConciseIdentity() {
|
||||
return "annotation_set_item @0x" + Integer.toHexString(getOffset());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int compareTo(AnnotationSetRefList o) {
|
||||
int comp = annotationSets.length - o.annotationSets.length;
|
||||
if (comp != 0) {
|
||||
return comp;
|
||||
}
|
||||
|
||||
for (int i=0; i<annotationSets.length; i++) {
|
||||
comp = annotationSets[i].compareTo(o.annotationSets[i]);
|
||||
if (comp != 0) {
|
||||
return comp;
|
||||
}
|
||||
}
|
||||
|
||||
return comp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return An array of the <code>AnnotationSetItem</code> objects that make up this
|
||||
* <code>AnnotationSetRefList</code>
|
||||
*/
|
||||
public AnnotationSetItem[] getAnnotationSets() {
|
||||
return annotationSets;
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate and cache the hashcode
|
||||
*/
|
||||
private void calcHashCode() {
|
||||
hashCode = 0;
|
||||
for (AnnotationSetItem annotationSetItem: annotationSets) {
|
||||
hashCode = hashCode * 31 + annotationSetItem.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
//there's a small possibility that the actual hash code will be 0. If so, we'll
|
||||
//just end up recalculating it each time
|
||||
if (hashCode == 0)
|
||||
calcHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this==o) {
|
||||
return true;
|
||||
}
|
||||
if (o==null || !this.getClass().equals(o.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AnnotationSetRefList other = (AnnotationSetRefList)o;
|
||||
return (this.compareTo(other) == 0);
|
||||
}
|
||||
}
|
53
dexlib/src/main/java/org/jf/dexlib/AnnotationVisibility.java
Normal file
53
dexlib/src/main/java/org/jf/dexlib/AnnotationVisibility.java
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
public enum AnnotationVisibility {
|
||||
BUILD((byte)0),
|
||||
RUNTIME((byte)1),
|
||||
SYSTEM((byte)2);
|
||||
|
||||
public final byte value;
|
||||
private AnnotationVisibility(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static AnnotationVisibility fromByte(byte value) {
|
||||
switch (value) {
|
||||
case (byte)0:
|
||||
return BUILD;
|
||||
case (byte)1:
|
||||
return RUNTIME;
|
||||
case (byte)2:
|
||||
return SYSTEM;
|
||||
default:
|
||||
throw new RuntimeException("Invalid annotation visibility value " + value);
|
||||
}
|
||||
}
|
||||
}
|
473
dexlib/src/main/java/org/jf/dexlib/ClassDataItem.java
Normal file
473
dexlib/src/main/java/org/jf/dexlib/ClassDataItem.java
Normal file
@ -0,0 +1,473 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.Util.*;
|
||||
|
||||
public class ClassDataItem extends Item<ClassDataItem> {
|
||||
private EncodedField[] staticFields;
|
||||
private EncodedField[] instanceFields;
|
||||
private EncodedMethod[] directMethods;
|
||||
private EncodedMethod[] virtualMethods;
|
||||
|
||||
private ClassDefItem parent = null;
|
||||
|
||||
/**
|
||||
* Creates a new uninitialized <code>ClassDataItem</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
*/
|
||||
public ClassDataItem(final DexFile dexFile) {
|
||||
super(dexFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>ClassDataItem</code> with the given values
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param staticFields The static fields for this class
|
||||
* @param instanceFields The instance fields for this class
|
||||
* @param directMethods The direct methods for this class
|
||||
* @param virtualMethods The virtual methods for this class
|
||||
*/
|
||||
private ClassDataItem(DexFile dexFile, EncodedField[] staticFields, EncodedField[] instanceFields,
|
||||
EncodedMethod[] directMethods, EncodedMethod[] virtualMethods) {
|
||||
super(dexFile);
|
||||
this.staticFields = staticFields==null?new EncodedField[0]:staticFields;
|
||||
this.instanceFields = instanceFields==null?new EncodedField[0]:instanceFields;
|
||||
this.directMethods = directMethods==null?new EncodedMethod[0]:directMethods;
|
||||
this.virtualMethods = virtualMethods==null?new EncodedMethod[0]:virtualMethods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>ClassDataItem</code> with the given values
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param staticFields The static fields for this class
|
||||
* @param instanceFields The instance fields for this class
|
||||
* @param directMethods The direct methods for this class
|
||||
* @param virtualMethods The virtual methods for this class
|
||||
* @return a new <code>ClassDataItem</code> with the given values
|
||||
*/
|
||||
public static ClassDataItem getInternedClassDataItem(DexFile dexFile, EncodedField[] staticFields,
|
||||
EncodedField[] instanceFields, EncodedMethod[] directMethods,
|
||||
EncodedMethod[] virtualMethods) {
|
||||
ClassDataItem classDataItem = new ClassDataItem(dexFile, staticFields, instanceFields, directMethods,
|
||||
virtualMethods);
|
||||
return dexFile.ClassDataSection.intern(classDataItem);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void readItem(Input in, ReadContext readContext) {
|
||||
staticFields = new EncodedField[in.readUnsignedLeb128()];
|
||||
instanceFields = new EncodedField[in.readUnsignedLeb128()];
|
||||
directMethods = new EncodedMethod[in.readUnsignedLeb128()];
|
||||
virtualMethods = new EncodedMethod[in.readUnsignedLeb128()];
|
||||
|
||||
EncodedField previousEncodedField = null;
|
||||
for (int i=0; i<staticFields.length; i++) {
|
||||
staticFields[i] = previousEncodedField = new EncodedField(dexFile, in, previousEncodedField);
|
||||
}
|
||||
|
||||
previousEncodedField = null;
|
||||
for (int i=0; i<instanceFields.length; i++) {
|
||||
instanceFields[i] = previousEncodedField = new EncodedField(dexFile, in, previousEncodedField);
|
||||
}
|
||||
|
||||
EncodedMethod previousEncodedMethod = null;
|
||||
for (int i=0; i<directMethods.length; i++) {
|
||||
directMethods[i] = previousEncodedMethod = new EncodedMethod(dexFile, readContext, in,
|
||||
previousEncodedMethod);
|
||||
}
|
||||
|
||||
previousEncodedMethod = null;
|
||||
for (int i=0; i<virtualMethods.length; i++) {
|
||||
virtualMethods[i] = previousEncodedMethod = new EncodedMethod(dexFile, readContext, in,
|
||||
previousEncodedMethod);
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int placeItem(int offset) {
|
||||
offset += Leb128Utils.unsignedLeb128Size(staticFields.length);
|
||||
offset += Leb128Utils.unsignedLeb128Size(instanceFields.length);
|
||||
offset += Leb128Utils.unsignedLeb128Size(directMethods.length);
|
||||
offset += Leb128Utils.unsignedLeb128Size(virtualMethods.length);
|
||||
|
||||
EncodedField previousEncodedField = null;
|
||||
for (EncodedField encodedField: staticFields) {
|
||||
offset += encodedField.place(offset, previousEncodedField);
|
||||
previousEncodedField = encodedField;
|
||||
}
|
||||
|
||||
previousEncodedField = null;
|
||||
for (EncodedField encodedField: instanceFields) {
|
||||
offset += encodedField.place(offset, previousEncodedField);
|
||||
previousEncodedField = encodedField;
|
||||
}
|
||||
|
||||
EncodedMethod previousEncodedMethod = null;
|
||||
for (EncodedMethod encodedMethod: directMethods) {
|
||||
offset += encodedMethod.place(offset, previousEncodedMethod);
|
||||
previousEncodedMethod = encodedMethod;
|
||||
}
|
||||
|
||||
previousEncodedMethod = null;
|
||||
for (EncodedMethod encodedMethod: virtualMethods) {
|
||||
offset += encodedMethod.place(offset, previousEncodedMethod);
|
||||
previousEncodedMethod = encodedMethod;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void writeItem(AnnotatedOutput out) {
|
||||
if (out.annotates()) {
|
||||
out.annotate("static_fields_size");
|
||||
out.writeUnsignedLeb128(staticFields.length);
|
||||
out.annotate("instance_fields_size");
|
||||
out.writeUnsignedLeb128(instanceFields.length);
|
||||
out.annotate("direct_methods_size");
|
||||
out.writeUnsignedLeb128(directMethods.length);
|
||||
out.annotate("virtual_methods_size");
|
||||
out.writeUnsignedLeb128(virtualMethods.length);
|
||||
|
||||
EncodedField previousEncodedField = null;
|
||||
for (EncodedField encodedField: staticFields) {
|
||||
encodedField.writeTo(out, previousEncodedField);
|
||||
previousEncodedField = encodedField;
|
||||
}
|
||||
|
||||
previousEncodedField = null;
|
||||
for (EncodedField encodedField: instanceFields) {
|
||||
encodedField.writeTo(out, previousEncodedField);
|
||||
previousEncodedField = encodedField;
|
||||
}
|
||||
|
||||
EncodedMethod previousEncodedMethod = null;
|
||||
for (EncodedMethod encodedMethod: directMethods) {
|
||||
encodedMethod.writeTo(out, previousEncodedMethod);
|
||||
previousEncodedMethod = encodedMethod;
|
||||
}
|
||||
|
||||
previousEncodedMethod = null;
|
||||
for (EncodedMethod encodedMethod: virtualMethods) {
|
||||
encodedMethod.writeTo(out, previousEncodedMethod);
|
||||
previousEncodedMethod = encodedMethod;
|
||||
}
|
||||
} else {
|
||||
out.writeUnsignedLeb128(staticFields.length);
|
||||
out.writeUnsignedLeb128(instanceFields.length);
|
||||
out.writeUnsignedLeb128(directMethods.length);
|
||||
out.writeUnsignedLeb128(virtualMethods.length);
|
||||
|
||||
EncodedField previousEncodedField = null;
|
||||
for (EncodedField encodedField: staticFields) {
|
||||
encodedField.writeTo(out, previousEncodedField);
|
||||
previousEncodedField = encodedField;
|
||||
}
|
||||
|
||||
previousEncodedField = null;
|
||||
for (EncodedField encodedField: instanceFields) {
|
||||
encodedField.writeTo(out, previousEncodedField);
|
||||
previousEncodedField = encodedField;
|
||||
}
|
||||
|
||||
EncodedMethod previousEncodedMethod = null;
|
||||
for (EncodedMethod encodedMethod: directMethods) {
|
||||
encodedMethod.writeTo(out, previousEncodedMethod);
|
||||
previousEncodedMethod = encodedMethod;
|
||||
}
|
||||
|
||||
previousEncodedMethod = null;
|
||||
for (EncodedMethod encodedMethod: virtualMethods) {
|
||||
encodedMethod.writeTo(out, previousEncodedMethod);
|
||||
previousEncodedMethod = encodedMethod;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_CLASS_DATA_ITEM;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String getConciseIdentity() {
|
||||
return "class_data_item @0x" + Integer.toHexString(getOffset());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int compareTo(ClassDataItem other) {
|
||||
if (parent == null) {
|
||||
if (other.parent == null) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (other.parent == null) {
|
||||
return 1;
|
||||
}
|
||||
return parent.compareTo(other.parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the <code>ClassDefItem</code> that this <code>ClassDataItem</code> is associated with
|
||||
* @param classDefItem the <code>ClassDefItem</code> that this <code>ClassDataItem</code> is associated with
|
||||
*/
|
||||
protected void setParent(ClassDefItem classDefItem) {
|
||||
this.parent = classDefItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the static fields for this class
|
||||
*/
|
||||
public EncodedField[] getStaticFields() {
|
||||
return staticFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the instance fields for this class
|
||||
*/
|
||||
public EncodedField[] getInstanceFields() {
|
||||
return instanceFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the direct methods for this class
|
||||
*/
|
||||
public EncodedMethod[] getDirectMethods() {
|
||||
return directMethods;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the virtual methods for this class
|
||||
*/
|
||||
public EncodedMethod[] getVirtualMethods() {
|
||||
return virtualMethods;
|
||||
}
|
||||
|
||||
public static class EncodedField {
|
||||
/**
|
||||
* The <code>FieldIdItem</code> that this <code>EncodedField</code> is associated with
|
||||
*/
|
||||
public final FieldIdItem field;
|
||||
|
||||
/**
|
||||
* The access flags for this field
|
||||
*/
|
||||
public final int accessFlags;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>EncodedField</code> with the given values
|
||||
* @param field The <code>FieldIdItem</code> that this <code>EncodedField</code> is associated with
|
||||
* @param accessFlags The access flags for this field
|
||||
*/
|
||||
public EncodedField(FieldIdItem field, int accessFlags) {
|
||||
this.field = field;
|
||||
this.accessFlags = accessFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used internally to construct a new <code>EncodedField</code> while reading in a <code>DexFile</code>
|
||||
* @param dexFile The <code>DexFile</code> that is being read in
|
||||
* @param in the Input object to read the <code>EncodedField</code> from
|
||||
* @param previousEncodedField The previous <code>EncodedField</code> in the list containing this
|
||||
* <code>EncodedField</code>.
|
||||
*/
|
||||
private EncodedField(DexFile dexFile, Input in, EncodedField previousEncodedField) {
|
||||
int previousIndex = previousEncodedField==null?0:previousEncodedField.field.getIndex();
|
||||
field = dexFile.FieldIdsSection.getItemByIndex(in.readUnsignedLeb128() + previousIndex);
|
||||
accessFlags = in.readUnsignedLeb128();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the <code>EncodedField</code> to the given <code>AnnotatedOutput</code> object
|
||||
* @param out the <code>AnnotatedOutput</code> object to write to
|
||||
* @param previousEncodedField The previous <code>EncodedField</code> in the list containing this
|
||||
* <code>EncodedField</code>.
|
||||
*/
|
||||
private void writeTo(AnnotatedOutput out, EncodedField previousEncodedField) {
|
||||
int previousIndex = previousEncodedField==null?0:previousEncodedField.field.getIndex();
|
||||
|
||||
if (out.annotates()) {
|
||||
out.annotate("field_idx_diff");
|
||||
out.writeUnsignedLeb128(field.getIndex() - previousIndex);
|
||||
out.annotate("access_flags");
|
||||
out.writeUnsignedLeb128(accessFlags);
|
||||
}else {
|
||||
out.writeUnsignedLeb128(field.getIndex() - previousIndex);
|
||||
out.writeUnsignedLeb128(accessFlags);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the size of this <code>EncodedField</code> and returns the offset
|
||||
* immediately following it
|
||||
* @param offset the offset of this <code>EncodedField</code> in the <code>DexFile</code>
|
||||
* @param previousEncodedField The previous <code>EncodedField</code> in the list containing this
|
||||
* <code>EncodedField</code>.
|
||||
* @return the offset immediately following this <code>EncodedField</code>
|
||||
*/
|
||||
private int place(int offset, EncodedField previousEncodedField) {
|
||||
int previousIndex = previousEncodedField==null?0:previousEncodedField.field.getIndex();
|
||||
|
||||
offset += Leb128Utils.unsignedLeb128Size(field.getIndex() - previousIndex);
|
||||
offset += Leb128Utils.unsignedLeb128Size(accessFlags);
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this <code>EncodedField</code> to another, based on the comparison of the associated
|
||||
* <code>FieldIdItem</code>
|
||||
* @param other The <code>EncodedField</code> to compare against
|
||||
* @return a standard integer comparison value indicating the relationship
|
||||
*/
|
||||
public int compareTo(EncodedField other)
|
||||
{
|
||||
return field.compareTo(other.field);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this is a static field
|
||||
*/
|
||||
public boolean isStatic() {
|
||||
return (accessFlags & AccessFlags.STATIC.getValue()) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static class EncodedMethod {
|
||||
/**
|
||||
* The <code>MethodIdItem</code> that this <code>EncodedMethod</code> is associated with
|
||||
*/
|
||||
public final MethodIdItem method;
|
||||
|
||||
/**
|
||||
* The access flags for this method
|
||||
*/
|
||||
public final int accessFlags;
|
||||
|
||||
/**
|
||||
* The <code>CodeItem</code> containing the code for this method, or null if there is no code for this method
|
||||
* (i.e. an abstract method)
|
||||
*/
|
||||
public final CodeItem codeItem;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>EncodedMethod</code> with the given values
|
||||
* @param method The <code>MethodIdItem</code> that this <code>EncodedMethod</code> is associated with
|
||||
* @param accessFlags The access flags for this method
|
||||
* @param codeItem The <code>CodeItem</code> containing the code for this method, or null if there is no code
|
||||
* for this method (i.e. an abstract method)
|
||||
*/
|
||||
public EncodedMethod(MethodIdItem method, int accessFlags, CodeItem codeItem) {
|
||||
this.method = method;
|
||||
this.accessFlags = accessFlags;
|
||||
this.codeItem = codeItem;
|
||||
if (codeItem != null) {
|
||||
codeItem.setParent(method);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used internally to construct a new <code>EncodedMethod</code> while reading in a <code>DexFile</code>
|
||||
* @param dexFile The <code>DexFile</code> that is being read in
|
||||
* @param readContext a <code>ReadContext</code> object to hold information that is only needed while reading
|
||||
* in a file
|
||||
* @param in the Input object to read the <code>EncodedMethod</code> from
|
||||
* @param previousEncodedMethod The previous <code>EncodedMethod</code> in the list containing this
|
||||
* <code>EncodedMethod</code>.
|
||||
*/
|
||||
public EncodedMethod(DexFile dexFile, ReadContext readContext, Input in, EncodedMethod previousEncodedMethod) {
|
||||
int previousIndex = previousEncodedMethod==null?0:previousEncodedMethod.method.getIndex();
|
||||
method = dexFile.MethodIdsSection.getItemByIndex(in.readUnsignedLeb128() + previousIndex);
|
||||
accessFlags = in.readUnsignedLeb128();
|
||||
codeItem = (CodeItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_CODE_ITEM, in.readUnsignedLeb128());
|
||||
if (codeItem != null) {
|
||||
codeItem.setParent(method);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the <code>EncodedMethod</code> to the given <code>AnnotatedOutput</code> object
|
||||
* @param out the <code>AnnotatedOutput</code> object to write to
|
||||
* @param previousEncodedMethod The previous <code>EncodedMethod</code> in the list containing this
|
||||
* <code>EncodedMethod</code>.
|
||||
*/
|
||||
private void writeTo(AnnotatedOutput out, EncodedMethod previousEncodedMethod) {
|
||||
int previousIndex = previousEncodedMethod==null?0:previousEncodedMethod.method.getIndex();
|
||||
|
||||
if (out.annotates()) {
|
||||
out.annotate("method_idx_diff");
|
||||
out.writeUnsignedLeb128(method.getIndex() - previousIndex);
|
||||
out.annotate("access_flags");
|
||||
out.writeUnsignedLeb128(accessFlags);
|
||||
out.annotate("code_off");
|
||||
out.writeUnsignedLeb128(codeItem==null?0:codeItem.getIndex());
|
||||
}else {
|
||||
out.writeUnsignedLeb128(method.getIndex() - previousIndex);
|
||||
out.writeUnsignedLeb128(accessFlags);
|
||||
out.writeUnsignedLeb128(codeItem==null?0:codeItem.getIndex());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the size of this <code>EncodedMethod</code> and returns the offset
|
||||
* immediately following it
|
||||
* @param offset the offset of this <code>EncodedMethod</code> in the <code>DexFile</code>
|
||||
* @param previousEncodedMethod The previous <code>EncodedMethod</code> in the list containing this
|
||||
* <code>EncodedMethod</code>.
|
||||
* @return the offset immediately following this <code>EncodedField</code>
|
||||
*/
|
||||
private int place(int offset, EncodedMethod previousEncodedMethod) {
|
||||
int previousIndex = previousEncodedMethod==null?0:previousEncodedMethod.method.getIndex();
|
||||
|
||||
offset += Leb128Utils.unsignedLeb128Size(method.getIndex() - previousIndex);
|
||||
offset += Leb128Utils.unsignedLeb128Size(accessFlags);
|
||||
offset += codeItem==null?1:Leb128Utils.unsignedLeb128Size(codeItem.getIndex());
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this <code>EncodedMethod</code> to another, based on the comparison of the associated
|
||||
* <code>MethodIdItem</code>
|
||||
* @param other The <code>EncodedMethod</code> to compare against
|
||||
* @return a standard integer comparison value indicating the relationship
|
||||
*/
|
||||
public int compareTo(EncodedMethod other) {
|
||||
return method.compareTo(other.method);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this is a direct method
|
||||
*/
|
||||
public boolean isDirect() {
|
||||
return ((accessFlags & (AccessFlags.STATIC.getValue() | AccessFlags.PRIVATE.getValue() |
|
||||
AccessFlags.CONSTRUCTOR.getValue())) != 0);
|
||||
}
|
||||
}
|
||||
}
|
286
dexlib/src/main/java/org/jf/dexlib/ClassDefItem.java
Normal file
286
dexlib/src/main/java/org/jf/dexlib/ClassDefItem.java
Normal file
@ -0,0 +1,286 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class ClassDefItem extends Item<ClassDefItem> {
|
||||
private TypeIdItem classType;
|
||||
private int accessFlags;
|
||||
private TypeIdItem superType;
|
||||
private TypeListItem implementedInterfaces;
|
||||
private StringIdItem sourceFile;
|
||||
private AnnotationDirectoryItem annotations;
|
||||
private ClassDataItem classData;
|
||||
private EncodedArrayItem staticFieldInitializers;
|
||||
|
||||
/**
|
||||
* Creates a new uninitialized <code>ClassDefItem</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
*/
|
||||
protected ClassDefItem(DexFile dexFile) {
|
||||
super(dexFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>ClassDefItem</code> with the given values
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param classType The type of this class
|
||||
* @param accessFlags The access flags of this class
|
||||
* @param superType The superclass of this class, or null if none (only valid for java.lang.Object)
|
||||
* @param implementedInterfaces A list of the interfaces that this class implements, or null if none
|
||||
* @param sourceFile The main source file that this class is defined in, or null if not available
|
||||
* @param annotations The annotations for this class and its fields, methods and method parameters, or null if none
|
||||
* @param classData The <code>ClassDataItem</code> containing the method and field definitions for this class
|
||||
* @param staticFieldInitializers The initial values for this class's static fields, or null if none
|
||||
*/
|
||||
private ClassDefItem(DexFile dexFile, TypeIdItem classType, int accessFlags, TypeIdItem superType,
|
||||
TypeListItem implementedInterfaces, StringIdItem sourceFile,
|
||||
AnnotationDirectoryItem annotations, ClassDataItem classData,
|
||||
EncodedArrayItem staticFieldInitializers) {
|
||||
super(dexFile);
|
||||
this.classType = classType;
|
||||
this.accessFlags = accessFlags;
|
||||
this.superType = superType;
|
||||
this.implementedInterfaces = implementedInterfaces;
|
||||
this.sourceFile = sourceFile;
|
||||
this.annotations = annotations;
|
||||
this.classData = classData;
|
||||
this.staticFieldInitializers = staticFieldInitializers;
|
||||
|
||||
if (classData != null) {
|
||||
classData.setParent(this);
|
||||
}
|
||||
if (annotations != null) {
|
||||
annotations.setParent(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <code>ClassDefItem</code> for the given values, and that has been interned into the given
|
||||
* <code>DexFile</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param classType The type of this class
|
||||
* @param accessFlags The access flags of this class
|
||||
* @param superType The superclass of this class, or null if none (only valid for java.lang.Object)
|
||||
* @param implementedInterfaces A list of the interfaces that this class implements, or null if none
|
||||
* @param sourceFile The main source file that this class is defined in, or null if not available
|
||||
* @param annotations The annotations for this class and its fields, methods and method parameters, or null if none
|
||||
* @param classData The <code>ClassDataItem</code> containing the method and field definitions for this class
|
||||
* @param staticFieldInitializers The initial values for this class's static fields, or null if none
|
||||
* @return a <code>ClassDefItem</code> for the given values, and that has been interned into the given
|
||||
* <code>DexFile</code>
|
||||
*/
|
||||
public static ClassDefItem getInternedClassDefItem(DexFile dexFile, TypeIdItem classType, int accessFlags,
|
||||
TypeIdItem superType, TypeListItem implementedInterfaces, StringIdItem sourceFile,
|
||||
AnnotationDirectoryItem annotations, ClassDataItem classData,
|
||||
EncodedArrayItem staticFieldInitializers) {
|
||||
ClassDefItem classDefItem = new ClassDefItem(dexFile, classType, accessFlags, superType, implementedInterfaces,
|
||||
sourceFile, annotations, classData, staticFieldInitializers);
|
||||
return dexFile.ClassDefsSection.intern(classDefItem);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void readItem(Input in, ReadContext readContext) {
|
||||
classType = dexFile.TypeIdsSection.getItemByIndex(in.readInt());
|
||||
accessFlags = in.readInt();
|
||||
superType = dexFile.TypeIdsSection.getItemByIndex(in.readInt());
|
||||
implementedInterfaces = (TypeListItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_TYPE_LIST,
|
||||
in.readInt());
|
||||
sourceFile = dexFile.StringIdsSection.getItemByIndex(in.readInt());
|
||||
annotations = (AnnotationDirectoryItem)readContext.getOffsettedItemByOffset(
|
||||
ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM, in.readInt());
|
||||
classData = (ClassDataItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_CLASS_DATA_ITEM, in.readInt());
|
||||
staticFieldInitializers = (EncodedArrayItem)readContext.getOffsettedItemByOffset(
|
||||
ItemType.TYPE_ENCODED_ARRAY_ITEM, in.readInt());
|
||||
|
||||
if (classData != null) {
|
||||
classData.setParent(this);
|
||||
}
|
||||
if (annotations != null) {
|
||||
annotations.setParent(this);
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int placeItem(int offset) {
|
||||
return offset + 32;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void writeItem(AnnotatedOutput out) {
|
||||
if (out.annotates()) {
|
||||
out.annotate(4, "class_idx");
|
||||
out.annotate(4, "access_flags");
|
||||
out.annotate(4, "superclass_idx");
|
||||
out.annotate(4, "interfaces_off");
|
||||
out.annotate(4, "source_file_idx");
|
||||
out.annotate(4, "annotations_off");
|
||||
out.annotate(4, "class_data_off");
|
||||
out.annotate(4, "static_values_off");
|
||||
}
|
||||
out.writeInt(classType.getIndex());
|
||||
out.writeInt(accessFlags);
|
||||
out.writeInt(superType==null?-1:superType.getIndex());
|
||||
out.writeInt(implementedInterfaces==null?0:implementedInterfaces.getOffset());
|
||||
out.writeInt(sourceFile==null?-1:sourceFile.getIndex());
|
||||
out.writeInt(annotations==null?0:annotations.getOffset());
|
||||
out.writeInt(classData==null?0:classData.getOffset());
|
||||
out.writeInt(staticFieldInitializers==null?0:staticFieldInitializers.getOffset());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_CLASS_DEF_ITEM;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String getConciseIdentity() {
|
||||
return "class_def_item: " + classType.getTypeDescriptor();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int compareTo(ClassDefItem o) {
|
||||
//The actual sorting for this class is implemented in SortClassDefItemSection.
|
||||
//This method is just used for sorting the associated ClassDataItem items, so
|
||||
//we can just do the comparison based on the offsets of the items
|
||||
return this.getOffset() - o.getOffset();
|
||||
}
|
||||
|
||||
public TypeIdItem getClassType() {
|
||||
return classType;
|
||||
}
|
||||
|
||||
public int getAccessFlags() {
|
||||
return accessFlags;
|
||||
}
|
||||
|
||||
public TypeIdItem getSuperclass() {
|
||||
return superType;
|
||||
}
|
||||
|
||||
public TypeListItem getInterfaces() {
|
||||
return implementedInterfaces;
|
||||
}
|
||||
|
||||
public StringIdItem getSourceFile() {
|
||||
return sourceFile;
|
||||
}
|
||||
|
||||
public AnnotationDirectoryItem getAnnotations() {
|
||||
return annotations;
|
||||
}
|
||||
|
||||
public ClassDataItem getClassData() {
|
||||
return classData;
|
||||
}
|
||||
|
||||
public EncodedArrayItem getStaticFieldInitializers() {
|
||||
return staticFieldInitializers;
|
||||
}
|
||||
|
||||
public static int placeClassDefItems(IndexedSection<ClassDefItem> section, int offset) {
|
||||
ClassDefPlacer cdp = new ClassDefPlacer(section);
|
||||
return cdp.placeSection(offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* This class places the items within a ClassDefItem section, such that superclasses and interfaces are
|
||||
* placed before sub/implementing classes
|
||||
*/
|
||||
private static class ClassDefPlacer {
|
||||
private final IndexedSection<ClassDefItem> section;
|
||||
private final HashMap<TypeIdItem, ClassDefItem> unplacedClassDefsByType =
|
||||
new HashMap<TypeIdItem, ClassDefItem>();
|
||||
|
||||
private int currentIndex = 0;
|
||||
private int currentOffset;
|
||||
|
||||
public ClassDefPlacer(IndexedSection<ClassDefItem> section) {
|
||||
this.section = section;
|
||||
|
||||
for (ClassDefItem classDefItem: section.items) {
|
||||
TypeIdItem typeIdItem = classDefItem.classType;
|
||||
unplacedClassDefsByType.put(typeIdItem, classDefItem);
|
||||
}
|
||||
}
|
||||
|
||||
public int placeSection(int offset) {
|
||||
currentOffset = offset;
|
||||
|
||||
if (section.DexFile.getSortAllItems()) {
|
||||
//presort the list, to guarantee a unique ordering
|
||||
Collections.sort(section.items, new Comparator<ClassDefItem>() {
|
||||
public int compare(ClassDefItem a, ClassDefItem b) {
|
||||
return a.getClassType().compareTo(b.getClassType());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (ClassDefItem classDefItem: section.items) {
|
||||
placeClass(classDefItem);
|
||||
}
|
||||
|
||||
for (ClassDefItem classDefItem: unplacedClassDefsByType.values()) {
|
||||
section.items.set(classDefItem.getIndex(), classDefItem);
|
||||
}
|
||||
|
||||
return currentOffset;
|
||||
}
|
||||
|
||||
private void placeClass(ClassDefItem classDefItem) {
|
||||
if (classDefItem.getOffset() == -1) {
|
||||
TypeIdItem superType = classDefItem.superType;
|
||||
ClassDefItem superClassDefItem = unplacedClassDefsByType.get(superType);
|
||||
|
||||
if (superClassDefItem != null) {
|
||||
placeClass(superClassDefItem);
|
||||
}
|
||||
|
||||
TypeListItem interfaces = classDefItem.implementedInterfaces;
|
||||
|
||||
if (interfaces != null) {
|
||||
for (TypeIdItem interfaceType: interfaces.getTypes()) {
|
||||
ClassDefItem interfaceClass = unplacedClassDefsByType.get(interfaceType);
|
||||
if (interfaceClass != null) {
|
||||
placeClass(interfaceClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentOffset = classDefItem.placeAt(currentIndex++, currentOffset);
|
||||
unplacedClassDefsByType.remove(classDefItem.classType);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
import org.jf.dexlib.DexFile;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
public class ArrayDataPseudoInstruction extends Instruction {
|
||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
int size = getElementWidth() * getElementCount();
|
||||
return size + (size & 0x01) + 8;
|
||||
}
|
||||
|
||||
public ArrayDataPseudoInstruction(int elementWidth, byte[] encodedValues) {
|
||||
super(Opcode.NOP, encodedValues.length + (encodedValues.length & 1) + 8);
|
||||
|
||||
if (encodedValues.length % elementWidth != 0) {
|
||||
throw new RuntimeException("There are not a whole number of " + elementWidth + " byte elements");
|
||||
}
|
||||
|
||||
int elementCount = buffer.length / elementWidth;
|
||||
|
||||
buffer[0] = 0x00;
|
||||
buffer[1] = 0x03; //fill-array-data psuedo-opcode
|
||||
|
||||
buffer[2] = (byte) elementWidth;
|
||||
buffer[3] = (byte) (elementWidth >> 8);
|
||||
|
||||
buffer[4] = (byte) elementCount;
|
||||
buffer[5] = (byte) (elementCount >> 8);
|
||||
buffer[6] = (byte) (elementCount >> 16);
|
||||
buffer[7] = (byte) (elementCount >> 24);
|
||||
|
||||
System.arraycopy(encodedValues, 0, buffer, 8, encodedValues.length);
|
||||
}
|
||||
|
||||
public ArrayDataPseudoInstruction(byte[] buffer, int bufferIndex) {
|
||||
super(Opcode.NOP, buffer, bufferIndex);
|
||||
|
||||
byte opcodeByte = buffer[bufferIndex++];
|
||||
if (opcodeByte != 0x00) {
|
||||
throw new RuntimeException("Invalid opcode byte for an ArrayData pseudo-instruction");
|
||||
}
|
||||
|
||||
byte subopcodeByte = buffer[bufferIndex];
|
||||
if (subopcodeByte != 0x03) {
|
||||
throw new RuntimeException("Invalid sub-opcode byte for an ArrayData pseudo-instruction");
|
||||
}
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.ArrayData;
|
||||
}
|
||||
|
||||
public int getElementWidth() {
|
||||
return NumberUtils.decodeUnsignedShort(buffer[bufferIndex+2], buffer[bufferIndex+3]);
|
||||
}
|
||||
|
||||
public int getElementCount() {
|
||||
return NumberUtils.decodeInt(buffer, bufferIndex+4);
|
||||
}
|
||||
|
||||
public static class ArrayElement {
|
||||
public final byte[] buffer;
|
||||
public int bufferIndex;
|
||||
public final int elementWidth;
|
||||
public ArrayElement(byte[] buffer, int elementWidth) {
|
||||
this.buffer = buffer;
|
||||
this.elementWidth = elementWidth;
|
||||
}
|
||||
}
|
||||
|
||||
public Iterator<ArrayElement> getElements() {
|
||||
return new Iterator<ArrayElement>() {
|
||||
final int elementCount = getElementCount();
|
||||
int i=0;
|
||||
int position = bufferIndex + 8;
|
||||
final ArrayElement arrayElement = new ArrayElement(buffer, getElementWidth());
|
||||
|
||||
public boolean hasNext() {
|
||||
return i<elementCount;
|
||||
}
|
||||
|
||||
public ArrayElement next() {
|
||||
arrayElement.bufferIndex = position;
|
||||
position += arrayElement.elementWidth;
|
||||
i++;
|
||||
return arrayElement;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
if (opcode != Opcode.NOP) {
|
||||
throw new RuntimeException("The opcode for an ArrayDataPseudoInstruction must by NOP");
|
||||
}
|
||||
return new ArrayDataPseudoInstruction(buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
75
dexlib/src/main/java/org/jf/dexlib/Code/Format/Format.java
Normal file
75
dexlib/src/main/java/org/jf/dexlib/Code/Format/Format.java
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
|
||||
public enum Format {
|
||||
Format10t(Instruction10t.Factory, 2),
|
||||
Format10x(Instruction10x.Factory, 2),
|
||||
Format11n(Instruction11n.Factory, 2),
|
||||
Format11x(Instruction11x.Factory, 2),
|
||||
Format12x(Instruction12x.Factory, 2),
|
||||
Format20t(Instruction20t.Factory, 4),
|
||||
Format21c(Instruction21c.Factory, 4),
|
||||
Format21h(Instruction21h.Factory, 4),
|
||||
Format21s(Instruction21s.Factory, 4),
|
||||
Format21t(Instruction21t.Factory, 4),
|
||||
Format22b(Instruction22b.Factory, 4),
|
||||
Format22c(Instruction22c.Factory, 4),
|
||||
Format22s(Instruction22s.Factory, 4),
|
||||
Format22t(Instruction22t.Factory, 4),
|
||||
Format22x(Instruction22x.Factory, 4),
|
||||
Format23x(Instruction23x.Factory, 4),
|
||||
Format30t(Instruction30t.Factory, 6),
|
||||
Format31c(Instruction31c.Factory, 6),
|
||||
Format31i(Instruction31i.Factory, 6),
|
||||
Format31t(Instruction31t.Factory, 6),
|
||||
Format32x(Instruction32x.Factory, 6),
|
||||
Format35c(Instruction35c.Factory, 6),
|
||||
Format3rc(Instruction3rc.Factory, 6),
|
||||
Format51l(Instruction51l.Factory, 10),
|
||||
ArrayData(null, -1, true),
|
||||
PackedSwitchData(null, -1, true),
|
||||
SparseSwitchData(null, -1, true);
|
||||
|
||||
public final Instruction.InstructionFactory Factory;
|
||||
public final int size;
|
||||
public final boolean variableSizeFormat;
|
||||
|
||||
private Format(Instruction.InstructionFactory factory, int size) {
|
||||
this(factory, size, false);
|
||||
}
|
||||
|
||||
private Format(Instruction.InstructionFactory factory, int size, boolean variableSizeFormat) {
|
||||
this.Factory = factory;
|
||||
this.size = size;
|
||||
this.variableSizeFormat = variableSizeFormat;
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.DexFile;
|
||||
|
||||
public class Instruction10t extends Instruction {
|
||||
public static final InstructionFactory Factory = new Factory();
|
||||
|
||||
public Instruction10t(Opcode opcode, byte offA) {
|
||||
super(opcode);
|
||||
|
||||
if (offA == 0) {
|
||||
throw new RuntimeException("The offset cannot be 0. Use goto/32 instead.");
|
||||
}
|
||||
|
||||
buffer[0] = opcode.value;
|
||||
buffer[1] = offA;
|
||||
}
|
||||
|
||||
private Instruction10t(Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(opcode, buffer, bufferIndex);
|
||||
|
||||
if (getOffset() == 0) {
|
||||
throw new RuntimeException("The offset cannot be 0. Use goto/32 instead.");
|
||||
}
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.Format10t;
|
||||
}
|
||||
|
||||
public byte getOffset() {
|
||||
return buffer[bufferIndex + 1];
|
||||
}
|
||||
|
||||
private static class Factory implements InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
return new Instruction10t(opcode, buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.DexFile;
|
||||
|
||||
public class Instruction10x extends Instruction {
|
||||
public static final InstructionFactory Factory = new Factory();
|
||||
|
||||
public Instruction10x(Opcode opcode) {
|
||||
super(opcode);
|
||||
|
||||
buffer[0] = opcode.value;
|
||||
}
|
||||
|
||||
public Instruction10x(Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(opcode, buffer, bufferIndex);
|
||||
|
||||
if (buffer[bufferIndex + 1] != 0x00) {
|
||||
throw new RuntimeException("The second byte of the instruction must be 0");
|
||||
}
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.Format10x;
|
||||
}
|
||||
|
||||
private static class Factory implements InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
return new Instruction10x(opcode, buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
|
||||
public class Instruction11n extends Instruction {
|
||||
public static final InstructionFactory Factory = new Factory();
|
||||
|
||||
public Instruction11n(Opcode opcode, byte regA, byte litB) {
|
||||
super(opcode);
|
||||
|
||||
if (regA >= 1 << 4) {
|
||||
throw new RuntimeException("The register number must be less than v16");
|
||||
}
|
||||
|
||||
if (litB < -(1 << 3) ||
|
||||
litB >= 1 << 3) {
|
||||
throw new RuntimeException("The literal value must be between -8 and 7 inclusive");
|
||||
}
|
||||
|
||||
buffer[0] = opcode.value;
|
||||
buffer[1] = (byte) ((litB << 4) | regA);
|
||||
}
|
||||
|
||||
private Instruction11n(Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(opcode, buffer, bufferIndex);
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.Format11n;
|
||||
}
|
||||
|
||||
public byte getRegister() {
|
||||
return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
public byte getLiteral() {
|
||||
return NumberUtils.decodeHighSignedNibble(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
return new Instruction11n(opcode, buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
|
||||
public class Instruction11x extends Instruction {
|
||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||
|
||||
public Instruction11x(Opcode opcode, short regA) {
|
||||
super(opcode);
|
||||
|
||||
if (regA >= 1 << 8) {
|
||||
throw new RuntimeException("The register number must be less than v256");
|
||||
}
|
||||
|
||||
buffer[0] = opcode.value;
|
||||
buffer[1] = (byte) regA;
|
||||
}
|
||||
|
||||
private Instruction11x(Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(opcode, buffer, bufferIndex);
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.Format11x;
|
||||
}
|
||||
|
||||
public short getRegister() {
|
||||
return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
return new Instruction11x(opcode, buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
|
||||
public class Instruction12x extends Instruction {
|
||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||
|
||||
public Instruction12x(Opcode opcode, byte regA, byte regB) {
|
||||
super(opcode);
|
||||
|
||||
if (regA >= 1 << 4 ||
|
||||
regB >= 1 << 4) {
|
||||
throw new RuntimeException("The register number must be less than v16");
|
||||
}
|
||||
|
||||
buffer[0] = opcode.value;
|
||||
buffer[1] = (byte) ((regB << 4) | regA);
|
||||
}
|
||||
|
||||
private Instruction12x(Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(opcode, buffer, bufferIndex);
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.Format12x;
|
||||
}
|
||||
|
||||
public byte getRegisterA() {
|
||||
return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
public byte getRegisterB() {
|
||||
return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
return new Instruction12x(opcode, buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
|
||||
public class Instruction20t extends Instruction {
|
||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||
|
||||
public Instruction20t(Opcode opcode, short offA) {
|
||||
super(opcode);
|
||||
|
||||
if (offA == 0) {
|
||||
throw new RuntimeException("The offset cannot be 0. Use goto/32 instead.");
|
||||
}
|
||||
|
||||
buffer[0] = opcode.value;
|
||||
buffer[2] = (byte) offA;
|
||||
buffer[3] = (byte) (offA >> 8);
|
||||
}
|
||||
|
||||
private Instruction20t(Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(opcode, buffer, bufferIndex);
|
||||
|
||||
if (getOffset() == 0) {
|
||||
throw new RuntimeException("The offset cannot be 0. Use goto/32 instead.");
|
||||
}
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.Format20t;
|
||||
}
|
||||
|
||||
public short getOffset() {
|
||||
return NumberUtils.decodeShort(buffer, bufferIndex + 2);
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
return new Instruction20t(opcode, buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.InstructionWithReference;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Item;
|
||||
import org.jf.dexlib.TypeIdItem;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
|
||||
public class Instruction21c extends InstructionWithReference {
|
||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||
|
||||
public Instruction21c(Opcode opcode, short regA, Item referencedItem) {
|
||||
super(opcode, referencedItem);
|
||||
|
||||
if (regA >= 1 << 8) {
|
||||
throw new RuntimeException("The register number must be less than v256");
|
||||
}
|
||||
|
||||
if (opcode == Opcode.NEW_INSTANCE && ((TypeIdItem) referencedItem).getTypeDescriptor().charAt(0) != 'L') {
|
||||
throw new RuntimeException("Only class references can be used with the new-instance opcode");
|
||||
}
|
||||
|
||||
buffer[0] = opcode.value;
|
||||
buffer[1] = (byte) regA;
|
||||
//the item index will be set later, during placement/writing
|
||||
}
|
||||
|
||||
private Instruction21c(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(dexFile, opcode, buffer, bufferIndex);
|
||||
|
||||
if (opcode == Opcode.NEW_INSTANCE && ((TypeIdItem) this.getReferencedItem()).getTypeDescriptor().charAt(0) != 'L') {
|
||||
throw new RuntimeException("Only class references can be used with the new-instance opcode");
|
||||
}
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.Format21c;
|
||||
}
|
||||
|
||||
public short getRegister() {
|
||||
return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
return new Instruction21c(dexFile, opcode, buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
|
||||
public class Instruction21h extends Instruction {
|
||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||
|
||||
public Instruction21h(Opcode opcode, short regA, short litB) {
|
||||
super(opcode);
|
||||
|
||||
if (regA >= 1 << 8) {
|
||||
throw new RuntimeException("The register number must be less than v256");
|
||||
}
|
||||
|
||||
buffer[0] = opcode.value;
|
||||
buffer[1] = (byte) regA;
|
||||
buffer[2] = (byte) litB;
|
||||
buffer[3] = (byte) (litB >> 8);
|
||||
}
|
||||
|
||||
private Instruction21h(Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(opcode, buffer, bufferIndex);
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.Format21h;
|
||||
}
|
||||
|
||||
public short getRegister() {
|
||||
return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
public short getLiteral() {
|
||||
return NumberUtils.decodeShort(buffer, bufferIndex + 2);
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
return new Instruction21h(opcode, buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
|
||||
public class Instruction21s extends Instruction {
|
||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||
|
||||
public Instruction21s(Opcode opcode, short regA, short litB) {
|
||||
super(opcode);
|
||||
|
||||
if (regA >= 1 << 8) {
|
||||
throw new RuntimeException("The register number must be less than v256");
|
||||
}
|
||||
|
||||
buffer[0] = opcode.value;
|
||||
buffer[1] = (byte) regA;
|
||||
buffer[2] = (byte) litB;
|
||||
buffer[3] = (byte) (litB >> 8);
|
||||
}
|
||||
|
||||
private Instruction21s(Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(opcode, buffer, bufferIndex);
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.Format21s;
|
||||
}
|
||||
|
||||
public short getRegister() {
|
||||
return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
public short getLiteral() {
|
||||
return NumberUtils.decodeShort(buffer, bufferIndex + 2);
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
return new Instruction21s(opcode, buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
|
||||
public class Instruction21t extends Instruction {
|
||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||
|
||||
public Instruction21t(Opcode opcode, short regA, short offB) {
|
||||
super(opcode);
|
||||
|
||||
if (regA >= 1 << 8) {
|
||||
throw new RuntimeException("The register number must be less than v256");
|
||||
}
|
||||
|
||||
if (offB == 0) {
|
||||
throw new RuntimeException("The offset cannot be 0.");
|
||||
}
|
||||
|
||||
buffer[0] = opcode.value;
|
||||
buffer[1] = (byte) regA;
|
||||
buffer[2] = (byte) offB;
|
||||
buffer[3] = (byte) (offB >> 8);
|
||||
}
|
||||
|
||||
private Instruction21t(Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(opcode, buffer, bufferIndex);
|
||||
|
||||
if (getOffset() == 0) {
|
||||
throw new RuntimeException("The offset cannot be 0.");
|
||||
}
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.Format21t;
|
||||
}
|
||||
|
||||
public short getRegister() {
|
||||
return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
public short getOffset() {
|
||||
return NumberUtils.decodeShort(buffer, bufferIndex + 2);
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
return new Instruction21t(opcode, buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
|
||||
public class Instruction22b extends Instruction {
|
||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||
|
||||
public Instruction22b(Opcode opcode, short regA, short regB, byte litC) {
|
||||
super(opcode);
|
||||
|
||||
if (regA >= 1 << 8 ||
|
||||
regB >= 1 << 8) {
|
||||
throw new RuntimeException("The register number must be less than v256");
|
||||
}
|
||||
|
||||
buffer[0] = opcode.value;
|
||||
buffer[1] = (byte) regA;
|
||||
buffer[2] = (byte) regB;
|
||||
buffer[3] = litC;
|
||||
}
|
||||
|
||||
private Instruction22b(Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(opcode, buffer, bufferIndex);
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.Format22b;
|
||||
}
|
||||
|
||||
public short getRegisterA() {
|
||||
return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
public short getRegisterB() {
|
||||
return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 2]);
|
||||
}
|
||||
|
||||
public byte getLiteral() {
|
||||
return buffer[bufferIndex + 3];
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
return new Instruction22b(opcode, buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.InstructionWithReference;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Item;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
|
||||
public class Instruction22c extends InstructionWithReference {
|
||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||
|
||||
public Instruction22c(Opcode opcode, byte regA, byte regB, Item referencedItem) {
|
||||
super(opcode, referencedItem);
|
||||
|
||||
if (regA >= 1 << 4 ||
|
||||
regB >= 1 << 4) {
|
||||
throw new RuntimeException("The register number must be less than v16");
|
||||
}
|
||||
|
||||
buffer[0] = opcode.value;
|
||||
buffer[1] = (byte) ((regB << 4) | regA);
|
||||
//the item index will be set later, during placement/writing
|
||||
}
|
||||
|
||||
private Instruction22c(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(dexFile, opcode, buffer, bufferIndex);
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.Format22c;
|
||||
}
|
||||
|
||||
public byte getRegisterA() {
|
||||
return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
public byte getRegisterB() {
|
||||
return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
return new Instruction22c(dexFile, opcode, buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
|
||||
public class Instruction22s extends Instruction {
|
||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||
|
||||
public Instruction22s(Opcode opcode, byte regA, byte regB, short litC) {
|
||||
super(opcode);
|
||||
|
||||
if (regA >= 1 << 4 ||
|
||||
regB >= 1 << 4) {
|
||||
throw new RuntimeException("The register number must be less than v16");
|
||||
}
|
||||
|
||||
buffer[0] = opcode.value;
|
||||
buffer[1] = (byte) ((regB << 4) | regA);
|
||||
buffer[2] = (byte) litC;
|
||||
buffer[3] = (byte) (litC >> 8);
|
||||
}
|
||||
|
||||
private Instruction22s(Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(opcode, buffer, bufferIndex);
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.Format22s;
|
||||
}
|
||||
|
||||
public byte getRegisterA() {
|
||||
return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
public byte getRegisterB() {
|
||||
return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
public short getLiteral() {
|
||||
return NumberUtils.decodeShort(buffer, bufferIndex + 2);
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
return new Instruction22s(opcode, buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
|
||||
public class Instruction22t extends Instruction {
|
||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||
|
||||
public Instruction22t(Opcode opcode, byte regA, byte regB, short offC) {
|
||||
super(opcode);
|
||||
|
||||
if (regA >= 1 << 4 ||
|
||||
regB >= 1 << 4) {
|
||||
throw new RuntimeException("The register number must be less than v16");
|
||||
}
|
||||
|
||||
if (offC == 0) {
|
||||
throw new RuntimeException("The offset cannot be 0.");
|
||||
}
|
||||
|
||||
buffer[0] = opcode.value;
|
||||
buffer[1] = (byte) ((regB << 4) | regA);
|
||||
buffer[2] = (byte) offC;
|
||||
buffer[3] = (byte) (offC >> 8);
|
||||
}
|
||||
|
||||
private Instruction22t(Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(opcode, buffer, bufferIndex);
|
||||
|
||||
if (getOffset() == 0) {
|
||||
throw new RuntimeException("The offset cannot be 0.");
|
||||
}
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.Format22t;
|
||||
}
|
||||
|
||||
public byte getRegisterA() {
|
||||
return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
public byte getRegisterB() {
|
||||
return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
public short getOffset() {
|
||||
return NumberUtils.decodeShort(buffer, bufferIndex + 2);
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
return new Instruction22t(opcode, buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
|
||||
public class Instruction22x extends Instruction {
|
||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||
|
||||
public Instruction22x(Opcode opcode, short regA, int regB) {
|
||||
super(opcode);
|
||||
|
||||
if (regA >= 1 << 8) {
|
||||
throw new RuntimeException("The register number must be less than v16");
|
||||
}
|
||||
|
||||
if (regB >= 1 << 16) {
|
||||
throw new RuntimeException("The register number must be less than v65536");
|
||||
}
|
||||
|
||||
buffer[0] = opcode.value;
|
||||
buffer[1] = (byte) regA;
|
||||
buffer[2] = (byte) regB;
|
||||
buffer[3] = (byte) (regB >> 8);
|
||||
}
|
||||
|
||||
private Instruction22x(Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(opcode, buffer, bufferIndex);
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.Format22x;
|
||||
}
|
||||
|
||||
public short getRegisterA() {
|
||||
return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
public int getRegisterB() {
|
||||
return NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 2);
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
return new Instruction22x(opcode, buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
|
||||
public class Instruction23x extends Instruction {
|
||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||
|
||||
public Instruction23x(Opcode opcode, short regA, short regB, short regC) {
|
||||
super(opcode);
|
||||
|
||||
if (regA >= 1 << 8 ||
|
||||
regB >= 1 << 8 ||
|
||||
regC >= 1 << 8) {
|
||||
throw new RuntimeException("The register number must be less than v256");
|
||||
}
|
||||
|
||||
buffer[0] = opcode.value;
|
||||
buffer[1] = (byte) regA;
|
||||
buffer[2] = (byte) regB;
|
||||
buffer[3] = (byte) regC;
|
||||
}
|
||||
|
||||
private Instruction23x(Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(opcode, buffer, bufferIndex);
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.Format23x;
|
||||
}
|
||||
|
||||
public short getRegisterA() {
|
||||
return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
public short getRegisterB() {
|
||||
return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 2]);
|
||||
}
|
||||
|
||||
public short getRegisterC() {
|
||||
return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 3]);
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
return new Instruction23x(opcode, buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
|
||||
public class Instruction30t extends Instruction
|
||||
{
|
||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||
|
||||
public Instruction30t(Opcode opcode, int offA) {
|
||||
super(opcode);
|
||||
|
||||
buffer[0] = opcode.value;
|
||||
buffer[2] = (byte)offA;
|
||||
buffer[3] = (byte)(offA >> 8);
|
||||
buffer[4] = (byte)(offA >> 16);
|
||||
buffer[5] = (byte)(offA >> 24);
|
||||
}
|
||||
|
||||
private Instruction30t(Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(opcode, buffer, bufferIndex);
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.Format30t;
|
||||
}
|
||||
|
||||
public int getOffset() {
|
||||
return NumberUtils.decodeInt(buffer, bufferIndex + 2);
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
return new Instruction30t(opcode, buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.InstructionWithReference;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Item;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
|
||||
public class Instruction31c extends InstructionWithReference {
|
||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||
|
||||
public Instruction31c(Opcode opcode, short regA, Item referencedItem) {
|
||||
super(opcode, referencedItem);
|
||||
|
||||
if (regA >= 1 << 8) {
|
||||
throw new RuntimeException("The register number must be less than v256");
|
||||
}
|
||||
|
||||
buffer[0] = opcode.value;
|
||||
buffer[1] = (byte) regA;
|
||||
//the item index will be set later, during placement/writing
|
||||
}
|
||||
|
||||
private Instruction31c(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(dexFile, opcode, buffer, bufferIndex);
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.Format31c;
|
||||
}
|
||||
|
||||
public short getRegister() {
|
||||
return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
return new Instruction31c(dexFile, opcode, buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
|
||||
public class Instruction31i extends Instruction {
|
||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||
|
||||
public Instruction31i(Opcode opcode, short regA, int litB) {
|
||||
super(opcode);
|
||||
|
||||
if (regA >= 1 << 8) {
|
||||
throw new RuntimeException("The register number must be less than v256");
|
||||
}
|
||||
|
||||
buffer[0] = opcode.value;
|
||||
buffer[1] = (byte) regA;
|
||||
buffer[2] = (byte) litB;
|
||||
buffer[3] = (byte) (litB >> 8);
|
||||
buffer[4] = (byte) (litB >> 16);
|
||||
buffer[5] = (byte) (litB >> 24);
|
||||
}
|
||||
|
||||
private Instruction31i(Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(opcode, buffer, bufferIndex);
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.Format31i;
|
||||
}
|
||||
|
||||
public short getRegister() {
|
||||
return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
public int getLiteral() {
|
||||
return NumberUtils.decodeInt(buffer, bufferIndex + 2);
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
return new Instruction31i(opcode, buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
|
||||
public class Instruction31t extends Instruction {
|
||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||
|
||||
public Instruction31t(Opcode opcode, short regA, int offB) {
|
||||
super(opcode);
|
||||
|
||||
if (regA >= 1 << 8) {
|
||||
throw new RuntimeException("The register number must be less than v256");
|
||||
}
|
||||
|
||||
buffer[0] = opcode.value;
|
||||
buffer[1] = (byte) regA;
|
||||
buffer[2] = (byte) offB;
|
||||
buffer[3] = (byte) (offB >> 8);
|
||||
buffer[4] = (byte) (offB >> 16);
|
||||
buffer[5] = (byte) (offB >> 24);
|
||||
}
|
||||
|
||||
private Instruction31t(Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(opcode, buffer, bufferIndex);
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.Format31t;
|
||||
}
|
||||
|
||||
public short getRegister() {
|
||||
return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
public int getOffset() {
|
||||
return NumberUtils.decodeInt(buffer, bufferIndex + 2);
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
return new Instruction31t(opcode, buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
|
||||
public class Instruction32x extends Instruction
|
||||
{
|
||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||
|
||||
public Instruction32x(Opcode opcode, int regA, int regB) {
|
||||
super(opcode);
|
||||
|
||||
if (regA >= 1<<16 ||
|
||||
regB >= 1<<16) {
|
||||
throw new RuntimeException("The register number must be less than v65536");
|
||||
}
|
||||
|
||||
buffer[0] = opcode.value;
|
||||
buffer[2] = (byte)regA;
|
||||
buffer[3] = (byte)(regA >> 8);
|
||||
buffer[4] = (byte)regB;
|
||||
buffer[5] = (byte)(regB >> 8);
|
||||
}
|
||||
|
||||
private Instruction32x(Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(opcode, buffer, bufferIndex);
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.Format32x;
|
||||
}
|
||||
|
||||
public int getRegisterA() {
|
||||
return NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 2);
|
||||
}
|
||||
|
||||
public int getRegisterB() {
|
||||
return NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 4);
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
return new Instruction32x(opcode, buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.InstructionWithReference;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import static org.jf.dexlib.Code.Opcode.*;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Item;
|
||||
import org.jf.dexlib.MethodIdItem;
|
||||
import org.jf.dexlib.TypeIdItem;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
|
||||
public class Instruction35c extends InstructionWithReference {
|
||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||
|
||||
public Instruction35c(Opcode opcode, int regCount, byte regD, byte regE, byte regF, byte regG,
|
||||
byte regA, Item referencedItem) {
|
||||
super(opcode, referencedItem);
|
||||
|
||||
if (regCount > 5) {
|
||||
throw new RuntimeException("regCount cannot be greater than 5");
|
||||
}
|
||||
|
||||
if (regD >= 1 << 4 ||
|
||||
regE >= 1 << 4 ||
|
||||
regF >= 1 << 4 ||
|
||||
regG >= 1 << 4 ||
|
||||
regA >= 1 << 4) {
|
||||
throw new RuntimeException("All register args must fit in 4 bits");
|
||||
}
|
||||
|
||||
buffer[0] = opcode.value;
|
||||
buffer[1] = (byte) ((regCount << 4) | regA);
|
||||
//the item index will be set later, during placement/writing
|
||||
buffer[4] = (byte) ((regE << 4) | regD);
|
||||
buffer[5] = (byte) ((regG << 4) | regF);
|
||||
|
||||
checkItem();
|
||||
}
|
||||
|
||||
private Instruction35c(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(dexFile, opcode, buffer, bufferIndex);
|
||||
|
||||
if (getRegCount() > 5) {
|
||||
throw new RuntimeException("regCount cannot be greater than 5");
|
||||
}
|
||||
|
||||
checkItem();
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.Format35c;
|
||||
}
|
||||
|
||||
public byte getRegisterA() {
|
||||
return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
public byte getRegCount() {
|
||||
return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
public byte getRegisterD() {
|
||||
return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 4]);
|
||||
}
|
||||
|
||||
public byte getRegisterE() {
|
||||
return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 4]);
|
||||
}
|
||||
|
||||
public byte getRegisterF() {
|
||||
return NumberUtils.decodeLowUnsignedNibble(buffer[bufferIndex + 5]);
|
||||
}
|
||||
|
||||
public byte getRegisterG() {
|
||||
return NumberUtils.decodeHighUnsignedNibble(buffer[bufferIndex + 5]);
|
||||
}
|
||||
|
||||
private void checkItem() {
|
||||
Item item = getReferencedItem();
|
||||
|
||||
if (opcode == FILLED_NEW_ARRAY) {
|
||||
//check data for filled-new-array opcode
|
||||
String type = ((TypeIdItem) item).getTypeDescriptor();
|
||||
if (type.charAt(0) != '[') {
|
||||
throw new RuntimeException("The type must be an array type");
|
||||
}
|
||||
if (type.charAt(1) == 'J' || type.charAt(1) == 'D') {
|
||||
throw new RuntimeException("The type cannot be an array of longs or doubles");
|
||||
}
|
||||
} else if (opcode.value >= INVOKE_VIRTUAL.value && opcode.value <= INVOKE_INTERFACE.value) {
|
||||
//check data for invoke-* opcodes
|
||||
MethodIdItem methodIdItem = (MethodIdItem) item;
|
||||
int parameterRegisterCount = methodIdItem.getPrototype().getParameterRegisterCount();
|
||||
if (opcode != INVOKE_STATIC) {
|
||||
parameterRegisterCount++;
|
||||
}
|
||||
if (parameterRegisterCount != getRegCount()) {
|
||||
throw new RuntimeException("regCount does not match the number of arguments of the method");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
return new Instruction35c(dexFile, opcode, buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.InstructionWithReference;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import static org.jf.dexlib.Code.Opcode.*;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Item;
|
||||
import org.jf.dexlib.MethodIdItem;
|
||||
import org.jf.dexlib.TypeIdItem;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
|
||||
public class Instruction3rc extends InstructionWithReference {
|
||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||
|
||||
public Instruction3rc(Opcode opcode, short regCount, int startReg, Item referencedItem) {
|
||||
super(opcode, referencedItem);
|
||||
|
||||
if (regCount >= 1 << 8) {
|
||||
throw new RuntimeException("regCount must be less than 256");
|
||||
}
|
||||
if (regCount < 0) {
|
||||
throw new RuntimeException("regCount cannot be negative");
|
||||
}
|
||||
|
||||
if (startReg >= 1 << 16) {
|
||||
throw new RuntimeException("The beginning register of the range must be less than 65536");
|
||||
}
|
||||
if (startReg < 0) {
|
||||
throw new RuntimeException("The beginning register of the range cannot be negative");
|
||||
}
|
||||
|
||||
buffer[0] = opcode.value;
|
||||
buffer[1] = (byte) regCount;
|
||||
//the item index will be set later, during placement/writing
|
||||
buffer[4] = (byte) startReg;
|
||||
buffer[5] = (byte) (startReg >> 8);
|
||||
|
||||
checkItem();
|
||||
}
|
||||
|
||||
private Instruction3rc(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(dexFile, opcode, buffer, bufferIndex);
|
||||
|
||||
checkItem();
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.Format3rc;
|
||||
}
|
||||
|
||||
public short getRegCount() {
|
||||
return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
public int getStartRegister() {
|
||||
return NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 4);
|
||||
}
|
||||
|
||||
private void checkItem() {
|
||||
Item item = getReferencedItem();
|
||||
|
||||
if (opcode == FILLED_NEW_ARRAY_RANGE) {
|
||||
//check data for filled-new-array/range opcode
|
||||
String type = ((TypeIdItem) item).getTypeDescriptor();
|
||||
if (type.charAt(0) != '[') {
|
||||
throw new RuntimeException("The type must be an array type");
|
||||
}
|
||||
if (type.charAt(1) == 'J' || type.charAt(1) == 'D') {
|
||||
throw new RuntimeException("The type cannot be an array of longs or doubles");
|
||||
}
|
||||
} else if (opcode.value >= INVOKE_VIRTUAL_RANGE.value && opcode.value <= INVOKE_INTERFACE_RANGE.value) {
|
||||
//check data for invoke-*/range opcodes
|
||||
MethodIdItem methodIdItem = (MethodIdItem) item;
|
||||
int parameterRegisterCount = methodIdItem.getPrototype().getParameterRegisterCount();
|
||||
if (opcode != INVOKE_STATIC_RANGE) {
|
||||
parameterRegisterCount++;
|
||||
}
|
||||
if (parameterRegisterCount != getRegCount()) {
|
||||
throw new RuntimeException("regCount does not match the number of arguments of the method");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
return new Instruction3rc(dexFile, opcode, buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
|
||||
public class Instruction51l extends Instruction {
|
||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||
|
||||
public Instruction51l(Opcode opcode, short regA, long litB) {
|
||||
super(opcode);
|
||||
|
||||
if (regA >= 1 << 8) {
|
||||
throw new RuntimeException("The register number must be less than v256");
|
||||
}
|
||||
|
||||
buffer[0] = opcode.value;
|
||||
buffer[1] = (byte) regA;
|
||||
buffer[2] = (byte) litB;
|
||||
buffer[3] = (byte) (litB >> 8);
|
||||
buffer[4] = (byte) (litB >> 16);
|
||||
buffer[5] = (byte) (litB >> 24);
|
||||
buffer[6] = (byte) (litB >> 32);
|
||||
buffer[7] = (byte) (litB >> 40);
|
||||
buffer[8] = (byte) (litB >> 48);
|
||||
buffer[9] = (byte) (litB >> 56);
|
||||
}
|
||||
|
||||
private Instruction51l(Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(opcode, buffer, bufferIndex);
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.Format51l;
|
||||
}
|
||||
|
||||
public short getRegister() {
|
||||
return NumberUtils.decodeUnsignedByte(buffer[bufferIndex + 1]);
|
||||
}
|
||||
|
||||
public long getLiteral() {
|
||||
return NumberUtils.decodeLong(buffer, bufferIndex + 2);
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
return new Instruction51l(opcode, buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
import org.jf.dexlib.DexFile;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
public class PackedSwitchDataPseudoInstruction extends Instruction {
|
||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return getTargetCount() * 4 + 8;
|
||||
}
|
||||
|
||||
public PackedSwitchDataPseudoInstruction(int firstKey, int[] targets) {
|
||||
super(Opcode.NOP, targets.length * 4 + 8);
|
||||
|
||||
/*this.firstKey = firstKey;
|
||||
this.targets = targets;*/
|
||||
|
||||
if (targets.length > 0xFFFF) {
|
||||
throw new RuntimeException("The packed-switch data contains too many elements. " +
|
||||
"The maximum number of switch elements is 65535");
|
||||
}
|
||||
|
||||
buffer[0] = 0x00;
|
||||
buffer[1] = 0x01; //packed-switch pseudo-opcode
|
||||
|
||||
buffer[2] = (byte) targets.length;
|
||||
buffer[3] = (byte) (targets.length >> 8);
|
||||
|
||||
buffer[4] = (byte) firstKey;
|
||||
buffer[5] = (byte) (firstKey >> 8);
|
||||
buffer[6] = (byte) (firstKey >> 16);
|
||||
buffer[7] = (byte) (firstKey >> 24);
|
||||
|
||||
int position = 8;
|
||||
for (int target : targets) {
|
||||
buffer[position++] = (byte) target;
|
||||
buffer[position++] = (byte) (target >> 8);
|
||||
buffer[position++] = (byte) (target >> 16);
|
||||
buffer[position++] = (byte) (target >> 24);
|
||||
}
|
||||
}
|
||||
|
||||
public PackedSwitchDataPseudoInstruction(byte[] buffer, int bufferIndex) {
|
||||
super(Opcode.NOP, buffer, bufferIndex);
|
||||
|
||||
byte opcodeByte = buffer[bufferIndex++];
|
||||
if (opcodeByte != 0x00) {
|
||||
throw new RuntimeException("Invalid opcode byte for a PackedSwitchData pseudo-instruction");
|
||||
}
|
||||
byte subopcodeByte = buffer[bufferIndex];
|
||||
if (subopcodeByte != 0x01) {
|
||||
throw new RuntimeException("Invalid sub-opcode byte for a PackedSwitchData pseudo-instruction");
|
||||
}
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.PackedSwitchData;
|
||||
}
|
||||
|
||||
public int getTargetCount() {
|
||||
return NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 2);
|
||||
}
|
||||
|
||||
public int getFirstKey() {
|
||||
return NumberUtils.decodeInt(buffer, bufferIndex + 4);
|
||||
}
|
||||
|
||||
public static class PackedSwitchTarget {
|
||||
public int value;
|
||||
public int target;
|
||||
}
|
||||
|
||||
public Iterator<PackedSwitchTarget> getTargets() {
|
||||
return new Iterator<PackedSwitchTarget>() {
|
||||
final int targetCount = getTargetCount();
|
||||
int i = 0;
|
||||
int position = bufferIndex + 8;
|
||||
int value = getFirstKey();
|
||||
|
||||
PackedSwitchTarget packedSwitchTarget = new PackedSwitchTarget();
|
||||
|
||||
public boolean hasNext() {
|
||||
return i<targetCount;
|
||||
}
|
||||
|
||||
public PackedSwitchTarget next() {
|
||||
packedSwitchTarget.value = value++;
|
||||
packedSwitchTarget.target = NumberUtils.decodeInt(buffer, position);
|
||||
position+=4;
|
||||
i++;
|
||||
return packedSwitchTarget;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static interface PackedSwitchTargetIteratorDelegate {
|
||||
void ProcessPackedSwitchTarget(int value, int target);
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
if (opcode != Opcode.NOP) {
|
||||
throw new RuntimeException("The opcode for a PackedSwitchDataPseudoInstruction must by NOP");
|
||||
}
|
||||
return new PackedSwitchDataPseudoInstruction(buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code.Format;
|
||||
|
||||
import org.jf.dexlib.Code.Instruction;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
import org.jf.dexlib.DexFile;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
public class SparseSwitchDataPseudoInstruction extends Instruction {
|
||||
public static final Instruction.InstructionFactory Factory = new Factory();
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return getTargetCount() * 8 + 4;
|
||||
}
|
||||
|
||||
public SparseSwitchDataPseudoInstruction(int[] keys, int[] targets) {
|
||||
super(Opcode.NOP, keys.length * 8 + 4);
|
||||
|
||||
if (keys.length != targets.length) {
|
||||
throw new RuntimeException("The number of keys and offsets don't match");
|
||||
}
|
||||
|
||||
if (targets.length == 0) {
|
||||
throw new RuntimeException("The sparse-switch data must contain at least 1 key/target");
|
||||
}
|
||||
|
||||
if (targets.length > 0xFFFF) {
|
||||
throw new RuntimeException("The sparse-switch data contains too many elements. " +
|
||||
"The maximum number of switch elements is 65535");
|
||||
}
|
||||
|
||||
buffer[0] = 0x00;
|
||||
buffer[1] = 0x02; //sparse-switch psuedo-opcode
|
||||
|
||||
buffer[2] = (byte) targets.length;
|
||||
buffer[3] = (byte) (targets.length >> 8);
|
||||
|
||||
int position = 8;
|
||||
|
||||
if (targets.length > 0) {
|
||||
int key = keys[0];
|
||||
buffer[4] = (byte) key;
|
||||
buffer[5] = (byte) (key >> 8);
|
||||
buffer[6] = (byte) (key >> 16);
|
||||
buffer[7] = (byte) (key >> 24);
|
||||
|
||||
for (int i = 1; i < keys.length; i++) {
|
||||
key = keys[i];
|
||||
if (key <= keys[i - 1]) {
|
||||
throw new RuntimeException("The targets in a sparse switch block must be sorted in ascending" +
|
||||
"order, by key");
|
||||
}
|
||||
|
||||
buffer[position++] = (byte) key;
|
||||
buffer[position++] = (byte) (key >> 8);
|
||||
buffer[position++] = (byte) (key >> 16);
|
||||
buffer[position++] = (byte) (key >> 24);
|
||||
}
|
||||
|
||||
for (int target : targets) {
|
||||
buffer[position++] = (byte) target;
|
||||
buffer[position++] = (byte) (target >> 8);
|
||||
buffer[position++] = (byte) (target >> 16);
|
||||
buffer[position++] = (byte) (target >> 24);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SparseSwitchDataPseudoInstruction(byte[] buffer, int bufferIndex) {
|
||||
super(Opcode.NOP, buffer, bufferIndex);
|
||||
|
||||
byte opcodeByte = buffer[bufferIndex++];
|
||||
if (opcodeByte != 0x00) {
|
||||
throw new RuntimeException("Invalid opcode byte for a SparseSwitchData pseudo-instruction");
|
||||
}
|
||||
byte subopcodeByte = buffer[bufferIndex];
|
||||
if (subopcodeByte != 0x02) {
|
||||
throw new RuntimeException("Invalid sub-opcode byte for a SparseSwitchData pseudo-instruction");
|
||||
}
|
||||
}
|
||||
|
||||
public Format getFormat() {
|
||||
return Format.SparseSwitchData;
|
||||
}
|
||||
|
||||
public int getTargetCount() {
|
||||
return NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 2);
|
||||
}
|
||||
|
||||
public static class SparseSwitchTarget {
|
||||
public int value;
|
||||
public int target;
|
||||
}
|
||||
|
||||
public Iterator<SparseSwitchTarget> getTargets() {
|
||||
return new Iterator<SparseSwitchTarget>() {
|
||||
final int targetCount = getTargetCount();
|
||||
int i = 0;
|
||||
int valuePosition = bufferIndex + 4;
|
||||
int targetPosition = bufferIndex + 4 + targetCount * 4;
|
||||
|
||||
SparseSwitchTarget sparseSwitchTarget = new SparseSwitchTarget();
|
||||
|
||||
public boolean hasNext() {
|
||||
return i<targetCount;
|
||||
}
|
||||
|
||||
public SparseSwitchTarget next() {
|
||||
sparseSwitchTarget.value = NumberUtils.decodeInt(buffer, valuePosition);
|
||||
sparseSwitchTarget.target = NumberUtils.decodeInt(buffer, targetPosition);
|
||||
valuePosition+=4;
|
||||
targetPosition+=4;
|
||||
i++;
|
||||
return sparseSwitchTarget;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static class Factory implements Instruction.InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
if (opcode != Opcode.NOP) {
|
||||
throw new RuntimeException("The opcode for a SparseSwitchDataPseudoInstruction must by NOP");
|
||||
}
|
||||
return new SparseSwitchDataPseudoInstruction(buffer, bufferIndex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
73
dexlib/src/main/java/org/jf/dexlib/Code/Instruction.java
Normal file
73
dexlib/src/main/java/org/jf/dexlib/Code/Instruction.java
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code;
|
||||
|
||||
import org.jf.dexlib.*;
|
||||
import org.jf.dexlib.Code.Format.Format;
|
||||
|
||||
public abstract class Instruction {
|
||||
public final Opcode opcode;
|
||||
protected final byte[] buffer;
|
||||
protected final int bufferIndex;
|
||||
|
||||
public int getSize() {
|
||||
return opcode.format.size;
|
||||
}
|
||||
|
||||
protected Instruction(Opcode opcode) {
|
||||
this.opcode = opcode;
|
||||
|
||||
this.bufferIndex = 0;
|
||||
this.buffer = new byte[opcode.format.size];
|
||||
}
|
||||
|
||||
protected Instruction(Opcode opcode, int bufferSize) {
|
||||
this.opcode = opcode;
|
||||
|
||||
this.bufferIndex = 0;
|
||||
this.buffer = new byte[bufferSize];
|
||||
}
|
||||
|
||||
protected Instruction(Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
this.opcode = opcode;
|
||||
|
||||
this.buffer = buffer;
|
||||
this.bufferIndex = bufferIndex;
|
||||
|
||||
if (buffer[bufferIndex] != opcode.value) {
|
||||
throw new RuntimeException("The given opcode doesn't match the opcode byte");
|
||||
}
|
||||
}
|
||||
|
||||
public abstract Format getFormat();
|
||||
|
||||
public static interface InstructionFactory {
|
||||
public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex);
|
||||
}
|
||||
}
|
205
dexlib/src/main/java/org/jf/dexlib/Code/InstructionIterator.java
Normal file
205
dexlib/src/main/java/org/jf/dexlib/Code/InstructionIterator.java
Normal file
@ -0,0 +1,205 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code;
|
||||
|
||||
import org.jf.dexlib.Util.Hex;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
import org.jf.dexlib.Code.Format.*;
|
||||
import org.jf.dexlib.DexFile;
|
||||
|
||||
public class InstructionIterator {
|
||||
/**
|
||||
* This method partially decodes the instructions in the given byte array and iterates over them, calling
|
||||
* the appropriate ProcessRawInstructionDelegate method for each instruction
|
||||
* @param insns a byte array containing the instructions
|
||||
* @param processRawInstruction a <code>ProcessInstructionDelegate</code> object containing the methods
|
||||
* that get called for each instruction that is encountered
|
||||
*/
|
||||
public static void IterateInstructions(byte[] insns, ProcessRawInstructionDelegate processRawInstruction) {
|
||||
int insnsPosition = 0;
|
||||
|
||||
while (insnsPosition < insns.length) {
|
||||
Opcode opcode = Opcode.getOpcodeByValue(insns[insnsPosition]);
|
||||
|
||||
if (opcode == null) {
|
||||
throw new RuntimeException("Unknown opcode: " + Hex.u1(insns[insnsPosition]));
|
||||
}
|
||||
|
||||
if (opcode.referenceType == ReferenceType.none) {
|
||||
byte secondByte = insns[insnsPosition+1];
|
||||
//if this is one of the "special" opcodes
|
||||
if (opcode == Opcode.NOP && secondByte > 0) {
|
||||
switch (secondByte) {
|
||||
case 1:
|
||||
{
|
||||
//packed-switch
|
||||
int size = NumberUtils.decodeUnsignedShort(insns[insnsPosition+2], insns[insnsPosition+3]);
|
||||
int end = insnsPosition + size * 4 + 8;
|
||||
processRawInstruction.ProcessPackedSwitchInstruction(insnsPosition, size, end-insnsPosition);
|
||||
insnsPosition = end;
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
//sparse-switch
|
||||
int size = NumberUtils.decodeUnsignedShort(insns[insnsPosition+2], insns[insnsPosition+3]);
|
||||
int end = insnsPosition + size * 8 + 4;
|
||||
processRawInstruction.ProcessSparseSwitchInstruction(insnsPosition, size, end-insnsPosition);
|
||||
insnsPosition = end;
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
//fill-array-data
|
||||
int elementWidth = NumberUtils.decodeUnsignedShort(insns[insnsPosition+2],
|
||||
insns[insnsPosition+3]);
|
||||
int size = NumberUtils.decodeInt(insns[insnsPosition+4], insns[insnsPosition+5],
|
||||
insns[insnsPosition+6], insns[insnsPosition+7]);
|
||||
int end = insnsPosition + (size * elementWidth) + 8;
|
||||
if (end % 2 == 1) {
|
||||
end++;
|
||||
}
|
||||
processRawInstruction.ProcessFillArrayDataInstruction(insnsPosition, elementWidth, size,
|
||||
end-insnsPosition);
|
||||
insnsPosition = end;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
processRawInstruction.ProcessNormalInstruction(opcode, insnsPosition);
|
||||
insnsPosition += opcode.format.size;
|
||||
}
|
||||
} else {
|
||||
processRawInstruction.ProcessReferenceInstruction(opcode, insnsPosition);
|
||||
insnsPosition += opcode.format.size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void IterateInstructions(DexFile dexFile, byte[] insns, ProcessInstructionDelegate delegate) {
|
||||
int insnsPosition = 0;
|
||||
|
||||
while (insnsPosition < insns.length) {
|
||||
Opcode opcode = Opcode.getOpcodeByValue(insns[insnsPosition]);
|
||||
|
||||
Instruction instruction = null;
|
||||
|
||||
if (opcode == null) {
|
||||
throw new RuntimeException("Unknown opcode: " + Hex.u1(insns[insnsPosition]));
|
||||
}
|
||||
|
||||
if (opcode == Opcode.NOP) {
|
||||
byte secondByte = insns[insnsPosition+1];
|
||||
switch (secondByte) {
|
||||
case 0:
|
||||
{
|
||||
instruction = new Instruction10x(Opcode.NOP, insns, insnsPosition);
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
insnsPosition += insnsPosition & 0x01;
|
||||
instruction = new PackedSwitchDataPseudoInstruction(insns, insnsPosition);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
insnsPosition += insnsPosition & 0x01;
|
||||
instruction = new SparseSwitchDataPseudoInstruction(insns, insnsPosition);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
insnsPosition += insnsPosition & 0x01;
|
||||
instruction = new ArrayDataPseudoInstruction(insns, insnsPosition);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
instruction = opcode.format.Factory.makeInstruction(dexFile, opcode, insns, insnsPosition);
|
||||
}
|
||||
|
||||
delegate.ProcessInstruction(insnsPosition, instruction);
|
||||
insnsPosition += instruction.getSize();
|
||||
}
|
||||
}
|
||||
|
||||
public static interface ProcessRawInstructionDelegate {
|
||||
/**
|
||||
* The <code>InstructionIterator</code> calls this method when a "normal" instruction is encountered. I.e.
|
||||
* not a special or reference instruction
|
||||
* @param opcode the opcode of the instruction that was encountered
|
||||
* @param index the start index of the instruction in the byte array that the
|
||||
* <code>InstructionIterator</code> is iterating
|
||||
*/
|
||||
public void ProcessNormalInstruction(Opcode opcode, int index);
|
||||
|
||||
/**
|
||||
* The <code>InstructionIterator</code> calls this method when a "reference" instruction is encountered.
|
||||
* I.e. an instruction that contains an index that is a reference to a string, method, type or field.
|
||||
* @param opcode the opcode of the instruction that was encountered
|
||||
* @param index the start index of the instruction in the byte array that the
|
||||
* <code>InstructionIterator</code> is iterating
|
||||
*/
|
||||
public void ProcessReferenceInstruction(Opcode opcode, int index);
|
||||
|
||||
/**
|
||||
* The <code>InstructionIterator</code> calls this method when a packed switch instruction is encountered.
|
||||
* @param index the start index of the instruction in the byte array that the
|
||||
* <code>InstructionIterator</code> is iterating
|
||||
* @param targetCount the number of targets that this packed switch structure contains
|
||||
* @param instructionLength the length of this instruction in bytes
|
||||
*/
|
||||
public void ProcessPackedSwitchInstruction(int index, int targetCount, int instructionLength);
|
||||
|
||||
/**
|
||||
* The <code>InstructionIterator</code> calls this method when a sparse switch instruction is encountered.
|
||||
* @param index the start index of the instruction in the byte array that the
|
||||
* <code>InstructionIterator</code> is iterating
|
||||
* @param targetCount the number of targets that this sparse switch structure contains
|
||||
* @param instructionLength the length of this instruction in bytes
|
||||
*/
|
||||
public void ProcessSparseSwitchInstruction(int index, int targetCount, int instructionLength);
|
||||
|
||||
/**
|
||||
* The <code>InstructionIterator</code> calls this method when a fill-array-data instruction is encountered.
|
||||
* @param index the start index of the instruction in the byte array that the
|
||||
* <code>InstructionIterator</code> is iterating
|
||||
* @param elementWidth the width of the elements contained in this fill-array-data structure
|
||||
* @param elementCount the number of elements contained in this fill-array-data structure
|
||||
* @param instructionLength the length of this instruction in bytes
|
||||
*/
|
||||
public void ProcessFillArrayDataInstruction(int index, int elementWidth, int elementCount,
|
||||
int instructionLength);
|
||||
}
|
||||
|
||||
public static interface ProcessInstructionDelegate {
|
||||
public void ProcessInstruction(int index, Instruction instruction);
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code;
|
||||
|
||||
import org.jf.dexlib.Item;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class InstructionReader {
|
||||
/**
|
||||
* Decodes the instructions in the given byte array, and builds a list of the items referenced by instructions,
|
||||
* using the given <code>DexFile</code> to resolve the item references
|
||||
* @param insns a byte array containing encoded instructions that have just been read in
|
||||
* @param dexFile the <code>DexFile</code> used to resolve item references
|
||||
* @return an array of the referenced <code>Item</code> objects, in the same order as their occurance in the
|
||||
* byte array
|
||||
*/
|
||||
public static Item[] getReferencedItems(final byte[] insns, final DexFile dexFile) {
|
||||
final LinkedList<Item> referencedItems = new LinkedList<Item>();
|
||||
|
||||
InstructionIterator.IterateInstructions(insns, new InstructionIterator.ProcessRawInstructionDelegate() {
|
||||
public void ProcessNormalInstruction(Opcode opcode, int index) {
|
||||
}
|
||||
|
||||
public void ProcessReferenceInstruction(Opcode opcode, int index) {
|
||||
if (opcode == Opcode.CONST_STRING_JUMBO) {
|
||||
int itemIndex = NumberUtils.decodeInt(insns, index+2);
|
||||
if (itemIndex < 0) {
|
||||
throw new RuntimeException("The string index for this const-string/jumbo instruction is too large");
|
||||
}
|
||||
referencedItems.add(dexFile.StringIdsSection.getItemByIndex(itemIndex));
|
||||
} else {
|
||||
int itemIndex = NumberUtils.decodeUnsignedShort(insns, index+2);
|
||||
if (itemIndex > 0xFFFF) {
|
||||
throw new RuntimeException("The item index does not fit in 2 bytes");
|
||||
}
|
||||
|
||||
switch (opcode.referenceType) {
|
||||
case string:
|
||||
referencedItems.add(dexFile.StringIdsSection.getItemByIndex(itemIndex));
|
||||
break;
|
||||
case type:
|
||||
referencedItems.add(dexFile.TypeIdsSection.getItemByIndex(itemIndex));
|
||||
break;
|
||||
case field:
|
||||
referencedItems.add(dexFile.FieldIdsSection.getItemByIndex(itemIndex));
|
||||
break;
|
||||
case method:
|
||||
referencedItems.add(dexFile.MethodIdsSection.getItemByIndex(itemIndex));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ProcessPackedSwitchInstruction(int index, int targetCount, int instructionLength) {
|
||||
}
|
||||
|
||||
public void ProcessSparseSwitchInstruction(int index, int targetCount, int instructionLength) {
|
||||
}
|
||||
|
||||
public void ProcessFillArrayDataInstruction(int index, int elementWidth, int elementCount, int instructionLength) {
|
||||
}
|
||||
});
|
||||
|
||||
Item[] items = new Item[referencedItems.size()];
|
||||
return referencedItems.toArray(items);
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code;
|
||||
|
||||
import org.jf.dexlib.*;
|
||||
import org.jf.dexlib.Util.NumberUtils;
|
||||
|
||||
public abstract class InstructionWithReference extends Instruction {
|
||||
private Item referencedItem;
|
||||
|
||||
protected InstructionWithReference(Opcode opcode, Item referencedItem) {
|
||||
super(opcode);
|
||||
this.referencedItem = referencedItem;
|
||||
checkReferenceType();
|
||||
}
|
||||
|
||||
protected InstructionWithReference(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) {
|
||||
super(opcode, buffer, bufferIndex);
|
||||
|
||||
int itemIndex = NumberUtils.decodeUnsignedShort(buffer[bufferIndex + 2],
|
||||
buffer[bufferIndex + 3]);
|
||||
lookupReferencedItem(dexFile, opcode, itemIndex);
|
||||
}
|
||||
|
||||
public Item getReferencedItem() {
|
||||
return referencedItem;
|
||||
}
|
||||
|
||||
private void lookupReferencedItem(DexFile dexFile, Opcode opcode, int itemIndex) {
|
||||
switch (opcode.referenceType) {
|
||||
case field:
|
||||
referencedItem = dexFile.FieldIdsSection.getItemByIndex(itemIndex);
|
||||
return;
|
||||
case method:
|
||||
referencedItem = dexFile.MethodIdsSection.getItemByIndex(itemIndex);
|
||||
return;
|
||||
case type:
|
||||
referencedItem = dexFile.TypeIdsSection.getItemByIndex(itemIndex);
|
||||
return;
|
||||
case string:
|
||||
referencedItem = dexFile.StringIdsSection.getItemByIndex(itemIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void checkReferenceType() {
|
||||
switch (opcode.referenceType) {
|
||||
case field:
|
||||
if (!(referencedItem instanceof FieldIdItem)) {
|
||||
throw new RuntimeException(referencedItem.getClass().getSimpleName() +
|
||||
" is the wrong item type for opcode " + opcode.name + ". Expecting FieldIdItem.");
|
||||
}
|
||||
return;
|
||||
case method:
|
||||
if (!(referencedItem instanceof MethodIdItem)) {
|
||||
throw new RuntimeException(referencedItem.getClass().getSimpleName() +
|
||||
" is the wrong item type for opcode " + opcode.name + ". Expecting MethodIdItem.");
|
||||
}
|
||||
return;
|
||||
case type:
|
||||
if (!(referencedItem instanceof TypeIdItem)) {
|
||||
throw new RuntimeException(referencedItem.getClass().getSimpleName() +
|
||||
" is the wrong item type for opcode " + opcode.name + ". Expecting TypeIdItem.");
|
||||
}
|
||||
return;
|
||||
case string:
|
||||
if (!(referencedItem instanceof StringIdItem)) {
|
||||
throw new RuntimeException(referencedItem.getClass().getSimpleName() +
|
||||
" is the wrong item type for opcode " + opcode.name + ". Expecting StringIdItem.");
|
||||
}
|
||||
return;
|
||||
default:
|
||||
if (referencedItem != null) {
|
||||
throw new RuntimeException(referencedItem.getClass().getSimpleName() +
|
||||
" is invalid for opcode " + opcode.name + ". This opcode does not reference an item");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code;
|
||||
|
||||
import org.jf.dexlib.Item;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
public class InstructionWriter {
|
||||
public static void writeInstructions(final byte[] insns, final Item[] referencedItems, final AnnotatedOutput out) {
|
||||
|
||||
InstructionIterator.IterateInstructions(insns, new InstructionIterator.ProcessRawInstructionDelegate() {
|
||||
int itemsPosition = 0;
|
||||
|
||||
public void ProcessNormalInstruction(Opcode opcode, int index) {
|
||||
out.write(insns, index, opcode.format.size);
|
||||
}
|
||||
|
||||
public void ProcessReferenceInstruction(Opcode opcode, int index) {
|
||||
out.write(insns, index, 2);
|
||||
|
||||
if (itemsPosition >= referencedItems.length) {
|
||||
throw new RuntimeException("There are not enough referenced items");
|
||||
}
|
||||
int itemIndex = referencedItems[itemsPosition++].getIndex();
|
||||
if (opcode == Opcode.CONST_STRING_JUMBO) {
|
||||
out.writeInt(itemIndex);
|
||||
} else {
|
||||
if (itemIndex > 0xFFFF) {
|
||||
throw new RuntimeException("The item index does not fit in 2 bytes");
|
||||
}
|
||||
out.writeShort(itemIndex);
|
||||
|
||||
if (opcode.format.size == 6) {
|
||||
out.write(insns, index + 4, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ProcessPackedSwitchInstruction(int index, int targetCount, int instructionLength) {
|
||||
out.write(insns, index, instructionLength);
|
||||
}
|
||||
|
||||
public void ProcessSparseSwitchInstruction(int index, int targetCount, int instructionLength) {
|
||||
out.write(insns, index, instructionLength);
|
||||
}
|
||||
|
||||
public void ProcessFillArrayDataInstruction(int index, int elementWidth, int elementCount, int instructionLength) {
|
||||
out.write(insns, index, instructionLength);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
290
dexlib/src/main/java/org/jf/dexlib/Code/Opcode.java
Normal file
290
dexlib/src/main/java/org/jf/dexlib/Code/Opcode.java
Normal file
@ -0,0 +1,290 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code;
|
||||
|
||||
import org.jf.dexlib.Code.Format.Format;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public enum Opcode
|
||||
{
|
||||
NOP((byte)0x00, "nop", ReferenceType.none, Format.Format10x),
|
||||
MOVE((byte)0x01, "move", ReferenceType.none, Format.Format12x),
|
||||
MOVE_FROM16((byte)0x02, "move/from16", ReferenceType.none, Format.Format22x),
|
||||
MOVE_16((byte)0x03, "move/16", ReferenceType.none, Format.Format32x),
|
||||
MOVE_WIDE((byte)0x04, "move-wide", ReferenceType.none, Format.Format12x),
|
||||
MOVE_WIDE_FROM16((byte)0x05, "move-wide/from16", ReferenceType.none, Format.Format22x),
|
||||
MOVE_WIDE_16((byte)0x06, "move-wide/16", ReferenceType.none, Format.Format32x),
|
||||
MOVE_OBJECT((byte)0x07, "move-object", ReferenceType.none, Format.Format12x),
|
||||
MOVE_OBJECT_FROM16((byte)0x08, "move-object/from16", ReferenceType.none, Format.Format22x),
|
||||
MOVE_OBJECT_16((byte)0x09, "move-object/16", ReferenceType.none, Format.Format32x),
|
||||
MOVE_RESULT((byte)0x0a, "move-result", ReferenceType.none, Format.Format11x),
|
||||
MOVE_RESULT_WIDE((byte)0x0b, "move-result-wide", ReferenceType.none, Format.Format11x),
|
||||
MOVE_RESULT_OBJECT((byte)0x0c, "move-result-object", ReferenceType.none, Format.Format11x),
|
||||
MOVE_EXCEPTION((byte)0x0d, "move-exception", ReferenceType.none, Format.Format11x),
|
||||
RETURN_VOID((byte)0x0e, "return-void", ReferenceType.none, Format.Format10x),
|
||||
RETURN((byte)0x0f, "return", ReferenceType.none, Format.Format11x),
|
||||
RETURN_WIDE((byte)0x10, "return-wide", ReferenceType.none, Format.Format11x),
|
||||
RETURN_OBJECT((byte)0x11, "return-object", ReferenceType.none, Format.Format11x),
|
||||
CONST_4((byte)0x12, "const/4", ReferenceType.none, Format.Format11n),
|
||||
CONST_16((byte)0x13, "const/16", ReferenceType.none, Format.Format21s),
|
||||
CONST((byte)0x14, "const", ReferenceType.none, Format.Format31i),
|
||||
CONST_HIGH16((byte)0x15, "const/high16", ReferenceType.none, Format.Format21h),
|
||||
CONST_WIDE_16((byte)0x16, "const-wide/16", ReferenceType.none, Format.Format21s),
|
||||
CONST_WIDE_32((byte)0x17, "const-wide/32", ReferenceType.none, Format.Format31i),
|
||||
CONST_WIDE((byte)0x18, "const-wide", ReferenceType.none, Format.Format51l),
|
||||
CONST_WIDE_HIGH16((byte)0x19, "const-wide/high16", ReferenceType.none, Format.Format21h),
|
||||
CONST_STRING((byte)0x1a, "const-string", ReferenceType.string, Format.Format21c),
|
||||
CONST_STRING_JUMBO((byte)0x1b, "const-string/jumbo", ReferenceType.string, Format.Format31c),
|
||||
CONST_CLASS((byte)0x1c, "const-class", ReferenceType.type, Format.Format21c),
|
||||
MONITOR_ENTER((byte)0x1d, "monitor-enter", ReferenceType.none, Format.Format11x),
|
||||
MONITOR_EXIT((byte)0x1e, "monitor-exit", ReferenceType.none, Format.Format11x),
|
||||
CHECK_CAST((byte)0x1f, "check-cast", ReferenceType.type, Format.Format21c),
|
||||
INSTANCE_OF((byte)0x20, "instance-of", ReferenceType.type, Format.Format22c),
|
||||
ARRAY_LENGTH((byte)0x21, "array-length", ReferenceType.none, Format.Format12x),
|
||||
NEW_INSTANCE((byte)0x22, "new-instance", ReferenceType.type, Format.Format21c),
|
||||
NEW_ARRAY((byte)0x23, "new-array", ReferenceType.type, Format.Format22c),
|
||||
FILLED_NEW_ARRAY((byte)0x24, "filled-new-array", ReferenceType.type, Format.Format35c),
|
||||
FILLED_NEW_ARRAY_RANGE((byte)0x25, "filled-new-array/range", ReferenceType.type, Format.Format3rc),
|
||||
FILL_ARRAY_DATA((byte)0x26, "fill-array-data", ReferenceType.none, Format.Format31t),
|
||||
THROW((byte)0x27, "throw", ReferenceType.none, Format.Format11x),
|
||||
GOTO((byte)0x28, "goto", ReferenceType.none, Format.Format10t),
|
||||
GOTO_16((byte)0x29, "goto/16", ReferenceType.none, Format.Format20t),
|
||||
GOTO_32((byte)0x2a, "goto/32", ReferenceType.none, Format.Format30t),
|
||||
PACKED_SWITCH((byte)0x2b, "packed-switch", ReferenceType.none, Format.Format31t),
|
||||
SPARSE_SWITCH((byte)0x2c, "sparse-switch", ReferenceType.none, Format.Format31t),
|
||||
CMPL_FLOAT((byte)0x2d, "cmpl-float", ReferenceType.none, Format.Format23x),
|
||||
CMPG_FLOAT((byte)0x2e, "cmpg-float", ReferenceType.none, Format.Format23x),
|
||||
CMPL_DOUBLE((byte)0x2f, "cmpl-double", ReferenceType.none, Format.Format23x),
|
||||
CMPG_DOUBLE((byte)0x30, "cmpg-double", ReferenceType.none, Format.Format23x),
|
||||
CMP_LONG((byte)0x31, "cmp-long", ReferenceType.none, Format.Format23x),
|
||||
IF_EQ((byte)0x32, "if-eq", ReferenceType.none, Format.Format22t),
|
||||
IF_NE((byte)0x33, "if-ne", ReferenceType.none, Format.Format22t),
|
||||
IF_LT((byte)0x34, "if-lt", ReferenceType.none, Format.Format22t),
|
||||
IF_GE((byte)0x35, "if-ge", ReferenceType.none, Format.Format22t),
|
||||
IF_GT((byte)0x36, "if-gt", ReferenceType.none, Format.Format22t),
|
||||
IF_LE((byte)0x37, "if-le", ReferenceType.none, Format.Format22t),
|
||||
IF_EQZ((byte)0x38, "if-eqz", ReferenceType.none, Format.Format21t),
|
||||
IF_NEZ((byte)0x39, "if-nez", ReferenceType.none, Format.Format21t),
|
||||
IF_LTZ((byte)0x3a, "if-ltz", ReferenceType.none, Format.Format21t),
|
||||
IF_GEZ((byte)0x3b, "if-gez", ReferenceType.none, Format.Format21t),
|
||||
IF_GTZ((byte)0x3c, "if-gtz", ReferenceType.none, Format.Format21t),
|
||||
IF_LEZ((byte)0x3d, "if-lez", ReferenceType.none, Format.Format21t),
|
||||
AGET((byte)0x44, "aget", ReferenceType.none, Format.Format23x),
|
||||
AGET_WIDE((byte)0x45, "aget-wide", ReferenceType.none, Format.Format23x),
|
||||
AGET_OBJECT((byte)0x46, "aget-object", ReferenceType.none, Format.Format23x),
|
||||
AGET_BOOLEAN((byte)0x47, "aget-boolean", ReferenceType.none, Format.Format23x),
|
||||
AGET_BYTE((byte)0x48, "aget-byte", ReferenceType.none, Format.Format23x),
|
||||
AGET_CHAR((byte)0x49, "aget-char", ReferenceType.none, Format.Format23x),
|
||||
AGET_SHORT((byte)0x4a, "aget-short", ReferenceType.none, Format.Format23x),
|
||||
APUT((byte)0x4b, "aput", ReferenceType.none, Format.Format23x),
|
||||
APUT_WIDE((byte)0x4c, "aput-wide", ReferenceType.none, Format.Format23x),
|
||||
APUT_OBJECT((byte)0x4d, "aput-object", ReferenceType.none, Format.Format23x),
|
||||
APUT_BOOLEAN((byte)0x4e, "aput-boolean", ReferenceType.none, Format.Format23x),
|
||||
APUT_BYTE((byte)0x4f, "aput-byte", ReferenceType.none, Format.Format23x),
|
||||
APUT_CHAR((byte)0x50, "aput-char", ReferenceType.none, Format.Format23x),
|
||||
APUT_SHORT((byte)0x51, "aput-short", ReferenceType.none, Format.Format23x),
|
||||
IGET((byte)0x52, "iget", ReferenceType.field, Format.Format22c),
|
||||
IGET_WIDE((byte)0x53, "iget-wide", ReferenceType.field, Format.Format22c),
|
||||
IGET_OBJECT((byte)0x54, "iget-object", ReferenceType.field, Format.Format22c),
|
||||
IGET_BOOLEAN((byte)0x55, "iget-boolean", ReferenceType.field, Format.Format22c),
|
||||
IGET_BYTE((byte)0x56, "iget-byte", ReferenceType.field, Format.Format22c),
|
||||
IGET_CHAR((byte)0x57, "iget-char", ReferenceType.field, Format.Format22c),
|
||||
IGET_SHORT((byte)0x58, "iget-short", ReferenceType.field, Format.Format22c),
|
||||
IPUT((byte)0x59, "iput", ReferenceType.field, Format.Format22c),
|
||||
IPUT_WIDE((byte)0x5a, "iput-wide", ReferenceType.field, Format.Format22c),
|
||||
IPUT_OBJECT((byte)0x5b, "iput-object", ReferenceType.field, Format.Format22c),
|
||||
IPUT_BOOLEAN((byte)0x5c, "iput-boolean", ReferenceType.field, Format.Format22c),
|
||||
IPUT_BYTE((byte)0x5d, "iput-byte", ReferenceType.field, Format.Format22c),
|
||||
IPUT_CHAR((byte)0x5e, "iput-char", ReferenceType.field, Format.Format22c),
|
||||
IPUT_SHORT((byte)0x5f, "iput-short", ReferenceType.field, Format.Format22c),
|
||||
SGET((byte)0x60, "sget", ReferenceType.field, Format.Format21c),
|
||||
SGET_WIDE((byte)0x61, "sget-wide", ReferenceType.field, Format.Format21c),
|
||||
SGET_OBJECT((byte)0x62, "sget-object", ReferenceType.field, Format.Format21c),
|
||||
SGET_BOOLEAN((byte)0x63, "sget-boolean", ReferenceType.field, Format.Format21c),
|
||||
SGET_BYTE((byte)0x64, "sget-byte", ReferenceType.field, Format.Format21c),
|
||||
SGET_CHAR((byte)0x65, "sget-char", ReferenceType.field, Format.Format21c),
|
||||
SGET_SHORT((byte)0x66, "sget-short", ReferenceType.field, Format.Format21c),
|
||||
SPUT((byte)0x67, "sput", ReferenceType.field, Format.Format21c),
|
||||
SPUT_WIDE((byte)0x68, "sput-wide", ReferenceType.field, Format.Format21c),
|
||||
SPUT_OBJECT((byte)0x69, "sput-object", ReferenceType.field, Format.Format21c),
|
||||
SPUT_BOOLEAN((byte)0x6a, "sput-boolean", ReferenceType.field, Format.Format21c),
|
||||
SPUT_BYTE((byte)0x6b, "sput-byte", ReferenceType.field, Format.Format21c),
|
||||
SPUT_CHAR((byte)0x6c, "sput-char", ReferenceType.field, Format.Format21c),
|
||||
SPUT_SHORT((byte)0x6d, "sput-short", ReferenceType.field, Format.Format21c),
|
||||
INVOKE_VIRTUAL((byte)0x6e, "invoke-virtual", ReferenceType.method, Format.Format35c),
|
||||
INVOKE_SUPER((byte)0x6f, "invoke-super", ReferenceType.method, Format.Format35c),
|
||||
INVOKE_DIRECT((byte)0x70, "invoke-direct", ReferenceType.method, Format.Format35c),
|
||||
INVOKE_STATIC((byte)0x71, "invoke-static", ReferenceType.method, Format.Format35c),
|
||||
INVOKE_INTERFACE((byte)0x72, "invoke-interface", ReferenceType.method, Format.Format35c),
|
||||
INVOKE_VIRTUAL_RANGE((byte)0x74, "invoke-virtual/range", ReferenceType.method, Format.Format3rc),
|
||||
INVOKE_SUPER_RANGE((byte)0x75, "invoke-super/range", ReferenceType.method, Format.Format3rc),
|
||||
INVOKE_DIRECT_RANGE((byte)0x76, "invoke-direct/range", ReferenceType.method, Format.Format3rc),
|
||||
INVOKE_STATIC_RANGE((byte)0x77, "invoke-static/range", ReferenceType.method, Format.Format3rc),
|
||||
INVOKE_INTERFACE_RANGE((byte)0x78, "invoke-interface/range", ReferenceType.method, Format.Format3rc),
|
||||
NEG_INT((byte)0x7b, "neg-int", ReferenceType.none, Format.Format12x),
|
||||
NOT_INT((byte)0x7c, "not-int", ReferenceType.none, Format.Format12x),
|
||||
NEG_LONG((byte)0x7d, "neg-long", ReferenceType.none, Format.Format12x),
|
||||
NOT_LONG((byte)0x7e, "not-long", ReferenceType.none, Format.Format12x),
|
||||
NEG_FLOAT((byte)0x7f, "neg-float", ReferenceType.none, Format.Format12x),
|
||||
NEG_DOUBLE((byte)0x80, "neg-double", ReferenceType.none, Format.Format12x),
|
||||
INT_TO_LONG((byte)0x81, "int-to-long", ReferenceType.none, Format.Format12x),
|
||||
INT_TO_FLOAT((byte)0x82, "int-to-float", ReferenceType.none, Format.Format12x),
|
||||
INT_TO_DOUBLE((byte)0x83, "int-to-double", ReferenceType.none, Format.Format12x),
|
||||
LONG_TO_INT((byte)0x84, "long-to-int", ReferenceType.none, Format.Format12x),
|
||||
LONG_TO_FLOAT((byte)0x85, "long-to-float", ReferenceType.none, Format.Format12x),
|
||||
LONG_TO_DOUBLE((byte)0x86, "long-to-double", ReferenceType.none, Format.Format12x),
|
||||
FLOAT_TO_INT((byte)0x87, "float-to-int", ReferenceType.none, Format.Format12x),
|
||||
FLOAT_TO_LONG((byte)0x88, "float-to-long", ReferenceType.none, Format.Format12x),
|
||||
FLOAT_TO_DOUBLE((byte)0x89, "float-to-double", ReferenceType.none, Format.Format12x),
|
||||
DOUBLE_TO_INT((byte)0x8a, "double-to-int", ReferenceType.none, Format.Format12x),
|
||||
DOUBLE_TO_LONG((byte)0x8b, "double-to-long", ReferenceType.none, Format.Format12x),
|
||||
DOUBLE_TO_FLOAT((byte)0x8c, "double-to-float", ReferenceType.none, Format.Format12x),
|
||||
INT_TO_BYTE((byte)0x8d, "int-to-byte", ReferenceType.none, Format.Format12x),
|
||||
INT_TO_CHAR((byte)0x8e, "int-to-char", ReferenceType.none, Format.Format12x),
|
||||
INT_TO_SHORT((byte)0x8f, "int-to-short", ReferenceType.none, Format.Format12x),
|
||||
ADD_INT((byte)0x90, "add-int", ReferenceType.none, Format.Format23x),
|
||||
SUB_INT((byte)0x91, "sub-int", ReferenceType.none, Format.Format23x),
|
||||
MUL_INT((byte)0x92, "mul-int", ReferenceType.none, Format.Format23x),
|
||||
DIV_INT((byte)0x93, "div-int", ReferenceType.none, Format.Format23x),
|
||||
REM_INT((byte)0x94, "rem-int", ReferenceType.none, Format.Format23x),
|
||||
AND_INT((byte)0x95, "and-int", ReferenceType.none, Format.Format23x),
|
||||
OR_INT((byte)0x96, "or-int", ReferenceType.none, Format.Format23x),
|
||||
XOR_INT((byte)0x97, "xor-int", ReferenceType.none, Format.Format23x),
|
||||
SHL_INT((byte)0x98, "shl-int", ReferenceType.none, Format.Format23x),
|
||||
SHR_INT((byte)0x99, "shr-int", ReferenceType.none, Format.Format23x),
|
||||
USHR_INT((byte)0x9a, "ushr-int", ReferenceType.none, Format.Format23x),
|
||||
ADD_LONG((byte)0x9b, "add-long", ReferenceType.none, Format.Format23x),
|
||||
SUB_LONG((byte)0x9c, "sub-long", ReferenceType.none, Format.Format23x),
|
||||
MUL_LONG((byte)0x9d, "mul-long", ReferenceType.none, Format.Format23x),
|
||||
DIV_LONG((byte)0x9e, "div-long", ReferenceType.none, Format.Format23x),
|
||||
REM_LONG((byte)0x9f, "rem-long", ReferenceType.none, Format.Format23x),
|
||||
AND_LONG((byte)0xa0, "and-long", ReferenceType.none, Format.Format23x),
|
||||
OR_LONG((byte)0xa1, "or-long", ReferenceType.none, Format.Format23x),
|
||||
XOR_LONG((byte)0xa2, "xor-long", ReferenceType.none, Format.Format23x),
|
||||
SHL_LONG((byte)0xa3, "shl-long", ReferenceType.none, Format.Format23x),
|
||||
SHR_LONG((byte)0xa4, "shr-long", ReferenceType.none, Format.Format23x),
|
||||
USHR_LONG((byte)0xa5, "ushr-long", ReferenceType.none, Format.Format23x),
|
||||
ADD_FLOAT((byte)0xa6, "add-float", ReferenceType.none, Format.Format23x),
|
||||
SUB_FLOAT((byte)0xa7, "sub-float", ReferenceType.none, Format.Format23x),
|
||||
MUL_FLOAT((byte)0xa8, "mul-float", ReferenceType.none, Format.Format23x),
|
||||
DIV_FLOAT((byte)0xa9, "div-float", ReferenceType.none, Format.Format23x),
|
||||
REM_FLOAT((byte)0xaa, "rem-float", ReferenceType.none, Format.Format23x),
|
||||
ADD_DOUBLE((byte)0xab, "add-double", ReferenceType.none, Format.Format23x),
|
||||
SUB_DOUBLE((byte)0xac, "sub-double", ReferenceType.none, Format.Format23x),
|
||||
MUL_DOUBLE((byte)0xad, "mul-double", ReferenceType.none, Format.Format23x),
|
||||
DIV_DOUBLE((byte)0xae, "div-double", ReferenceType.none, Format.Format23x),
|
||||
REM_DOUBLE((byte)0xaf, "rem-double", ReferenceType.none, Format.Format23x),
|
||||
ADD_INT_2ADDR((byte)0xb0, "add-int/2addr", ReferenceType.none, Format.Format12x),
|
||||
SUB_INT_2ADDR((byte)0xb1, "sub-int/2addr", ReferenceType.none, Format.Format12x),
|
||||
MUL_INT_2ADDR((byte)0xb2, "mul-int/2addr", ReferenceType.none, Format.Format12x),
|
||||
DIV_INT_2ADDR((byte)0xb3, "div-int/2addr", ReferenceType.none, Format.Format12x),
|
||||
REM_INT_2ADDR((byte)0xb4, "rem-int/2addr", ReferenceType.none, Format.Format12x),
|
||||
AND_INT_2ADDR((byte)0xb5, "and-int/2addr", ReferenceType.none, Format.Format12x),
|
||||
OR_INT_2ADDR((byte)0xb6, "or-int/2addr", ReferenceType.none, Format.Format12x),
|
||||
XOR_INT_2ADDR((byte)0xb7, "xor-int/2addr", ReferenceType.none, Format.Format12x),
|
||||
SHL_INT_2ADDR((byte)0xb8, "shl-int/2addr", ReferenceType.none, Format.Format12x),
|
||||
SHR_INT_2ADDR((byte)0xb9, "shr-int/2addr", ReferenceType.none, Format.Format12x),
|
||||
USHR_INT_2ADDR((byte)0xba, "ushr-int/2addr", ReferenceType.none, Format.Format12x),
|
||||
ADD_LONG_2ADDR((byte)0xbb, "add-long/2addr", ReferenceType.none, Format.Format12x),
|
||||
SUB_LONG_2ADDR((byte)0xbc, "sub-long/2addr", ReferenceType.none, Format.Format12x),
|
||||
MUL_LONG_2ADDR((byte)0xbd, "mul-long/2addr", ReferenceType.none, Format.Format12x),
|
||||
DIV_LONG_2ADDR((byte)0xbe, "div-long/2addr", ReferenceType.none, Format.Format12x),
|
||||
REM_LONG_2ADDR((byte)0xbf, "rem-long/2addr", ReferenceType.none, Format.Format12x),
|
||||
AND_LONG_2ADDR((byte)0xc0, "and-long/2addr", ReferenceType.none, Format.Format12x),
|
||||
OR_LONG_2ADDR((byte)0xc1, "or-long/2addr", ReferenceType.none, Format.Format12x),
|
||||
XOR_LONG_2ADDR((byte)0xc2, "xor-long/2addr", ReferenceType.none, Format.Format12x),
|
||||
SHL_LONG_2ADDR((byte)0xc3, "shl-long/2addr", ReferenceType.none, Format.Format12x),
|
||||
SHR_LONG_2ADDR((byte)0xc4, "shr-long/2addr", ReferenceType.none, Format.Format12x),
|
||||
USHR_LONG_2ADDR((byte)0xc5, "ushr-long/2addr", ReferenceType.none, Format.Format12x),
|
||||
ADD_FLOAT_2ADDR((byte)0xc6, "add-float/2addr", ReferenceType.none, Format.Format12x),
|
||||
SUB_FLOAT_2ADDR((byte)0xc7, "sub-float/2addr", ReferenceType.none, Format.Format12x),
|
||||
MUL_FLOAT_2ADDR((byte)0xc8, "mul-float/2addr", ReferenceType.none, Format.Format12x),
|
||||
DIV_FLOAT_2ADDR((byte)0xc9, "div-float/2addr", ReferenceType.none, Format.Format12x),
|
||||
REM_FLOAT_2ADDR((byte)0xca, "rem-float/2addr", ReferenceType.none, Format.Format12x),
|
||||
ADD_DOUBLE_2ADDR((byte)0xcb, "add-double/2addr", ReferenceType.none, Format.Format12x),
|
||||
SUB_DOUBLE_2ADDR((byte)0xcc, "sub-double/2addr", ReferenceType.none, Format.Format12x),
|
||||
MUL_DOUBLE_2ADDR((byte)0xcd, "mul-double/2addr", ReferenceType.none, Format.Format12x),
|
||||
DIV_DOUBLE_2ADDR((byte)0xce, "div-double/2addr", ReferenceType.none, Format.Format12x),
|
||||
REM_DOUBLE_2ADDR((byte)0xcf, "rem-double/2addr", ReferenceType.none, Format.Format12x),
|
||||
ADD_INT_LIT16((byte)0xd0, "add-int/lit16", ReferenceType.none, Format.Format22s),
|
||||
RSUB_INT((byte)0xd1, "rsub-int", ReferenceType.none, Format.Format22s),
|
||||
MUL_INT_LIT16((byte)0xd2, "mul-int/lit16", ReferenceType.none, Format.Format22s),
|
||||
DIV_INT_LIT16((byte)0xd3, "div-int/lit16", ReferenceType.none, Format.Format22s),
|
||||
REM_INT_LIT16((byte)0xd4, "rem-int/lit16", ReferenceType.none, Format.Format22s),
|
||||
AND_INT_LIT16((byte)0xd5, "and-int/lit16", ReferenceType.none, Format.Format22s),
|
||||
OR_INT_LIT16((byte)0xd6, "or-int/lit16", ReferenceType.none, Format.Format22s),
|
||||
XOR_INT_LIT16((byte)0xd7, "xor-int/lit16", ReferenceType.none, Format.Format22s),
|
||||
ADD_INT_LIT8((byte)0xd8, "add-int/lit8", ReferenceType.none, Format.Format22b),
|
||||
RSUB_INT_LIT8((byte)0xd9, "rsub-int/lit8", ReferenceType.none, Format.Format22b),
|
||||
MUL_INT_LIT8((byte)0xda, "mul-int/lit8", ReferenceType.none, Format.Format22b),
|
||||
DIV_INT_LIT8((byte)0xdb, "div-int/lit8", ReferenceType.none, Format.Format22b),
|
||||
REM_INT_LIT8((byte)0xdc, "rem-int/lit8", ReferenceType.none, Format.Format22b),
|
||||
AND_INT_LIT8((byte)0xdd, "and-int/lit8", ReferenceType.none, Format.Format22b),
|
||||
OR_INT_LIT8((byte)0xde, "or-int/lit8", ReferenceType.none, Format.Format22b),
|
||||
XOR_INT_LIT8((byte)0xdf, "xor-int/lit8", ReferenceType.none, Format.Format22b),
|
||||
SHL_INT_LIT8((byte)0xe0, "shl-int/lit8", ReferenceType.none, Format.Format22b),
|
||||
SHR_INT_LIT8((byte)0xe1, "shr-int/lit8", ReferenceType.none, Format.Format22b),
|
||||
USHR_INT_LIT8((byte)0xe2, "ushr-int/lit8", ReferenceType.none, Format.Format22b);
|
||||
|
||||
|
||||
|
||||
private static Opcode[] opcodesByValue;
|
||||
private static HashMap<Integer, Opcode> opcodesByName;
|
||||
|
||||
static {
|
||||
opcodesByValue = new Opcode[256];
|
||||
opcodesByName = new HashMap<Integer, Opcode>();
|
||||
|
||||
for (Opcode opcode: Opcode.values()) {
|
||||
opcodesByValue[opcode.value & 0xFF] = opcode;
|
||||
opcodesByName.put(opcode.name.hashCode(), opcode);
|
||||
}
|
||||
}
|
||||
|
||||
public static Opcode getOpcodeByName(String opcodeName) {
|
||||
return opcodesByName.get(opcodeName.toLowerCase().hashCode());
|
||||
}
|
||||
|
||||
public static Opcode getOpcodeByValue(byte opcodeValue) {
|
||||
return opcodesByValue[opcodeValue & 0xFF];
|
||||
}
|
||||
|
||||
public final byte value;
|
||||
public final String name;
|
||||
public final ReferenceType referenceType;
|
||||
public final Format format;
|
||||
|
||||
Opcode(byte opcodeValue, String opcodeName, ReferenceType referenceType, Format format) {
|
||||
this.value = opcodeValue;
|
||||
this.name = opcodeName;
|
||||
this.referenceType = referenceType;
|
||||
this.format = format;
|
||||
}
|
||||
}
|
56
dexlib/src/main/java/org/jf/dexlib/Code/ReferenceType.java
Normal file
56
dexlib/src/main/java/org/jf/dexlib/Code/ReferenceType.java
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Code;
|
||||
|
||||
import org.jf.dexlib.*;
|
||||
|
||||
public enum ReferenceType
|
||||
{
|
||||
string,
|
||||
type,
|
||||
field,
|
||||
method,
|
||||
none;
|
||||
|
||||
public boolean checkItem(Item item) {
|
||||
switch (this) {
|
||||
case string:
|
||||
return item instanceof StringIdItem;
|
||||
case type:
|
||||
return item instanceof TypeIdItem;
|
||||
case field:
|
||||
return item instanceof FieldIdItem;
|
||||
case method:
|
||||
return item instanceof MethodIdItem;
|
||||
case none:
|
||||
return item == null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
562
dexlib/src/main/java/org/jf/dexlib/CodeItem.java
Normal file
562
dexlib/src/main/java/org/jf/dexlib/CodeItem.java
Normal file
@ -0,0 +1,562 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.Code.InstructionReader;
|
||||
import org.jf.dexlib.Code.InstructionIterator;
|
||||
import org.jf.dexlib.Code.Opcode;
|
||||
import org.jf.dexlib.Code.InstructionWriter;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.SparseArray;
|
||||
import org.jf.dexlib.Util.Leb128Utils;
|
||||
|
||||
public class CodeItem extends Item<CodeItem> {
|
||||
private int registerCount;
|
||||
private int inWords;
|
||||
private int outWords;
|
||||
private DebugInfoItem debugInfo;
|
||||
private byte[] encodedInstructions;
|
||||
private Item[] referencedItems;
|
||||
private TryItem[] tries;
|
||||
private EncodedCatchHandler[] encodedCatchHandlers;
|
||||
|
||||
private MethodIdItem parent;
|
||||
|
||||
/**
|
||||
* Creates a new uninitialized <code>CodeItem</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
*/
|
||||
public CodeItem(DexFile dexFile) {
|
||||
super(dexFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>CodeItem</code> with the given values.
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param registerCount the number of registers that the method containing this code uses
|
||||
* @param inWords the number of 2-byte words that the parameters to the method containing this code take
|
||||
* @param outWords the maximum number of 2-byte words for the arguments of any method call in this code
|
||||
* @param debugInfo the debug information for this code/method
|
||||
* @param encodedInstructions the instructions, encoded as a byte array
|
||||
* @param referencedItems an array of the items referenced by instructions, in order of occurance in the code
|
||||
* @param tries an array of the tries defined for this code/method
|
||||
* @param encodedCatchHandlers an array of the exception handlers defined for this code/method
|
||||
*/
|
||||
private CodeItem(DexFile dexFile,
|
||||
int registerCount,
|
||||
int inWords,
|
||||
int outWords,
|
||||
DebugInfoItem debugInfo,
|
||||
byte[] encodedInstructions,
|
||||
Item[] referencedItems,
|
||||
TryItem[] tries,
|
||||
EncodedCatchHandler[] encodedCatchHandlers) {
|
||||
super(dexFile);
|
||||
|
||||
this.registerCount = registerCount;
|
||||
this.inWords = inWords;
|
||||
this.outWords = outWords;
|
||||
this.debugInfo = debugInfo;
|
||||
if (debugInfo != null) {
|
||||
debugInfo.setParent(this);
|
||||
}
|
||||
this.encodedInstructions = encodedInstructions;
|
||||
this.referencedItems = referencedItems;
|
||||
this.tries = tries;
|
||||
this.encodedCatchHandlers = encodedCatchHandlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new <code>CodeItem</code> with the given values.
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param registerCount the number of registers that the method containing this code uses
|
||||
* @param inWords the number of 2-byte words that the parameters to the method containing this code take
|
||||
* @param outWords the maximum number of 2-byte words for the arguments of any method call in this code
|
||||
* @param debugInfo the debug information for this code/method
|
||||
* @param encodedInstructions the instructions, encoded as a byte array
|
||||
* @param referencedItems an array of the items referenced by instructions, in order of occurance in the code
|
||||
* @param tries an array of the tries defined for this code/method
|
||||
* @param encodedCatchHandlers an array of the exception handlers defined for this code/method
|
||||
* @return a new <code>CodeItem</code> with the given values.
|
||||
*/
|
||||
public static CodeItem getInternedCodeItem(DexFile dexFile,
|
||||
int registerCount,
|
||||
int inWords,
|
||||
int outWords,
|
||||
DebugInfoItem debugInfo,
|
||||
byte[] encodedInstructions,
|
||||
Item[] referencedItems,
|
||||
TryItem[] tries,
|
||||
EncodedCatchHandler[] encodedCatchHandlers) {
|
||||
CodeItem codeItem = new CodeItem(dexFile, registerCount, inWords, outWords, debugInfo, encodedInstructions,
|
||||
referencedItems, tries, encodedCatchHandlers);
|
||||
return dexFile.CodeItemsSection.intern(codeItem);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void readItem(Input in, ReadContext readContext) {
|
||||
this.registerCount = in.readShort();
|
||||
this.inWords = in.readShort();
|
||||
this.outWords = in.readShort();
|
||||
int triesCount = in.readShort();
|
||||
this.debugInfo = (DebugInfoItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_DEBUG_INFO_ITEM,
|
||||
in.readInt());
|
||||
if (this.debugInfo != null) {
|
||||
this.debugInfo.setParent(this);
|
||||
}
|
||||
int instructionCount = in.readInt();
|
||||
this.encodedInstructions = in.readBytes(instructionCount * 2);
|
||||
this.referencedItems = InstructionReader.getReferencedItems(encodedInstructions, dexFile);
|
||||
if (triesCount > 0) {
|
||||
in.alignTo(4);
|
||||
|
||||
//we need to read in the catch handlers first, so save the offset to the try items for future reference
|
||||
int triesOffset = in.getCursor();
|
||||
in.setCursor(triesOffset + 8 * triesCount);
|
||||
|
||||
//read in the encoded catch handlers
|
||||
int encodedHandlerStart = in.getCursor();
|
||||
int handlerCount = in.readUnsignedLeb128();
|
||||
SparseArray<EncodedCatchHandler> handlerMap = new SparseArray<EncodedCatchHandler>(handlerCount);
|
||||
encodedCatchHandlers = new EncodedCatchHandler[handlerCount];
|
||||
for (int i=0; i<handlerCount; i++) {
|
||||
int position = in.getCursor() - encodedHandlerStart;
|
||||
encodedCatchHandlers[i] = new EncodedCatchHandler(dexFile, in);
|
||||
handlerMap.append(position, encodedCatchHandlers[i]);
|
||||
}
|
||||
int codeItemEnd = in.getCursor();
|
||||
|
||||
//now go back and read the tries
|
||||
in.setCursor(triesOffset);
|
||||
tries = new TryItem[triesCount];
|
||||
for (int i=0; i<triesCount; i++) {
|
||||
tries[i] = new TryItem(in, handlerMap);
|
||||
}
|
||||
|
||||
//and now back to the end of the code item
|
||||
in.setCursor(codeItemEnd);
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int placeItem(int offset) {
|
||||
offset += 16 + encodedInstructions.length;
|
||||
if (tries != null && tries.length > 0) {
|
||||
if (encodedInstructions.length % 2 == 1) {
|
||||
offset++;
|
||||
}
|
||||
|
||||
offset += tries.length * 8;
|
||||
int encodedCatchHandlerBaseOffset = offset;
|
||||
for (EncodedCatchHandler encodedCatchHandler: encodedCatchHandlers) {
|
||||
offset += encodedCatchHandler.place(offset, encodedCatchHandlerBaseOffset);
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void writeItem(final AnnotatedOutput out) {
|
||||
if (out.annotates()) {
|
||||
out.annotate(2, "registers_size");
|
||||
out.annotate(2, "ins_size");
|
||||
out.annotate(2, "outs_size");
|
||||
out.annotate(2, "tries_size");
|
||||
out.annotate(4, "debug_info_off");
|
||||
out.annotate(4, "insns_size");
|
||||
InstructionIterator.IterateInstructions(encodedInstructions,
|
||||
new InstructionIterator.ProcessRawInstructionDelegate() {
|
||||
|
||||
public void ProcessNormalInstruction(Opcode opcode, int index) {
|
||||
out.annotate(opcode.format.size, opcode.name + " instruction");
|
||||
}
|
||||
|
||||
public void ProcessReferenceInstruction(Opcode opcode, int index) {
|
||||
out.annotate(opcode.format.size, opcode.name + " instruction");
|
||||
}
|
||||
|
||||
public void ProcessPackedSwitchInstruction(int index, int targetCount, int instructionLength) {
|
||||
out.annotate(instructionLength, "packed_switch instruction");
|
||||
}
|
||||
|
||||
public void ProcessSparseSwitchInstruction(int index, int targetCount, int instructionLength) {
|
||||
out.annotate(instructionLength, "sparse_switch instruction");
|
||||
}
|
||||
|
||||
public void ProcessFillArrayDataInstruction(int index, int elementWidth, int elementCount, int instructionLength) {
|
||||
out.annotate(instructionLength, "fill_array_data instruction");
|
||||
}
|
||||
});
|
||||
if (tries != null && (tries.length % 2 == 1)) {
|
||||
out.annotate(2, "padding");
|
||||
}
|
||||
}
|
||||
|
||||
out.writeShort(registerCount);
|
||||
out.writeShort(inWords);
|
||||
out.writeShort(outWords);
|
||||
if (tries == null) {
|
||||
out.writeShort(0);
|
||||
} else {
|
||||
out.writeShort(tries.length);
|
||||
}
|
||||
if (debugInfo == null) {
|
||||
out.writeInt(0);
|
||||
} else {
|
||||
out.writeInt(debugInfo.getIndex());
|
||||
}
|
||||
out.writeInt(encodedInstructions.length / 2);
|
||||
InstructionWriter.writeInstructions(encodedInstructions, referencedItems, out);
|
||||
|
||||
if (tries != null && tries.length > 0) {
|
||||
if ((tries.length % 2) == 1) {
|
||||
out.writeShort(0);
|
||||
}
|
||||
|
||||
for (TryItem tryItem: tries) {
|
||||
tryItem.writeTo(out);
|
||||
}
|
||||
|
||||
out.writeUnsignedLeb128(encodedCatchHandlers.length);
|
||||
|
||||
for (EncodedCatchHandler encodedCatchHandler: encodedCatchHandlers) {
|
||||
encodedCatchHandler.writeTo(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_CODE_ITEM;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String getConciseIdentity() {
|
||||
//TODO: should mention the method name here
|
||||
return "code_item @0x" + Integer.toHexString(getOffset());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int compareTo(CodeItem other) {
|
||||
if (parent == null) {
|
||||
if (other.parent == null) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (other.parent == null) {
|
||||
return 1;
|
||||
}
|
||||
return parent.compareTo(other.parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the register count
|
||||
*/
|
||||
public int getRegisterCount() {
|
||||
return registerCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a byte array containing the encoded instructions
|
||||
*/
|
||||
public byte[] getEncodedInstructions() {
|
||||
return encodedInstructions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an array of the <code>TryItem</code> objects in this <code>CodeItem</code>
|
||||
*/
|
||||
public TryItem[] getTries() {
|
||||
return tries;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the <code>DebugInfoItem</code> associated with this <code>CodeItem</code>
|
||||
*/
|
||||
public DebugInfoItem getDebugInfo() {
|
||||
return debugInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the <code>MethodIdItem</code> of the method that this <code>CodeItem</code> is associated with
|
||||
* @param methodIdItem the <code>MethodIdItem</code> of the method that this <code>CodeItem</code> is associated
|
||||
* with
|
||||
*/
|
||||
protected void setParent(MethodIdItem methodIdItem) {
|
||||
this.parent = methodIdItem;
|
||||
}
|
||||
|
||||
public static class TryItem {
|
||||
/**
|
||||
* The address (in 2-byte words) within the code where the try block starts
|
||||
*/
|
||||
public final int startAddress;
|
||||
|
||||
/**
|
||||
* The number of 2-byte words that the try block covers
|
||||
*/
|
||||
public final int instructionCount;
|
||||
|
||||
/**
|
||||
* The associated exception handler
|
||||
*/
|
||||
public final EncodedCatchHandler encodedCatchHandler;
|
||||
|
||||
/**
|
||||
* Construct a new <code>TryItem</code> with the given values
|
||||
* @param startAddress the address (in 2-byte words) within the code where the try block starts
|
||||
* @param instructionCount the number of 2-byte words that the try block covers
|
||||
* @param encodedCatchHandler the associated exception handler
|
||||
*/
|
||||
public TryItem(int startAddress, int instructionCount, EncodedCatchHandler encodedCatchHandler) {
|
||||
this.startAddress = startAddress;
|
||||
this.instructionCount = instructionCount;
|
||||
this.encodedCatchHandler = encodedCatchHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used internally to construct a new <code>TryItem</code> while reading in a <code>DexFile</code>
|
||||
* @param in the Input object to read the <code>TryItem</code> from
|
||||
* @param encodedCatchHandlers a SparseArray of the EncodedCatchHandlers for this <code>CodeItem</code>. The
|
||||
* key should be the offset of the EncodedCatchHandler from the beginning of the encoded_catch_handler_list
|
||||
* structure.
|
||||
*/
|
||||
private TryItem(Input in, SparseArray<EncodedCatchHandler> encodedCatchHandlers) {
|
||||
startAddress = in.readInt();
|
||||
instructionCount = in.readShort();
|
||||
|
||||
encodedCatchHandler = encodedCatchHandlers.get(in.readShort());
|
||||
if (encodedCatchHandler == null) {
|
||||
throw new RuntimeException("Could not find the EncodedCatchHandler referenced by this TryItem");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the <code>TryItem</code> to the given <code>AnnotatedOutput</code> object
|
||||
* @param out the <code>AnnotatedOutput</code> object to write to
|
||||
*/
|
||||
private void writeTo(AnnotatedOutput out) {
|
||||
if (out.annotates()) {
|
||||
out.annotate(4, "start_addr");
|
||||
out.annotate(2, "insn_count");
|
||||
out.annotate(2, "handler_off");
|
||||
}
|
||||
|
||||
out.writeInt(startAddress);
|
||||
out.writeShort(instructionCount);
|
||||
out.writeShort(encodedCatchHandler.getOffsetInList());
|
||||
}
|
||||
}
|
||||
|
||||
public static class EncodedCatchHandler {
|
||||
/**
|
||||
* An array of the individual exception handlers
|
||||
*/
|
||||
public final EncodedTypeAddrPair[] handlers;
|
||||
|
||||
/**
|
||||
* The address within the code (in 2-byte words) for the catch all handler, or -1 if there is no catch all
|
||||
* handler
|
||||
*/
|
||||
public final int catchAllHandlerAddress;
|
||||
|
||||
//TODO: would it be possible to get away without having these? and generate/create these values while writing?
|
||||
private int baseOffset;
|
||||
private int offset;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>EncodedCatchHandler</code> with the given values
|
||||
* @param handlers an array of the individual exception handlers
|
||||
* @param catchAllHandlerAddress The address within the code (in 2-byte words) for the catch all handler, or -1
|
||||
* if there is no catch all handler
|
||||
*/
|
||||
public EncodedCatchHandler(EncodedTypeAddrPair[] handlers, int catchAllHandlerAddress) {
|
||||
this.handlers = handlers;
|
||||
this.catchAllHandlerAddress = catchAllHandlerAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used internally to construct a new <code>EncodedCatchHandler</code> while reading in a
|
||||
* <code>DexFile</code>
|
||||
* @param dexFile the <code>DexFile</code> that is being read in
|
||||
* @param in the Input object to read the <code>EncodedCatchHandler</code> from
|
||||
*/
|
||||
private EncodedCatchHandler(DexFile dexFile, Input in) {
|
||||
int handlerCount = in.readSignedLeb128();
|
||||
|
||||
if (handlerCount < 0) {
|
||||
handlers = new EncodedTypeAddrPair[-1 * handlerCount];
|
||||
} else {
|
||||
handlers = new EncodedTypeAddrPair[handlerCount];
|
||||
}
|
||||
|
||||
for (int i=0; i<handlers.length; i++) {
|
||||
handlers[i] = new EncodedTypeAddrPair(dexFile, in);
|
||||
}
|
||||
|
||||
if (handlerCount <= 0) {
|
||||
catchAllHandlerAddress = in.readUnsignedLeb128();
|
||||
} else {
|
||||
catchAllHandlerAddress = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the offset of this <code>EncodedCatchHandler</code> from the beginning of the
|
||||
* encoded_catch_handler_list structure
|
||||
*/
|
||||
private int getOffsetInList() {
|
||||
return offset-baseOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Places the <code>EncodedCatchHandler</code>, storing the offset and baseOffset, and returning the offset
|
||||
* immediately following this <code>EncodedCatchHandler</code>
|
||||
* @param offset the offset of this <code>EncodedCatchHandler</code> in the <code>DexFile</code>
|
||||
* @param baseOffset the offset of the beginning of the encoded_catch_handler_list structure in the
|
||||
* <code>DexFile</code>
|
||||
* @return the offset immediately following this <code>EncodedCatchHandler</code>
|
||||
*/
|
||||
private int place(int offset, int baseOffset) {
|
||||
this.offset = offset;
|
||||
this.baseOffset = baseOffset;
|
||||
|
||||
int size = handlers.length;
|
||||
if (catchAllHandlerAddress > -1) {
|
||||
size *= -1;
|
||||
offset += Leb128Utils.unsignedLeb128Size(catchAllHandlerAddress);
|
||||
}
|
||||
offset += Leb128Utils.signedLeb128Size(size);
|
||||
|
||||
for (EncodedTypeAddrPair handler: handlers) {
|
||||
offset += handler.getSize();
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the <code>EncodedCatchHandler</code> to the given <code>AnnotatedOutput</code> object
|
||||
* @param out the <code>AnnotatedOutput</code> object to write to
|
||||
*/
|
||||
private void writeTo(AnnotatedOutput out) {
|
||||
if (out.annotates()) {
|
||||
out.annotate("size");
|
||||
|
||||
int size = handlers.length;
|
||||
if (catchAllHandlerAddress < 0) {
|
||||
size = size * -1;
|
||||
}
|
||||
out.writeSignedLeb128(size);
|
||||
|
||||
for (EncodedTypeAddrPair handler: handlers) {
|
||||
handler.writeTo(out);
|
||||
}
|
||||
|
||||
if (catchAllHandlerAddress > -1) {
|
||||
out.annotate("catch_all_addr");
|
||||
out.writeUnsignedLeb128(catchAllHandlerAddress);
|
||||
}
|
||||
} else {
|
||||
int size = handlers.length;
|
||||
if (catchAllHandlerAddress < 0) {
|
||||
size = size * -1;
|
||||
}
|
||||
out.writeSignedLeb128(size);
|
||||
|
||||
for (EncodedTypeAddrPair handler: handlers) {
|
||||
handler.writeTo(out);
|
||||
}
|
||||
|
||||
if (catchAllHandlerAddress > -1) {
|
||||
out.writeUnsignedLeb128(catchAllHandlerAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class EncodedTypeAddrPair {
|
||||
/**
|
||||
* The type of the <code>Exception</code> that this handler handles
|
||||
*/
|
||||
public final TypeIdItem exceptionType;
|
||||
|
||||
/**
|
||||
* The address (in 2-byte words) in the code of the handler
|
||||
*/
|
||||
public final int handlerAddress;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>EncodedTypeAddrPair</code> with the given values
|
||||
* @param exceptionType the type of the <code>Exception</code> that this handler handles
|
||||
* @param handlerAddress the address (in 2-byte words) in the code of the handler
|
||||
*/
|
||||
public EncodedTypeAddrPair(TypeIdItem exceptionType, int handlerAddress) {
|
||||
this.exceptionType = exceptionType;
|
||||
this.handlerAddress = handlerAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used internally to construct a new <code>EncodedTypeAddrPair</code> while reading in a
|
||||
* <code>DexFile</code>
|
||||
* @param dexFile the <code>DexFile</code> that is being read in
|
||||
* @param in the Input object to read the <code>EncodedCatchHandler</code> from
|
||||
*/
|
||||
private EncodedTypeAddrPair(DexFile dexFile, Input in) {
|
||||
exceptionType = dexFile.TypeIdsSection.getItemByIndex(in.readUnsignedLeb128());
|
||||
handlerAddress = in.readUnsignedLeb128();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the size of this <code>EncodedTypeAddrPair</code>
|
||||
*/
|
||||
private int getSize() {
|
||||
return Leb128Utils.unsignedLeb128Size(exceptionType.getIndex()) +
|
||||
Leb128Utils.unsignedLeb128Size(handlerAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the <code>EncodedTypeAddrPair</code> to the given <code>AnnotatedOutput</code> object
|
||||
* @param out the <code>AnnotatedOutput</code> object to write to
|
||||
*/
|
||||
private void writeTo(AnnotatedOutput out) {
|
||||
if (out.annotates()) {
|
||||
out.annotate("type_idx");
|
||||
out.writeUnsignedLeb128(exceptionType.getIndex());
|
||||
|
||||
out.annotate("addr");
|
||||
out.writeUnsignedLeb128(handlerAddress);
|
||||
} else {
|
||||
out.writeUnsignedLeb128(exceptionType.getIndex());
|
||||
out.writeUnsignedLeb128(handlerAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,336 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Debug;
|
||||
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.ByteArrayInput;
|
||||
import org.jf.dexlib.TypeIdItem;
|
||||
import org.jf.dexlib.StringIdItem;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.DebugInfoItem;
|
||||
|
||||
public class DebugInstructionIterator {
|
||||
/**
|
||||
* This method decodes the debug instructions in the given byte array and iterates over them, calling
|
||||
* the ProcessDebugInstructionDelegate.ProcessDebugInstruction method for each instruction
|
||||
* @param in an Input object that the debug instructions can be read from
|
||||
* @param processDebugInstruction a <code>ProcessDebugInstructionDelegate</code> object that gets called
|
||||
* for each instruction that is encountered
|
||||
*/
|
||||
public static void IterateInstructions(Input in, ProcessRawDebugInstructionDelegate processDebugInstruction) {
|
||||
int startOffset;
|
||||
|
||||
while(true)
|
||||
{
|
||||
startOffset = in.getCursor();
|
||||
byte debugOpcode = in.readByte();
|
||||
|
||||
switch (debugOpcode) {
|
||||
case 0x00:
|
||||
{
|
||||
processDebugInstruction.ProcessEndSequence(startOffset);
|
||||
return;
|
||||
}
|
||||
case 0x01:
|
||||
{
|
||||
int addressDiff = in.readUnsignedLeb128();
|
||||
processDebugInstruction.ProcessAdvancePC(startOffset, in.getCursor() - startOffset, addressDiff);
|
||||
break;
|
||||
}
|
||||
case 0x02:
|
||||
{
|
||||
int lineDiff = in.readSignedLeb128();
|
||||
processDebugInstruction.ProcessAdvanceLine(startOffset, in.getCursor() - startOffset, lineDiff);
|
||||
break;
|
||||
}
|
||||
case 0x03:
|
||||
{
|
||||
int registerNum = in.readUnsignedLeb128();
|
||||
int nameIndex = in.readUnsignedLeb128() - 1;
|
||||
int typeIndex = in.readUnsignedLeb128() - 1;
|
||||
processDebugInstruction.ProcessStartLocal(startOffset, in.getCursor() - startOffset, registerNum,
|
||||
nameIndex, typeIndex);
|
||||
break;
|
||||
}
|
||||
case 0x04:
|
||||
{
|
||||
int registerNum = in.readUnsignedLeb128();
|
||||
int nameIndex = in.readUnsignedLeb128() - 1;
|
||||
int typeIndex = in.readUnsignedLeb128() - 1;
|
||||
int signatureIndex = in.readUnsignedLeb128() - 1;
|
||||
processDebugInstruction.ProcessStartLocalExtended(startOffset, in.getCursor() - startOffset,
|
||||
registerNum, nameIndex, typeIndex, signatureIndex);
|
||||
break;
|
||||
}
|
||||
case 0x05:
|
||||
{
|
||||
int registerNum = in.readUnsignedLeb128();
|
||||
processDebugInstruction.ProcessEndLocal(startOffset, in.getCursor() - startOffset, registerNum);
|
||||
break;
|
||||
}
|
||||
case 0x06:
|
||||
{
|
||||
int registerNum = in.readUnsignedLeb128();
|
||||
processDebugInstruction.ProcessRestartLocal(startOffset, in.getCursor() - startOffset, registerNum);
|
||||
break;
|
||||
}
|
||||
case 0x07:
|
||||
{
|
||||
processDebugInstruction.ProcessSetPrologueEnd(startOffset);
|
||||
break;
|
||||
}
|
||||
case 0x08:
|
||||
{
|
||||
processDebugInstruction.ProcessSetEpilogueBegin(startOffset);
|
||||
break;
|
||||
}
|
||||
case 0x09:
|
||||
{
|
||||
int nameIndex = in.readUnsignedLeb128();
|
||||
processDebugInstruction.ProcessSetFile(startOffset, in.getCursor() - startOffset, nameIndex);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
byte base = (byte)((debugOpcode & 0xFF) - 0x0A);
|
||||
processDebugInstruction.ProcessSpecialOpcode(startOffset, debugOpcode, (base % 15) - 4, base / 15);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method decodes the debug instructions in the given byte array and iterates over them, calling
|
||||
* the ProcessDebugInstructionDelegate.ProcessDebugInstruction method for each instruction
|
||||
* @param debugInfoItem the <code>DebugInfoItem</code> to iterate over
|
||||
* @param registerCount the number of registers in the method that the given debug info is for
|
||||
* @param processDecodedDebugInstruction a <code>ProcessDebugInstructionDelegate</code> object that gets called
|
||||
* for each instruction that is encountered
|
||||
*/
|
||||
public static void DecodeInstructions(DebugInfoItem debugInfoItem, int registerCount,
|
||||
ProcessDecodedDebugInstructionDelegate processDecodedDebugInstruction) {
|
||||
int startOffset;
|
||||
int address = 0;
|
||||
int line = debugInfoItem.getLineStart();
|
||||
Input in = new ByteArrayInput(debugInfoItem.getEncodedDebugInfo());
|
||||
DexFile dexFile = debugInfoItem.getDexFile();
|
||||
|
||||
Local[] locals = new Local[registerCount];
|
||||
|
||||
while(true)
|
||||
{
|
||||
startOffset = in.getCursor();
|
||||
byte debugOpcode = in.readByte();
|
||||
|
||||
switch (debugOpcode) {
|
||||
case 0x00:
|
||||
{
|
||||
return;
|
||||
}
|
||||
case 0x01:
|
||||
{
|
||||
int addressDiff = in.readUnsignedLeb128();
|
||||
address += addressDiff;
|
||||
break;
|
||||
}
|
||||
case 0x02:
|
||||
{
|
||||
int lineDiff = in.readSignedLeb128();
|
||||
line += lineDiff;
|
||||
break;
|
||||
}
|
||||
case 0x03:
|
||||
{
|
||||
int registerNum = in.readUnsignedLeb128();
|
||||
StringIdItem name = dexFile.StringIdsSection.getItemByIndex(in.readUnsignedLeb128() - 1);
|
||||
TypeIdItem type = dexFile.TypeIdsSection.getItemByIndex(in.readUnsignedLeb128() - 1);
|
||||
locals[registerNum] = new Local(registerNum, name, type, null);
|
||||
processDecodedDebugInstruction.ProcessStartLocal(startOffset, in.getCursor() - startOffset, registerNum,
|
||||
name, type);
|
||||
break;
|
||||
}
|
||||
case 0x04:
|
||||
{
|
||||
int registerNum = in.readUnsignedLeb128();
|
||||
StringIdItem name = dexFile.StringIdsSection.getItemByIndex(in.readUnsignedLeb128() - 1);
|
||||
TypeIdItem type = dexFile.TypeIdsSection.getItemByIndex(in.readUnsignedLeb128() - 1);
|
||||
StringIdItem signature = dexFile.StringIdsSection.getItemByIndex(in.readUnsignedLeb128() - 1);
|
||||
locals[registerNum] = new Local(registerNum, name, type, signature);
|
||||
processDecodedDebugInstruction.ProcessStartLocalExtended(startOffset, in.getCursor() - startOffset,
|
||||
registerNum, name, type, signature);
|
||||
break;
|
||||
}
|
||||
case 0x05:
|
||||
{
|
||||
int registerNum = in.readUnsignedLeb128();
|
||||
Local local = locals[registerNum];
|
||||
if (local == null) {
|
||||
processDecodedDebugInstruction.ProcessEndLocal(startOffset, in.getCursor() - startOffset, registerNum,
|
||||
null, null, null);
|
||||
} else {
|
||||
processDecodedDebugInstruction.ProcessEndLocal(startOffset, in.getCursor() - startOffset, registerNum,
|
||||
local.name, local.type, local.signature);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x06:
|
||||
{
|
||||
int registerNum = in.readUnsignedLeb128();
|
||||
Local local = locals[registerNum];
|
||||
if (local == null) {
|
||||
processDecodedDebugInstruction.ProcessRestartLocal(startOffset, in.getCursor() - startOffset,
|
||||
registerNum, null, null, null);
|
||||
} else {
|
||||
processDecodedDebugInstruction.ProcessRestartLocal(startOffset, in.getCursor() - startOffset,
|
||||
registerNum, local.name, local.type, local.signature);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 0x07:
|
||||
{
|
||||
processDecodedDebugInstruction.ProcessSetPrologueEnd(startOffset);
|
||||
break;
|
||||
}
|
||||
case 0x08:
|
||||
{
|
||||
processDecodedDebugInstruction.ProcessSetEpilogueBegin(startOffset);
|
||||
break;
|
||||
}
|
||||
case 0x09:
|
||||
{
|
||||
StringIdItem name = dexFile.StringIdsSection.getItemByIndex(in.readUnsignedLeb128() - 1);
|
||||
processDecodedDebugInstruction.ProcessSetFile(startOffset, in.getCursor() - startOffset, name);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
byte base = (byte)((debugOpcode & 0xFF) - 0x0A);
|
||||
address += base / 15;
|
||||
line += (base % 15) - 4;
|
||||
processDecodedDebugInstruction.ProcessLineEmit(address, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class ProcessRawDebugInstructionDelegate
|
||||
{
|
||||
//TODO: add javadocs
|
||||
public void ProcessEndSequence(int startOffset) {
|
||||
ProcessStaticOpcode(startOffset, 1);
|
||||
}
|
||||
|
||||
public void ProcessAdvancePC(int startOffset, int length, int addressDiff) {
|
||||
ProcessStaticOpcode(startOffset, length);
|
||||
}
|
||||
|
||||
public void ProcessAdvanceLine(int startOffset, int length, int lineDiff) {
|
||||
ProcessStaticOpcode(startOffset, length);
|
||||
}
|
||||
|
||||
public void ProcessStartLocal(int startOffset, int length, int registerNum, int nameIndex, int typeIndex) {
|
||||
}
|
||||
|
||||
public void ProcessStartLocalExtended(int startOffset, int length, int registerNum, int nameIndex,
|
||||
int typeIndex,int signatureIndex) {
|
||||
}
|
||||
|
||||
public void ProcessEndLocal(int startOffset, int length, int registerNum) {
|
||||
ProcessStaticOpcode(startOffset, length);
|
||||
}
|
||||
|
||||
public void ProcessRestartLocal(int startOffset, int length, int registerNum) {
|
||||
ProcessStaticOpcode(startOffset, length);
|
||||
}
|
||||
|
||||
public void ProcessSetPrologueEnd(int startOffset) {
|
||||
ProcessStaticOpcode(startOffset, 1);
|
||||
}
|
||||
|
||||
public void ProcessSetEpilogueBegin(int startOffset) {
|
||||
ProcessStaticOpcode(startOffset, 1);
|
||||
}
|
||||
|
||||
public void ProcessSetFile(int startOffset, int length, int nameIndex) {
|
||||
}
|
||||
|
||||
public void ProcessSpecialOpcode(int startOffset, int debugOpcode, int lineDiff, int addressDiff) {
|
||||
ProcessStaticOpcode(startOffset, 1);
|
||||
}
|
||||
|
||||
public void ProcessStaticOpcode(int startOffset, int length) {
|
||||
}
|
||||
}
|
||||
|
||||
public static class ProcessDecodedDebugInstructionDelegate
|
||||
{
|
||||
public void ProcessStartLocal(int codeAddress, int length, int registerNum, StringIdItem name,
|
||||
TypeIdItem type) {
|
||||
}
|
||||
|
||||
public void ProcessStartLocalExtended(int codeAddress, int length, int registerNum, StringIdItem name,
|
||||
TypeIdItem type, StringIdItem signature) {
|
||||
}
|
||||
|
||||
public void ProcessEndLocal(int codeAddress, int length, int registerNum, StringIdItem name, TypeIdItem type,
|
||||
StringIdItem signature) {
|
||||
}
|
||||
|
||||
public void ProcessRestartLocal(int codeAddress, int length, int registerNum, StringIdItem name,
|
||||
TypeIdItem type, StringIdItem signature) {
|
||||
}
|
||||
|
||||
public void ProcessSetPrologueEnd(int codeAddress) {
|
||||
}
|
||||
|
||||
public void ProcessSetEpilogueBegin(int codeAddress) {
|
||||
}
|
||||
|
||||
public void ProcessSetFile(int codeAddress, int length, StringIdItem name) {
|
||||
}
|
||||
|
||||
public void ProcessLineEmit(int codeAddress, int line) {
|
||||
}
|
||||
}
|
||||
|
||||
private static class Local {
|
||||
public final int register;
|
||||
public final StringIdItem name;
|
||||
public final TypeIdItem type;
|
||||
public final StringIdItem signature;
|
||||
public Local(int register, StringIdItem name, TypeIdItem type, StringIdItem signature) {
|
||||
this.register = register;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
64
dexlib/src/main/java/org/jf/dexlib/Debug/DebugOpcode.java
Normal file
64
dexlib/src/main/java/org/jf/dexlib/Debug/DebugOpcode.java
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Debug;
|
||||
|
||||
public enum DebugOpcode {
|
||||
DBG_END_SEQUENCE((byte)0x00),
|
||||
DBG_ADVANCE_PC((byte)0x01),
|
||||
DBG_ADVANCE_LINE((byte)0x02),
|
||||
DBG_START_LOCAL((byte)0x03),
|
||||
DBG_START_LOCAL_EXTENDED((byte)0x04),
|
||||
DBG_END_LOCAL((byte)0x05),
|
||||
DBG_RESTART_LOCAL((byte)0x06),
|
||||
DBG_SET_PROLOGUE_END((byte)0x07),
|
||||
DBG_SET_EPILOGUE_END((byte)0x08),
|
||||
DBG_SET_FILE((byte)0x09),
|
||||
DBG_SPECIAL_OPCODE((byte)0x0A);
|
||||
|
||||
private static DebugOpcode[] opcodesByValue;
|
||||
|
||||
static {
|
||||
opcodesByValue = new DebugOpcode[11];
|
||||
|
||||
for (DebugOpcode debugOpcode: DebugOpcode.values()) {
|
||||
opcodesByValue[debugOpcode.value & 0xFF] = debugOpcode;
|
||||
}
|
||||
}
|
||||
|
||||
public static DebugOpcode getDebugOpcodeByValue(byte debugOpcodeValue) {
|
||||
debugOpcodeValue = (byte)Math.min(debugOpcodeValue, 0x0A);
|
||||
return opcodesByValue[debugOpcodeValue];
|
||||
}
|
||||
|
||||
public final byte value;
|
||||
|
||||
DebugOpcode(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
379
dexlib/src/main/java/org/jf/dexlib/DebugInfoItem.java
Normal file
379
dexlib/src/main/java/org/jf/dexlib/DebugInfoItem.java
Normal file
@ -0,0 +1,379 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.Debug.DebugInstructionIterator;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.Leb128Utils;
|
||||
import org.jf.dexlib.Util.ByteArrayInput;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DebugInfoItem extends Item<DebugInfoItem> {
|
||||
private int lineStart;
|
||||
private StringIdItem[] parameterNames;
|
||||
private byte[] encodedDebugInfo;
|
||||
private Item[] referencedItems;
|
||||
|
||||
private CodeItem parent = null;
|
||||
|
||||
/**
|
||||
* Creates a new uninitialized <code>DebugInfoInfo</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
*/
|
||||
public DebugInfoItem(DexFile dexFile) {
|
||||
super(dexFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>DebugInfoItem</code> with the given values
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param lineStart the initial value for the line number register for the debug info machine
|
||||
* @param parameterNames an array of the names of the associated method's parameters. The entire parameter
|
||||
* can be null if no parameter info is available, or any element can be null to indicate no info for that parameter
|
||||
* @param encodedDebugInfo the debug info, encoded as a byte array
|
||||
* @param referencedItems an array of the items referenced by instructions, in order of occurance in the encoded
|
||||
* debug info
|
||||
*/
|
||||
private DebugInfoItem(DexFile dexFile,
|
||||
int lineStart,
|
||||
StringIdItem[] parameterNames,
|
||||
byte[] encodedDebugInfo,
|
||||
Item[] referencedItems) {
|
||||
super(dexFile);
|
||||
this.lineStart = lineStart;
|
||||
this.parameterNames = parameterNames;
|
||||
this.encodedDebugInfo = encodedDebugInfo;
|
||||
this.referencedItems = referencedItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new <code>DebugInfoItem</code> with the given values
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param lineStart the initial value for the line number register for the debug info machine
|
||||
* @param parameterNames an array of the names of the associated method's parameters. The entire parameter
|
||||
* can be null if no parameter info is available, or any element can be null to indicate no info for that parameter
|
||||
* @param encodedDebugInfo the debug info, encoded as a byte array
|
||||
* @param referencedItems an array of the items referenced by instructions, in order of occurance in the encoded
|
||||
* debug info
|
||||
* @return a new <code>DebugInfoItem</code> with the given values
|
||||
*/
|
||||
public static DebugInfoItem getInternedDebugInfoItem(DexFile dexFile,
|
||||
int lineStart,
|
||||
StringIdItem[] parameterNames,
|
||||
byte[] encodedDebugInfo,
|
||||
Item[] referencedItems) {
|
||||
DebugInfoItem debugInfoItem = new DebugInfoItem(dexFile, lineStart, parameterNames, encodedDebugInfo,
|
||||
referencedItems);
|
||||
return dexFile.DebugInfoItemsSection.intern(debugInfoItem);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void readItem(Input in, ReadContext readContext) {
|
||||
lineStart = in.readUnsignedLeb128();
|
||||
parameterNames = new StringIdItem[in.readUnsignedLeb128()];
|
||||
IndexedSection<StringIdItem> stringIdSection = dexFile.StringIdsSection;
|
||||
for (int i=0; i<parameterNames.length; i++) {
|
||||
int index = in.readUnsignedLeb128() - 1;
|
||||
if (index < 0) {
|
||||
parameterNames[i] = null;
|
||||
} else {
|
||||
parameterNames[i] = stringIdSection.getItemByIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
int start = in.getCursor();
|
||||
final List<Item> referencedItemsList = new ArrayList<Item>(50);
|
||||
DebugInstructionIterator.IterateInstructions(in,
|
||||
new DebugInstructionIterator.ProcessRawDebugInstructionDelegate() {
|
||||
@Override
|
||||
public void ProcessStartLocal(int startOffset, int length, int registerNum, int nameIndex,
|
||||
int typeIndex) {
|
||||
if (nameIndex != -1) {
|
||||
referencedItemsList.add(dexFile.StringIdsSection.getItemByIndex(nameIndex));
|
||||
}
|
||||
if (typeIndex != -1) {
|
||||
referencedItemsList.add(dexFile.TypeIdsSection.getItemByIndex(typeIndex));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ProcessStartLocalExtended(int startOffset, int length, int registerNume, int nameIndex,
|
||||
int typeIndex, int signatureIndex) {
|
||||
if (nameIndex != -1) {
|
||||
referencedItemsList.add(dexFile.StringIdsSection.getItemByIndex(nameIndex));
|
||||
}
|
||||
if (typeIndex != -1) {
|
||||
referencedItemsList.add(dexFile.TypeIdsSection.getItemByIndex(typeIndex));
|
||||
}
|
||||
if (signatureIndex != -1) {
|
||||
referencedItemsList.add(dexFile.StringIdsSection.getItemByIndex(signatureIndex));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ProcessSetFile(int startOffset, int length, int nameIndex) {
|
||||
if (nameIndex != -1) {
|
||||
referencedItemsList.add(dexFile.StringIdsSection.getItemByIndex(nameIndex));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
referencedItems = new Item[referencedItemsList.size()];
|
||||
referencedItemsList.toArray(referencedItems);
|
||||
|
||||
int length = in.getCursor() - start;
|
||||
in.setCursor(start);
|
||||
encodedDebugInfo = in.readBytes(length);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int placeItem(int offset) {
|
||||
offset += Leb128Utils.unsignedLeb128Size(lineStart);
|
||||
offset += Leb128Utils.unsignedLeb128Size(parameterNames.length);
|
||||
for (StringIdItem parameterName: parameterNames) {
|
||||
int indexp1;
|
||||
if (parameterName == null) {
|
||||
indexp1 = 0;
|
||||
} else {
|
||||
indexp1 = parameterName.getIndex() + 1;
|
||||
}
|
||||
offset += Leb128Utils.unsignedLeb128Size(indexp1);
|
||||
}
|
||||
|
||||
//make a subclass so we can keep track of and access the computed length
|
||||
class ProcessDebugInstructionDelegateWithLength extends
|
||||
DebugInstructionIterator.ProcessRawDebugInstructionDelegate {
|
||||
public int length = 0;
|
||||
}
|
||||
ProcessDebugInstructionDelegateWithLength pdidwl;
|
||||
|
||||
//final referencedItems = this.referencedItems;
|
||||
|
||||
DebugInstructionIterator.IterateInstructions(new ByteArrayInput(encodedDebugInfo),
|
||||
pdidwl = new ProcessDebugInstructionDelegateWithLength() {
|
||||
private int referencedItemsPosition = 0;
|
||||
|
||||
@Override
|
||||
public void ProcessStaticOpcode(int startOffset, int length) {
|
||||
this.length+=length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ProcessStartLocal(int startOffset, int length, int registerNum, int nameIndex,
|
||||
int typeIndex) {
|
||||
this.length+=Leb128Utils.unsignedLeb128Size(registerNum);
|
||||
if (nameIndex != 0) {
|
||||
this.length+=
|
||||
Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1);
|
||||
} else {
|
||||
this.length++;
|
||||
}
|
||||
if (typeIndex != 0) {
|
||||
this.length+=
|
||||
Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1);
|
||||
} else {
|
||||
this.length++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ProcessStartLocalExtended(int startOffset, int length, int registerNum, int nameIndex,
|
||||
int typeIndex, int signatureIndex) {
|
||||
this.length+=Leb128Utils.unsignedLeb128Size(registerNum);
|
||||
if (nameIndex != 0) {
|
||||
this.length+=
|
||||
Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1);
|
||||
} else {
|
||||
this.length++;
|
||||
}
|
||||
if (typeIndex != 0) {
|
||||
this.length+=
|
||||
Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1);
|
||||
} else {
|
||||
this.length++;
|
||||
}
|
||||
if (signatureIndex != 0) {
|
||||
this.length+=
|
||||
Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1);
|
||||
} else {
|
||||
this.length++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ProcessSetFile(int startOffset, int length, int nameIndex) {
|
||||
if (nameIndex != 0) {
|
||||
this.length+=
|
||||
Leb128Utils.unsignedLeb128Size(referencedItems[referencedItemsPosition++].getIndex()+1);
|
||||
} else {
|
||||
this.length++;
|
||||
}
|
||||
}
|
||||
});
|
||||
return offset + pdidwl.length;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void writeItem(final AnnotatedOutput out) {
|
||||
out.writeUnsignedLeb128(lineStart);
|
||||
out.writeUnsignedLeb128(parameterNames.length);
|
||||
for (StringIdItem parameterName: parameterNames) {
|
||||
int indexp1;
|
||||
if (parameterName == null) {
|
||||
indexp1 = 0;
|
||||
} else {
|
||||
indexp1 = parameterName.getIndex() + 1;
|
||||
}
|
||||
out.writeUnsignedLeb128(indexp1);
|
||||
}
|
||||
|
||||
DebugInstructionIterator.IterateInstructions(new ByteArrayInput(encodedDebugInfo),
|
||||
new DebugInstructionIterator.ProcessRawDebugInstructionDelegate() {
|
||||
private int referencedItemsPosition = 0;
|
||||
|
||||
@Override
|
||||
public void ProcessStaticOpcode(int startOffset, int length) {
|
||||
out.write(encodedDebugInfo, startOffset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ProcessStartLocal(int startOffset, int length, int registerNum, int nameIndex,
|
||||
int typeIndex) {
|
||||
out.writeUnsignedLeb128(registerNum);
|
||||
if (nameIndex != -1) {
|
||||
out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1);
|
||||
} else {
|
||||
out.writeByte(0);
|
||||
}
|
||||
if (typeIndex != -1) {
|
||||
out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1);
|
||||
} else {
|
||||
out.writeByte(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ProcessStartLocalExtended(int startOffset, int length, int registerNum, int nameIndex,
|
||||
int typeIndex, int signatureIndex) {
|
||||
out.writeUnsignedLeb128(registerNum);
|
||||
if (nameIndex != -1) {
|
||||
out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1);
|
||||
} else {
|
||||
out.writeByte(0);
|
||||
}
|
||||
if (typeIndex != -1) {
|
||||
out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1);
|
||||
} else {
|
||||
out.writeByte(0);
|
||||
}
|
||||
if (signatureIndex != -1) {
|
||||
out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1);
|
||||
} else {
|
||||
out.writeByte(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ProcessSetFile(int startOffset, int length, int nameIndex) {
|
||||
if (nameIndex != -1) {
|
||||
out.writeUnsignedLeb128(referencedItems[referencedItemsPosition++].getIndex() + 1);
|
||||
} else {
|
||||
out.writeByte(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_DEBUG_INFO_ITEM;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String getConciseIdentity() {
|
||||
return "debug_info_item @0x" + Integer.toHexString(getOffset());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int compareTo(DebugInfoItem other) {
|
||||
if (parent == null) {
|
||||
if (other.parent == null) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (other.parent == null) {
|
||||
return 1;
|
||||
}
|
||||
return parent.compareTo(other.parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the <code>CodeItem</code> that this <code>DebugInfoItem</code> is associated with
|
||||
* @param codeItem the <code>CodeItem</code> that this <code>DebugInfoItem</code> is associated with
|
||||
*/
|
||||
protected void setParent(CodeItem codeItem) {
|
||||
this.parent = codeItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the initial value for the line number register for the debug info machine
|
||||
*/
|
||||
public int getLineStart() {
|
||||
return lineStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the debug info, encoded as a byte array
|
||||
*/
|
||||
public byte[] getEncodedDebugInfo() {
|
||||
return encodedDebugInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an array of the items referenced by instructions, in order of occurance in the encoded debug info
|
||||
*/
|
||||
public Item[] getReferencedItems() {
|
||||
return referencedItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an array of the names of the associated method's parameters. The array can be null if no parameter info
|
||||
* is available, or any element can be null to indicate no info for that parameter
|
||||
*/
|
||||
public StringIdItem[] getParameterNames() {
|
||||
return parameterNames;
|
||||
}
|
||||
}
|
674
dexlib/src/main/java/org/jf/dexlib/DexFile.java
Normal file
674
dexlib/src/main/java/org/jf/dexlib/DexFile.java
Normal file
@ -0,0 +1,674 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
import org.jf.dexlib.Util.ByteArrayInput;
|
||||
import org.jf.dexlib.Util.FileUtils;
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.*;
|
||||
import org.jf.dexlib.Item;
|
||||
import org.jf.dexlib.StringDataItem;
|
||||
|
||||
import java.io.File;
|
||||
import java.security.DigestException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.zip.Adler32;
|
||||
|
||||
/**
|
||||
* <h3>Main use cases</h3>
|
||||
*
|
||||
* <p>These are the main use cases that drove the design of this library</p>
|
||||
*
|
||||
* <ol>
|
||||
* <li><p><b>Annotate an existing dex file</b> - In this case, the intent is to document the structure of
|
||||
* an existing dex file. We want to be able to read in the dex file, and then write out a dex file
|
||||
* that is exactly the same (while adding annotation information to an AnnotatedOutput object)</p></li>
|
||||
*
|
||||
* <li><p><b>Canonicalize an existing dex file</b> - In this case, the intent is to rewrite an existing dex file
|
||||
* so that it is in a canonical form. There is a certain amount of leeway in how various types of
|
||||
* tems in a dex file are ordered or represented. It is sometimes useful to be able to easily
|
||||
* compare a disassebled and reassembled dex file with the original dex file. If both dex-files are
|
||||
* written canonically, they "should" match exactly, barring any explicit changes to the reassembled
|
||||
* file.</p>
|
||||
*
|
||||
* <p>Currently, there are a couple of pieces of information that probably won't match exactly
|
||||
* <ul>
|
||||
* <li>the order of exception handlers in the <code>EncodedCatchHandlerList</code> for a method</li>
|
||||
* <li>the ordering of some of the debug info in the <code>{@link org.jf.dexlib.DebugInfoItem}</code> for a method</li>
|
||||
* </ul></p>
|
||||
*
|
||||
*
|
||||
* <p>Note that the above discrepancies should typically only be "intra-item" differences. They
|
||||
* shouldn't change the size of the item, or affect how anything else is placed or laid out</p></li>
|
||||
*
|
||||
* <li><p><b>Creating a dex file from scratch</b> - In this case, a blank dex file is created and then classes
|
||||
* are added to it incrementally by calling the {@link org.jf.dexlib.Section#intern intern} method of
|
||||
* {@link DexFile#ClassDefsSection}, which will add all the information necessary to represent the given
|
||||
* class. For example, when assembling a dex file from a set of assembly text files.</p>
|
||||
*
|
||||
* <p>In this case, we can choose to write the dex file in a canonical form or not. It is somewhat
|
||||
* slower to write it in a canonical format, due to the extra sorting and calculations that are
|
||||
* required.</p></li>
|
||||
*
|
||||
*
|
||||
* <li><p><b>Reading in the dex file</b> - In this case, the intent is to read in a dex file and expose all the
|
||||
* data to the calling application. For example, when disassembling a dex file into a text based
|
||||
* assembly format, or doing other misc processing of the dex file.</p></li>
|
||||
*
|
||||
*
|
||||
* <h3>Other use cases</h3>
|
||||
*
|
||||
* <p>These are other use cases that are possible, but did not drive the design of the library.
|
||||
* No effort was made to test these use cases or ensure that they work. Some of these could
|
||||
* probably be better achieved with a disassemble - modify - reassemble type process, using
|
||||
* smali/baksmali or another assembler/disassembler pair that are compatible with each other</p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>deleting classes/methods/etc. from a dex file</li>
|
||||
* <li>merging 2 dex files</li>
|
||||
* <li>splitting a dex file</li>
|
||||
* <li>moving classes from 1 dex file to another</li>
|
||||
* <li>removing the debug information from a dex file</li>
|
||||
* <li>obfustication of a dex file</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class DexFile
|
||||
{
|
||||
/**
|
||||
* A mapping from ItemType to the section that contains items of the given type
|
||||
*/
|
||||
private final Section[] sectionsByType;
|
||||
|
||||
/**
|
||||
* Ordered lists of the indexed and offsetted sections. The order of these lists specifies the order
|
||||
* that the sections will be written in
|
||||
*/
|
||||
private final IndexedSection[] indexedSections;
|
||||
private final OffsettedSection[] offsettedSections;
|
||||
|
||||
/**
|
||||
* dalvik had a bug where it wrote the registers for certain types of debug info in a signed leb
|
||||
* format, instead of an unsigned leb format. There are no negative registers of course, but
|
||||
* certain positive values have a different encoding depending on whether they are encoded as
|
||||
* an unsigned leb128 or a signed leb128. Specifically, the signed leb128 is 1 byte longer in some cases.
|
||||
*
|
||||
* This determine whether we should keep any signed registers as signed, or force all register to
|
||||
* unsigned. By default we don't keep track of whether they were signed or not, and write them back
|
||||
* out as unsigned. This option only has an effect when reading an existing dex file. It has no
|
||||
* effect when a dex file is created from scratch
|
||||
*
|
||||
* The 2 main use-cases in play are
|
||||
* 1. Annotate an existing dex file - In this case, preserveSignedRegisters should be false, so that we keep
|
||||
* track of any signed registers and write them back out as signed Leb128 values.
|
||||
*
|
||||
* 2. Canonicalize an existing dex file - In this case, fixRegisters should be true, so that all
|
||||
* registers in the debug info are written as unsigned Leb128 values regardless of how they were
|
||||
* originally encoded
|
||||
*/
|
||||
private final boolean preserveSignedRegisters;
|
||||
|
||||
/**
|
||||
* When true, this prevents any sorting of the items during placement of the dex file. This
|
||||
* should *only* be set to true when this dex file was read in from an existing (valid) dex file,
|
||||
* and no modifications were made (i.e. no items added or deleted). Otherwise it is likely that
|
||||
* an invalid dex file will be generated.
|
||||
*
|
||||
* This is useful for the first use case (annotating an existing dex file). This ensures the items
|
||||
* retain the same order as in the original dex file.
|
||||
*/
|
||||
private boolean inplace = false;
|
||||
|
||||
/**
|
||||
* When true, this imposes an full ordering on all the items, to force them into a (possibly
|
||||
* arbitrary) canonical order. When false, only the items that the dex format specifies
|
||||
* an order for are sorted. The rest of the items are not ordered.
|
||||
*
|
||||
* This is useful for the second use case (canonicalizing an existing dex file) or possibly for
|
||||
* the third use case (creating a dex file from scratch), if there is a need to write the new
|
||||
* dex file in a canonical form.
|
||||
*/
|
||||
private boolean sortAllItems = false;
|
||||
|
||||
|
||||
/**
|
||||
* this is used to access the dex file from within inner classes, when they declare fields or
|
||||
* variable that hide fields on this object
|
||||
*/
|
||||
private final DexFile dexFile = this;
|
||||
|
||||
|
||||
private int dataOffset;
|
||||
private int dataSize;
|
||||
private int fileSize;
|
||||
|
||||
|
||||
/**
|
||||
* A private constructor containing common code to initialize the section maps and lists
|
||||
* @param preserveSignedRegisters If true, keep track of any registers in the debug information
|
||||
* that are signed, so they will be written in the same format. See
|
||||
* <code>getPreserveSignedRegisters()</code>
|
||||
*/
|
||||
private DexFile(boolean preserveSignedRegisters) {
|
||||
this.preserveSignedRegisters = preserveSignedRegisters;
|
||||
|
||||
sectionsByType = new Section[] {
|
||||
StringIdsSection,
|
||||
TypeIdsSection,
|
||||
ProtoIdsSection,
|
||||
FieldIdsSection,
|
||||
MethodIdsSection,
|
||||
ClassDefsSection,
|
||||
TypeListsSection,
|
||||
AnnotationSetRefListsSection,
|
||||
AnnotationSetsSection,
|
||||
ClassDataSection,
|
||||
CodeItemsSection,
|
||||
AnnotationDirectoriesSection,
|
||||
StringDataSection,
|
||||
DebugInfoItemsSection,
|
||||
AnnotationsSection,
|
||||
EncodedArraysSection,
|
||||
null,
|
||||
null
|
||||
};
|
||||
|
||||
indexedSections = new IndexedSection[] {
|
||||
StringIdsSection,
|
||||
TypeIdsSection,
|
||||
ProtoIdsSection,
|
||||
FieldIdsSection,
|
||||
MethodIdsSection,
|
||||
ClassDefsSection
|
||||
};
|
||||
|
||||
offsettedSections = new OffsettedSection[] {
|
||||
AnnotationSetRefListsSection,
|
||||
AnnotationSetsSection,
|
||||
CodeItemsSection,
|
||||
AnnotationDirectoriesSection,
|
||||
TypeListsSection,
|
||||
StringDataSection,
|
||||
AnnotationsSection,
|
||||
EncodedArraysSection,
|
||||
ClassDataSection,
|
||||
DebugInfoItemsSection
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new DexFile instance by reading in the given dex file.
|
||||
* @param file The dex file to read in
|
||||
*/
|
||||
public DexFile(String file) {
|
||||
this(new File(file), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new DexFile instance by reading in the given dex file,
|
||||
* and optionally keep track of any registers in the debug information that are signed,
|
||||
* so they will be written in the same format.
|
||||
* @param file The dex file to read in
|
||||
* @param preserveSignedRegisters If true, keep track of any registers in the debug information
|
||||
* that are signed, so they will be written in the same format. See
|
||||
* <code>getPreserveSignedRegisters()</code>
|
||||
*/
|
||||
public DexFile(String file, boolean preserveSignedRegisters) {
|
||||
this(new File(file), preserveSignedRegisters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new DexFile instance by reading in the given dex file.
|
||||
* @param file The dex file to read in
|
||||
*/
|
||||
public DexFile(File file) {
|
||||
this(file, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new DexFile instance by reading in the given dex file,
|
||||
* and optionally keep track of any registers in the debug information that are signed,
|
||||
* so they will be written in the same format.
|
||||
* @param file The dex file to read in
|
||||
* @param preserveSignedRegisters If true, keep track of any registers in the debug information
|
||||
* that are signed, so they will be written in the same format.
|
||||
* @see #getPreserveSignedRegisters
|
||||
*/
|
||||
public DexFile(File file, boolean preserveSignedRegisters) {
|
||||
this(preserveSignedRegisters);
|
||||
|
||||
Input in = new ByteArrayInput(FileUtils.readFile(file));
|
||||
|
||||
ReadContext readContext = new ReadContext(this);
|
||||
|
||||
HeaderItem.readFrom(in, 0, readContext);
|
||||
|
||||
//the map offset was set while reading in the header item
|
||||
int mapOffset = readContext.getSectionOffset(ItemType.TYPE_MAP_LIST);
|
||||
|
||||
in.setCursor(mapOffset);
|
||||
MapItem.readFrom(in, 0, readContext);
|
||||
|
||||
for (Section section: sectionsByType) {
|
||||
if (section == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int sectionOffset = readContext.getSectionOffset(section.ItemType);
|
||||
if (sectionOffset > 0) {
|
||||
int sectionSize = readContext.getSectionSize(section.ItemType);
|
||||
in.setCursor(sectionOffset);
|
||||
section.readFrom(sectionSize, in, readContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new, blank dex file. Classes can be added to this dex file by calling
|
||||
* the <code>Section.intern()</code> method of <code>ClassDefsSection</code>
|
||||
*/
|
||||
public DexFile() {
|
||||
this(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the <code>Section</code> containing items of the same type as the given item
|
||||
* @param item Get the <code>Section</code> that contains items of this type
|
||||
* @param <T> The specific item subclass - inferred from the passed item
|
||||
* @return the <code>Section</code> containing items of the same type as the given item
|
||||
*/
|
||||
public <T extends Item> Section<T> getSectionForItem(T item) {
|
||||
return (Section<T>)sectionsByType[item.getItemType().SectionIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the <code>Section</code> containing items of the given type
|
||||
* @param itemType the type of item
|
||||
* @return the <code>Section</code> containing items of the given type
|
||||
*/
|
||||
public Section getSectionForType(ItemType itemType) {
|
||||
return sectionsByType[itemType.SectionIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a boolean value indicating whether this dex file preserved any signed
|
||||
* registers in the debug info as it read the dex file in. By default, the dex file
|
||||
* doesn't check whether the registers are encoded as unsigned or signed values.
|
||||
*
|
||||
* This does *not* affect the actual register value that is read in. The value is
|
||||
* read correctly regardless
|
||||
*
|
||||
* This does affect whether any signed registers will retain the same encoding or be
|
||||
* forced to the (correct) unsigned encoding when the dex file is written back out.
|
||||
*
|
||||
* See the discussion about signed register values in the documentation for
|
||||
* <code>DexFile</code>
|
||||
* @return a boolean indicating whether this dex file preserved any signed registers
|
||||
* as it was read in
|
||||
*/
|
||||
public boolean getPreserveSignedRegisters() {
|
||||
return preserveSignedRegisters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a boolean value indicating whether all items should be placed into a
|
||||
* (possibly arbitrary) "canonical" ordering. If false, then only the items
|
||||
* that must be ordered per the dex specification are sorted.
|
||||
*
|
||||
* When true, writing the dex file involves somewhat more overhead
|
||||
*
|
||||
* If both SortAllItems and Inplace are true, Inplace takes precedence
|
||||
* @return a boolean value indicating whether all items should be sorted
|
||||
*/
|
||||
public boolean getSortAllItems() {
|
||||
return this.sortAllItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a boolean value indicating whether all items should be placed into a
|
||||
* (possibly arbitrary) "canonical" ordering. If false, then only the items
|
||||
* that must be ordered per the dex specification are sorted.
|
||||
*
|
||||
* When true, writing the dex file involves somewhat more overhead
|
||||
*
|
||||
* If both SortAllItems and Inplace are true, Inplace takes precedence
|
||||
* @param value a boolean value indicating whether all items should be sorted
|
||||
*/
|
||||
public void setSortAllItems(boolean value) {
|
||||
this.sortAllItems = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a boolean value indicating whether items in this dex file should be
|
||||
* written back out "in-place", or whether the normal layout logic should be
|
||||
* applied.
|
||||
*
|
||||
* This should only be used for a dex file that has been read from an existing
|
||||
* dex file, and no modifications have been made to the dex file. Otherwise,
|
||||
* there is a good chance that the resulting dex file will be invalid due to
|
||||
* items that aren't placed correctly
|
||||
*
|
||||
* If both SortAllItems and Inplace are true, Inplace takes precedence
|
||||
* @return a boolean value indicating whether items in this dex file should be
|
||||
* written back out in-place.
|
||||
*/
|
||||
public boolean getInplace() {
|
||||
return this.inplace;
|
||||
}
|
||||
|
||||
public int getFileSize() {
|
||||
//TODO: implement this
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getDataSize() {
|
||||
//TODO: implement this
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getDataOffset() {
|
||||
//TODO: implement this
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a boolean value indicating whether items in this dex file should be
|
||||
* written back out "in-place", or whether the normal layout logic should be
|
||||
* applied.
|
||||
*
|
||||
* This should only be used for a dex file that has been read from an existing
|
||||
* dex file, and no modifications have been made to the dex file. Otherwise,
|
||||
* there is a good chance that the resulting dex file will be invalid due to
|
||||
* items that aren't placed correctly
|
||||
*
|
||||
* If both SortAllItems and Inplace are true, Inplace takes precedence
|
||||
* @param value a boolean value indicating whether items in this dex file should be
|
||||
* written back out in-place.
|
||||
*/
|
||||
public void setInplace(boolean value) {
|
||||
this.inplace = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of Section objects that are sorted by offset.
|
||||
* @return an array of Section objects that are sorted by offset.
|
||||
*/
|
||||
protected Section[] getOrderedSections() {
|
||||
int sectionCount = 0;
|
||||
|
||||
for (Section section: sectionsByType) {
|
||||
if (section.ItemType.isIndexedItem() || section.getItems().size() > 0) {
|
||||
sectionCount++;
|
||||
}
|
||||
}
|
||||
|
||||
Section[] sections = new Section[sectionCount];
|
||||
sectionCount = 0;
|
||||
for (Section section: sectionsByType) {
|
||||
if (section.ItemType.isIndexedItem() || section.getItems().size() > 0) {
|
||||
sections[sectionCount++] = section;
|
||||
}
|
||||
}
|
||||
|
||||
Arrays.sort(sections, new Comparator<Section>() {
|
||||
public int compare(Section a, Section b) {
|
||||
return a.getOffset() - b.getOffset();
|
||||
}
|
||||
});
|
||||
|
||||
return sections;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should be called before writing a dex file. It sorts the sections
|
||||
* as needed or as indicated by <code>getSortAllItems()</code> and <code>getInplace()</code>,
|
||||
* and then performs a pass through all of the items, finalizing the position (i.e.
|
||||
* index and/or offset) of each item in the dex file.
|
||||
*
|
||||
* This step is needed primarily so that the indexes and offsets of all indexed and
|
||||
* offsetted items are available when writing references to those items elsewhere.
|
||||
*/
|
||||
public void place() {
|
||||
int offset = HeaderItem.placeAt(0, 0);
|
||||
|
||||
for (IndexedSection indexedSection: indexedSections) {
|
||||
if (!this.inplace) {
|
||||
indexedSection.sortSection();
|
||||
}
|
||||
offset = indexedSection.placeAt(offset);
|
||||
}
|
||||
|
||||
dataOffset = offset;
|
||||
|
||||
for (OffsettedSection offsettedSection: offsettedSections) {
|
||||
if (this.sortAllItems && !this.inplace) {
|
||||
offsettedSection.sortSection();
|
||||
}
|
||||
offset = offsettedSection.placeAt(offset);
|
||||
}
|
||||
|
||||
offset = MapItem.placeAt(offset, 0);
|
||||
|
||||
fileSize = offset;
|
||||
dataSize = offset - dataOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the dex file to the give <code>AnnotatedOutput</code> object. If
|
||||
* <code>out.Annotates()</code> is true, then annotations that document the format
|
||||
* of the dex file are written.
|
||||
*
|
||||
* You must call <code>place()</code> on this dex file, before calling this method
|
||||
* @param out the AnnotatedOutput object to write the dex file and annotations to
|
||||
*
|
||||
* After calling this method, you should call <code>calcSignature()</code> and
|
||||
* then <code>calcChecksum()</code> on the resulting byte array, to calculate the
|
||||
* signature and checksum in the header
|
||||
*/
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
HeaderItem.writeTo(out);
|
||||
|
||||
for (IndexedSection indexedSection: indexedSections) {
|
||||
indexedSection.writeTo(out);
|
||||
}
|
||||
|
||||
//TODO: if inplace is true, we need to use the order of the sections as they were in the original file
|
||||
for (OffsettedSection offsettedSection: offsettedSections) {
|
||||
offsettedSection.writeTo(out);
|
||||
}
|
||||
|
||||
out.alignTo(MapItem.getItemType().ItemAlignment);
|
||||
MapItem.writeTo(out);
|
||||
}
|
||||
|
||||
public final HeaderItem HeaderItem = new HeaderItem(this);
|
||||
public final MapItem MapItem = new MapItem(this);
|
||||
|
||||
/**
|
||||
* The <code>IndexedSection</code> containing <code>StringIdItem</code> items
|
||||
*/
|
||||
public final IndexedSection<StringIdItem> StringIdsSection =
|
||||
new IndexedSection<StringIdItem>(this, ItemType.TYPE_STRING_ID_ITEM);
|
||||
|
||||
/**
|
||||
* The <code>IndexedSection</code> containing <code>TypeIdItem</code> items
|
||||
*/
|
||||
public final IndexedSection<TypeIdItem> TypeIdsSection =
|
||||
new IndexedSection<TypeIdItem>(this, ItemType.TYPE_TYPE_ID_ITEM);
|
||||
|
||||
/**
|
||||
* The <code>IndexedSection</code> containing <code>ProtoIdItem</code> items
|
||||
*/
|
||||
public final IndexedSection<ProtoIdItem> ProtoIdsSection =
|
||||
new IndexedSection<ProtoIdItem>(this, ItemType.TYPE_PROTO_ID_ITEM);
|
||||
|
||||
/**
|
||||
* The <code>IndexedSection</code> containing <code>FieldIdItem</code> items
|
||||
*/
|
||||
public final IndexedSection<FieldIdItem> FieldIdsSection =
|
||||
new IndexedSection<FieldIdItem>(this, ItemType.TYPE_FIELD_ID_ITEM);
|
||||
|
||||
/**
|
||||
* The <code>IndexedSection</code> containing <code>MethodIdItem</code> items
|
||||
*/
|
||||
public final IndexedSection<MethodIdItem> MethodIdsSection =
|
||||
new IndexedSection<MethodIdItem>(this, ItemType.TYPE_METHOD_ID_ITEM);
|
||||
|
||||
/**
|
||||
* The <code>IndexedSection</code> containing <code>ClassDefItem</code> items
|
||||
*/
|
||||
public final IndexedSection<ClassDefItem> ClassDefsSection =
|
||||
new IndexedSection<ClassDefItem>(this, ItemType.TYPE_CLASS_DEF_ITEM) {
|
||||
|
||||
public int placeAt(int offset) {
|
||||
if (dexFile.getInplace()) {
|
||||
return super.placeAt(offset);
|
||||
}
|
||||
|
||||
int ret = ClassDefItem.placeClassDefItems(this, offset);
|
||||
|
||||
this.offset = items.get(0).getOffset();
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The <code>OffsettedSection</code> containing <code>TypeListItem</code> items
|
||||
*/
|
||||
public final OffsettedSection<TypeListItem> TypeListsSection =
|
||||
new OffsettedSection<TypeListItem>(this, ItemType.TYPE_TYPE_LIST);
|
||||
|
||||
/**
|
||||
* The <code>OffsettedSection</code> containing <code>AnnotationSetRefList</code> items
|
||||
*/
|
||||
public final OffsettedSection<AnnotationSetRefList> AnnotationSetRefListsSection =
|
||||
new OffsettedSection<AnnotationSetRefList>(this, ItemType.TYPE_ANNOTATION_SET_REF_LIST);
|
||||
|
||||
/**
|
||||
* The <code>OffsettedSection</code> containing <code>AnnotationSetItem</code> items
|
||||
*/
|
||||
public final OffsettedSection<AnnotationSetItem> AnnotationSetsSection =
|
||||
new OffsettedSection<AnnotationSetItem>(this, ItemType.TYPE_ANNOTATION_SET_ITEM);
|
||||
|
||||
/**
|
||||
* The <code>OffsettedSection</code> containing <code>ClassDataItem</code> items
|
||||
*/
|
||||
public final OffsettedSection<ClassDataItem> ClassDataSection =
|
||||
new OffsettedSection<ClassDataItem>(this, ItemType.TYPE_CLASS_DATA_ITEM);
|
||||
|
||||
/**
|
||||
* The <code>OffsettedSection</code> containing <code>CodeItem</code> items
|
||||
*/
|
||||
public final OffsettedSection<CodeItem> CodeItemsSection =
|
||||
new OffsettedSection<CodeItem>(this, ItemType.TYPE_CODE_ITEM);
|
||||
|
||||
/**
|
||||
* The <code>OffsettedSection</code> containing <code>StringDataItem</code> items
|
||||
*/
|
||||
public final OffsettedSection<StringDataItem> StringDataSection =
|
||||
new OffsettedSection<StringDataItem>(this, ItemType.TYPE_STRING_DATA_ITEM);
|
||||
|
||||
/**
|
||||
* The <code>OffsettedSection</code> containing <code>DebugInfoItem</code> items
|
||||
*/
|
||||
public final OffsettedSection<DebugInfoItem> DebugInfoItemsSection =
|
||||
new OffsettedSection<DebugInfoItem>(this, ItemType.TYPE_DEBUG_INFO_ITEM);
|
||||
|
||||
/**
|
||||
* The <code>OffsettedSection</code> containing <code>AnnotationItem</code> items
|
||||
*/
|
||||
public final OffsettedSection<AnnotationItem> AnnotationsSection =
|
||||
new OffsettedSection<AnnotationItem>(this, ItemType.TYPE_ANNOTATION_ITEM);
|
||||
|
||||
/**
|
||||
* The <code>OffsettedSection</code> containing <code>EncodedArrayItem</code> items
|
||||
*/
|
||||
public final OffsettedSection<EncodedArrayItem> EncodedArraysSection =
|
||||
new OffsettedSection<EncodedArrayItem>(this, ItemType.TYPE_ENCODED_ARRAY_ITEM);
|
||||
|
||||
/**
|
||||
* The <code>OffsettedSection</code> containing <code>AnnotationDirectoryItem</code> items
|
||||
*/
|
||||
public final OffsettedSection<AnnotationDirectoryItem> AnnotationDirectoriesSection =
|
||||
new OffsettedSection<AnnotationDirectoryItem>(this, ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM);
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the signature for the dex file in the given byte array,
|
||||
* and then writes the signature to the appropriate location in the header
|
||||
* containing in the array
|
||||
*
|
||||
* @param bytes non-null; the bytes of the file
|
||||
*/
|
||||
public static void calcSignature(byte[] bytes) {
|
||||
MessageDigest md;
|
||||
|
||||
try {
|
||||
md = MessageDigest.getInstance("SHA-1");
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
md.update(bytes, 32, bytes.length - 32);
|
||||
|
||||
try {
|
||||
int amt = md.digest(bytes, 12, 20);
|
||||
if (amt != 20) {
|
||||
throw new RuntimeException("unexpected digest write: " + amt +
|
||||
" bytes");
|
||||
}
|
||||
} catch (DigestException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the checksum for the <code>.dex</code> file in the
|
||||
* given array, and modify the array to contain it.
|
||||
*
|
||||
* @param bytes non-null; the bytes of the file
|
||||
*/
|
||||
public static void calcChecksum(byte[] bytes) {
|
||||
Adler32 a32 = new Adler32();
|
||||
|
||||
a32.update(bytes, 12, bytes.length - 12);
|
||||
|
||||
int sum = (int) a32.getValue();
|
||||
|
||||
bytes[8] = (byte) sum;
|
||||
bytes[9] = (byte) (sum >> 8);
|
||||
bytes[10] = (byte) (sum >> 16);
|
||||
bytes[11] = (byte) (sum >> 24);
|
||||
}
|
||||
}
|
138
dexlib/src/main/java/org/jf/dexlib/EncodedArrayItem.java
Normal file
138
dexlib/src/main/java/org/jf/dexlib/EncodedArrayItem.java
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.EncodedValue.ArrayEncodedSubValue;
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
public class EncodedArrayItem extends Item<EncodedArrayItem> {
|
||||
private int hashCode = 0;
|
||||
|
||||
private ArrayEncodedSubValue encodedArray;
|
||||
|
||||
/**
|
||||
* Creates a new uninitialized <code>EncodedArrayItem</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
*/
|
||||
protected EncodedArrayItem(DexFile dexFile) {
|
||||
super(dexFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>EncodedArrayItem</code> with the given values
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param encodedArray The encoded array value
|
||||
*/
|
||||
private EncodedArrayItem(DexFile dexFile, ArrayEncodedSubValue encodedArray) {
|
||||
super(dexFile);
|
||||
this.encodedArray = encodedArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an <code>EncodedArrayItem</code> for the given values, and that has been interned into the given
|
||||
* <code>DexFile</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param encodedArray The encoded array value
|
||||
* @return an <code>EncodedArrayItem</code> for the given values, and that has been interned into the given
|
||||
*/
|
||||
public static EncodedArrayItem getInternedEncodedArrayItem(DexFile dexFile, ArrayEncodedSubValue encodedArray) {
|
||||
EncodedArrayItem encodedArrayItem = new EncodedArrayItem(dexFile, encodedArray);
|
||||
return dexFile.EncodedArraysSection.intern(encodedArrayItem);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void readItem(Input in, ReadContext readContext) {
|
||||
encodedArray = new ArrayEncodedSubValue(dexFile, in);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int placeItem(int offset) {
|
||||
return encodedArray.placeValue(offset);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void writeItem(AnnotatedOutput out) {
|
||||
if (out.annotates()) {
|
||||
out.annotate("encoded_array");
|
||||
}
|
||||
encodedArray.writeValue(out);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_ENCODED_ARRAY_ITEM;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String getConciseIdentity() {
|
||||
return "encoded_array @0x" + Integer.toHexString(getOffset());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int compareTo(EncodedArrayItem encodedArrayItem) {
|
||||
return encodedArray.compareTo(encodedArrayItem.encodedArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The encoded array value
|
||||
*/
|
||||
public ArrayEncodedSubValue getEncodedArray() {
|
||||
return encodedArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate and cache the hashcode
|
||||
*/
|
||||
private void calcHashCode() {
|
||||
hashCode = encodedArray.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
//there's a small possibility that the actual hash code will be 0. If so, we'll
|
||||
//just end up recalculating it each time
|
||||
if (hashCode == 0)
|
||||
calcHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this==o) {
|
||||
return true;
|
||||
}
|
||||
if (o==null || !this.getClass().equals(o.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EncodedArrayItem other = (EncodedArrayItem)o;
|
||||
return (encodedArray.compareTo(other.encodedArray) == 0);
|
||||
}
|
||||
}
|
@ -0,0 +1,160 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.EncodedValue;
|
||||
|
||||
import org.jf.dexlib.TypeIdItem;
|
||||
import org.jf.dexlib.StringIdItem;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
import org.jf.dexlib.Util.Leb128Utils;
|
||||
|
||||
/**
|
||||
* An <code>AnnotationEncodedSubValue</code> is identical to an <code>AnnotationEncodedValue</code>, except that it
|
||||
* doesn't have the initial valueType/valueArg byte. This is used in the <code>AnnotationItem</code> object
|
||||
*/
|
||||
public class AnnotationEncodedSubValue extends EncodedValue {
|
||||
private int hashCode = 0;
|
||||
|
||||
public final TypeIdItem annotationType;
|
||||
public final StringIdItem[] names;
|
||||
public final EncodedValue[] values;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>AnnotationEncodedSubValue</code> by reading the value from the given <code>Input</code>
|
||||
* object.
|
||||
* @param dexFile The <code>DexFile</code> that is being read in
|
||||
* @param in The <code>Input</code> object to read from
|
||||
*/
|
||||
public AnnotationEncodedSubValue(DexFile dexFile, Input in) {
|
||||
annotationType = dexFile.TypeIdsSection.getItemByIndex(in.readUnsignedLeb128());
|
||||
names = new StringIdItem[in.readUnsignedLeb128()];
|
||||
values = new EncodedValue[names.length];
|
||||
|
||||
for (int i=0; i<names.length; i++) {
|
||||
names[i] = dexFile.StringIdsSection.getItemByIndex(in.readUnsignedLeb128());
|
||||
values[i] = EncodedValue.readEncodedValue(dexFile, in);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>AnnotationEncodedValue</code> with the given values. names and values must be the same
|
||||
* length, and must be sorted according to the name
|
||||
* @param annotationType The type of the annotation
|
||||
* @param names An array of the names of the elements of the annotation
|
||||
* @param values An array of the values of the elements on the annotation
|
||||
*/
|
||||
public AnnotationEncodedSubValue(TypeIdItem annotationType, StringIdItem[] names, EncodedValue[] values) {
|
||||
this.annotationType = annotationType;
|
||||
if (names.length != values.length) {
|
||||
throw new RuntimeException("The names and values parameters must be the same length");
|
||||
}
|
||||
this.names = names;
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeValue(AnnotatedOutput out) {
|
||||
out.writeUnsignedLeb128(annotationType.getIndex());
|
||||
out.writeUnsignedLeb128(names.length);
|
||||
|
||||
for (int i=0; i<names.length; i++) {
|
||||
out.writeUnsignedLeb128(names[i].getIndex());
|
||||
values[i].writeValue(out);
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int placeValue(int offset) {
|
||||
offset = offset + Leb128Utils.unsignedLeb128Size(annotationType.getIndex());
|
||||
offset = offset + Leb128Utils.unsignedLeb128Size(names.length);
|
||||
|
||||
for (int i=0; i<names.length; i++) {
|
||||
offset = offset + Leb128Utils.unsignedLeb128Size(names[i].getIndex());
|
||||
offset = values[i].placeValue(offset);
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int compareValue(EncodedValue o) {
|
||||
AnnotationEncodedSubValue other = (AnnotationEncodedSubValue)o;
|
||||
|
||||
int comp = annotationType.compareTo(other.annotationType);
|
||||
if (comp != 0) {
|
||||
return comp;
|
||||
}
|
||||
|
||||
comp = names.length - other.names.length;
|
||||
if (comp != 0) {
|
||||
return comp;
|
||||
}
|
||||
|
||||
for (int i=0; i<names.length; i++) {
|
||||
comp = names[i].compareTo(other.names[i]);
|
||||
if (comp != 0) {
|
||||
return comp;
|
||||
}
|
||||
|
||||
comp = values[i].compareTo(other.values[i]);
|
||||
if (comp != 0) {
|
||||
return comp;
|
||||
}
|
||||
}
|
||||
|
||||
return comp;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ValueType getValueType() {
|
||||
return ValueType.VALUE_ANNOTATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate and cache the hashcode
|
||||
*/
|
||||
private void calcHashCode() {
|
||||
hashCode = annotationType.hashCode();
|
||||
|
||||
for (int i=0; i<names.length; i++) {
|
||||
hashCode = 31 * hashCode + names[i].hashCode();
|
||||
hashCode = 31 * hashCode + values[i].hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
//there's a small possibility that the actual hash code will be 0. If so, we'll
|
||||
//just end up recalculating it each time
|
||||
if (hashCode == 0)
|
||||
calcHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.EncodedValue;
|
||||
|
||||
import org.jf.dexlib.StringIdItem;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.TypeIdItem;
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
public class AnnotationEncodedValue extends AnnotationEncodedSubValue {
|
||||
/**
|
||||
* Constructs a new <code>AnnotationEncodedValue</code> by reading the value from the given <code>Input</code>
|
||||
* object. The <code>Input</code>'s cursor should be set to the 2nd byte of the encoded value
|
||||
* @param dexFile The <code>DexFile</code> that is being read in
|
||||
* @param in The <code>Input</code> object to read from
|
||||
*/
|
||||
protected AnnotationEncodedValue(DexFile dexFile, Input in) {
|
||||
super(dexFile, in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>AnnotationEncodedValue</code> with the given values. names and values must be the same
|
||||
* length, and must be sorted according to the name
|
||||
* @param annotationType The type of the annotation
|
||||
* @param names An array of the names of the elements of the annotation
|
||||
* @param values An array of the values of the elements on the annotation
|
||||
*/
|
||||
public AnnotationEncodedValue(TypeIdItem annotationType, StringIdItem[] names, EncodedValue[] values) {
|
||||
super(annotationType, names, values);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeValue(AnnotatedOutput out) {
|
||||
out.writeByte(ValueType.VALUE_ANNOTATION.value);
|
||||
super.writeValue(out);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int placeValue(int offset) {
|
||||
return super.placeValue(offset + 1);
|
||||
}
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.EncodedValue;
|
||||
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
import org.jf.dexlib.Util.Leb128Utils;
|
||||
|
||||
/**
|
||||
* An <code>ArrayEncodedSubValue</code> is identical to an <code>ArrayEncodedValue</code>, except that it
|
||||
* doesn't have the initial valueType/valueArg byte. This is used in the <code>EncodedArrayItem</code> object
|
||||
*/
|
||||
public class ArrayEncodedSubValue extends EncodedValue {
|
||||
private int hashCode = 0;
|
||||
|
||||
public final EncodedValue[] values;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>ArrayEncodedSubValue</code> by reading the value from the given <code>Input</code> object.
|
||||
* The <code>Input</code>'s cursor should be set to the 2nd byte of the encoded value
|
||||
* @param dexFile The <code>DexFile</code> that is being read in
|
||||
* @param in The <code>Input</code> object to read from
|
||||
*/
|
||||
public ArrayEncodedSubValue(DexFile dexFile, Input in) {
|
||||
values = new EncodedValue[in.readUnsignedLeb128()];
|
||||
|
||||
for (int i=0; i<values.length; i++) {
|
||||
values[i] = EncodedValue.readEncodedValue(dexFile, in);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>ArrayEncodedSubValue</code> with the given values
|
||||
* @param values The array values
|
||||
*/
|
||||
public ArrayEncodedSubValue(EncodedValue[] values) {
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeValue(AnnotatedOutput out) {
|
||||
out.writeByte(ValueType.VALUE_ARRAY.value);
|
||||
out.writeUnsignedLeb128(values.length);
|
||||
for (EncodedValue encodedValue: values) {
|
||||
encodedValue.writeValue(out);
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int placeValue(int offset) {
|
||||
offset = offset + 1 + Leb128Utils.unsignedLeb128Size(values.length);
|
||||
for (EncodedValue encodedValue: values) {
|
||||
offset = encodedValue.placeValue(offset);
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int compareValue(EncodedValue o) {
|
||||
ArrayEncodedSubValue other = (ArrayEncodedSubValue)o;
|
||||
|
||||
int comp = values.length - other.values.length;
|
||||
if (comp != 0) {
|
||||
return comp;
|
||||
}
|
||||
|
||||
for (int i=0; i<values.length; i++) {
|
||||
comp = values[i].compareValue(other.values[i]);
|
||||
if (comp != 0) {
|
||||
return comp;
|
||||
}
|
||||
}
|
||||
|
||||
return comp;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ValueType getValueType() {
|
||||
return ValueType.VALUE_ARRAY;
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate and cache the hashcode
|
||||
*/
|
||||
private void calcHashCode() {
|
||||
hashCode = 0;
|
||||
|
||||
for (EncodedValue encodedValue: values) {
|
||||
hashCode = 31 * hashCode + encodedValue.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
//there's a small possibility that the actual hash code will be 0. If so, we'll
|
||||
//just end up recalculating it each time
|
||||
if (hashCode == 0)
|
||||
calcHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.EncodedValue;
|
||||
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
import org.jf.dexlib.DexFile;
|
||||
|
||||
public class ArrayEncodedValue extends ArrayEncodedSubValue {
|
||||
/**
|
||||
* Constructs a new <code>ArrayEncodedValue</code> by reading the value from the given <code>Input</code> object.
|
||||
* The <code>Input</code>'s cursor should be set to the 2nd byte of the encoded value
|
||||
* @param dexFile The <code>DexFile</code> that is being read in
|
||||
* @param in The <code>Input</code> object to read from
|
||||
*/
|
||||
protected ArrayEncodedValue(DexFile dexFile, Input in) {
|
||||
super(dexFile, in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>ArrayEncodedValue</code> with the given values
|
||||
* @param values The array values
|
||||
*/
|
||||
public ArrayEncodedValue(EncodedValue[] values) {
|
||||
super(values);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeValue(AnnotatedOutput out) {
|
||||
out.writeByte(ValueType.VALUE_ARRAY.value);
|
||||
super.writeValue(out);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int placeValue(int offset) {
|
||||
return super.placeValue(offset + 1);
|
||||
}
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.EncodedValue;
|
||||
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
public class BooleanEncodedValue extends EncodedValue {
|
||||
/**
|
||||
* The dupliton values
|
||||
*/
|
||||
public static final BooleanEncodedValue TrueValue = new BooleanEncodedValue(true);
|
||||
public static final BooleanEncodedValue FalseValue = new BooleanEncodedValue(false);
|
||||
|
||||
public final boolean value;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>BooleanEncodedValue</code> with the given value
|
||||
* @param value The value
|
||||
*/
|
||||
private BooleanEncodedValue(boolean value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <code>BooleanEncodedValue</code> for the given valueArg value. The high 3 bits of the first byte should
|
||||
* be passed as the valueArg parameter
|
||||
* @param valueArg The high 3 bits of the first byte of this encoded value
|
||||
* @return the <code>BooleanEncodedValue</code> for the given valueArg value
|
||||
*/
|
||||
protected static BooleanEncodedValue getBooleanEncodedValue(byte valueArg) {
|
||||
if (valueArg == 0) {
|
||||
return FalseValue;
|
||||
} else if (valueArg == 1) {
|
||||
return TrueValue;
|
||||
}
|
||||
throw new RuntimeException("valueArg must be either 0 or 1");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <code>BooleanEncodedValue</code> for the given boolean value
|
||||
* @param value the boolean value
|
||||
* @return the <code>BooleanEncodedValue</code> for the given boolean value
|
||||
*/
|
||||
public static BooleanEncodedValue getBooleanEncodedValue(boolean value) {
|
||||
if (value) {
|
||||
return TrueValue;
|
||||
}
|
||||
return FalseValue;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeValue(AnnotatedOutput out) {
|
||||
out.writeByte(ValueType.VALUE_BOOLEAN.value | (value?1:0 << 5));
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int placeValue(int offset) {
|
||||
return offset + 1;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int compareValue(EncodedValue o) {
|
||||
BooleanEncodedValue other = (BooleanEncodedValue)o;
|
||||
if (value == other.value)
|
||||
return 0;
|
||||
if (value)
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ValueType getValueType() {
|
||||
return ValueType.VALUE_BOOLEAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value?1:0;
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.EncodedValue;
|
||||
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.EncodedValueUtils;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
public class ByteEncodedValue extends EncodedValue {
|
||||
public final byte value;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>ByteEncodedValue</code> by reading the value from the given <code>Input</code> object.
|
||||
* The <code>Input</code>'s cursor should be set to the 2nd byte of the encoded value
|
||||
* @param in The <code>Input</code> object to read from
|
||||
*/
|
||||
protected ByteEncodedValue(Input in) {
|
||||
value = (byte)EncodedValueUtils.decodeSignedIntegralValue(in.readBytes(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>ByteEncodedValue</code> with the given value
|
||||
* @param value The value
|
||||
*/
|
||||
public ByteEncodedValue(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeValue(AnnotatedOutput out) {
|
||||
out.writeByte(ValueType.VALUE_BYTE.value);
|
||||
out.writeByte(value);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int placeValue(int offset) {
|
||||
return offset + 2;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int compareValue(EncodedValue o) {
|
||||
ByteEncodedValue other = (ByteEncodedValue)o;
|
||||
|
||||
return value - other.value;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ValueType getValueType() {
|
||||
return ValueType.VALUE_BYTE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value;
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.EncodedValue;
|
||||
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.EncodedValueUtils;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
public class CharEncodedValue extends EncodedValue {
|
||||
public final char value;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>CharEncodedValue</code> by reading the value from the given <code>Input</code> object.
|
||||
* The <code>Input</code>'s cursor should be set to the 2nd byte of the encoded value, and the high 3 bits of
|
||||
* the first byte should be passed as the valueArg parameter
|
||||
* @param in The <code>Input</code> object to read from
|
||||
* @param valueArg The high 3 bits of the first byte of this encoded value
|
||||
*/
|
||||
protected CharEncodedValue(Input in, byte valueArg) {
|
||||
value = (char)EncodedValueUtils.decodeUnsignedIntegralValue(in.readBytes(valueArg+1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>CharEncodedValue</code> with the given value
|
||||
* @param value The value
|
||||
*/
|
||||
public CharEncodedValue(char value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeValue(AnnotatedOutput out) {
|
||||
byte[] bytes = EncodedValueUtils.encodeUnsignedIntegralValue(value);
|
||||
out.writeByte(ValueType.VALUE_CHAR.value | ((bytes.length - 1) << 5));
|
||||
out.write(bytes);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int placeValue(int offset) {
|
||||
return offset + EncodedValueUtils.getRequiredBytesForUnsignedIntegralValue(value) + 1;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int compareValue(EncodedValue o) {
|
||||
CharEncodedValue other = (CharEncodedValue)o;
|
||||
|
||||
return value - other.value;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ValueType getValueType() {
|
||||
return ValueType.VALUE_CHAR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value;
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.EncodedValue;
|
||||
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.EncodedValueUtils;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
public class DoubleEncodedValue extends EncodedValue {
|
||||
public final double value;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>DoubleEncodedValue</code> by reading the value from the given <code>Input</code> object.
|
||||
* The <code>Input</code>'s cursor should be set to the 2nd byte of the encoded value, and the high 3 bits of
|
||||
* the first byte should be passed as the valueArg parameter
|
||||
* @param in The <code>Input</code> object to read from
|
||||
* @param valueArg The high 3 bits of the first byte of this encoded value
|
||||
*/
|
||||
protected DoubleEncodedValue(Input in, byte valueArg) {
|
||||
long longValue = EncodedValueUtils.decodeRightZeroExtendedValue(in.readBytes(valueArg + 1));
|
||||
value = Double.longBitsToDouble(longValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>DoubleEncodedValue</code> with the given value
|
||||
* @param value The value
|
||||
*/
|
||||
public DoubleEncodedValue(double value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeValue(AnnotatedOutput out) {
|
||||
byte[] bytes = EncodedValueUtils.encodeRightZeroExtendedValue(Double.doubleToRawLongBits(value));
|
||||
out.writeByte(ValueType.VALUE_DOUBLE.value | ((bytes.length - 1) << 5));
|
||||
out.write(bytes);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int placeValue(int offset) {
|
||||
return offset + 1 + EncodedValueUtils.getRequiredBytesForRightZeroExtendedValue(
|
||||
Double.doubleToRawLongBits(value));
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int compareValue(EncodedValue o) {
|
||||
DoubleEncodedValue other = (DoubleEncodedValue)o;
|
||||
|
||||
return Double.compare(value, other.value);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ValueType getValueType() {
|
||||
return ValueType.VALUE_DOUBLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (int)Double.doubleToRawLongBits(value);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.EncodedValue;
|
||||
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
import org.jf.dexlib.DexFile;
|
||||
|
||||
public abstract class EncodedValue implements Comparable<EncodedValue> {
|
||||
/**
|
||||
* Writes this <code>EncodedValue</code> to the given <code>AnnotatedOutput</code> object
|
||||
* @param out the <code>AnnotatedOutput</code> object to write to
|
||||
*/
|
||||
public abstract void writeValue(AnnotatedOutput out);
|
||||
|
||||
/**
|
||||
* Calculates the size of this encoded value and returns offset + size;
|
||||
* @param offset The offset to place this encoded value
|
||||
* @return the offset immediately after this encoded value
|
||||
*/
|
||||
public abstract int placeValue(int offset);
|
||||
|
||||
|
||||
public static EncodedValue readEncodedValue(DexFile dexFile, Input in) {
|
||||
Byte b = in.readByte();
|
||||
ValueType valueType = ValueType.fromByte((byte)(b & 0x1f));
|
||||
byte valueArg = (byte)((b & 0xFF) >> 5);
|
||||
|
||||
switch (valueType) {
|
||||
case VALUE_BYTE:
|
||||
return new ByteEncodedValue(in);
|
||||
case VALUE_SHORT:
|
||||
return new ShortEncodedValue(in, valueArg);
|
||||
case VALUE_CHAR:
|
||||
return new CharEncodedValue(in, valueArg);
|
||||
case VALUE_INT:
|
||||
return new IntEncodedValue(in, valueArg);
|
||||
case VALUE_LONG:
|
||||
return new LongEncodedValue(in, valueArg);
|
||||
case VALUE_FLOAT:
|
||||
return new FloatEncodedValue(in, valueArg);
|
||||
case VALUE_DOUBLE:
|
||||
return new DoubleEncodedValue(in, valueArg);
|
||||
case VALUE_STRING:
|
||||
return new StringEncodedValue(dexFile, in, valueArg);
|
||||
case VALUE_TYPE:
|
||||
return new TypeEncodedValue(dexFile, in, valueArg);
|
||||
case VALUE_FIELD:
|
||||
return new FieldEncodedValue(dexFile, in, valueArg);
|
||||
case VALUE_METHOD:
|
||||
return new MethodEncodedValue(dexFile, in, valueArg);
|
||||
case VALUE_ENUM:
|
||||
return new EnumEncodedValue(dexFile, in, valueArg);
|
||||
case VALUE_ARRAY:
|
||||
return new ArrayEncodedValue(dexFile, in);
|
||||
case VALUE_ANNOTATION:
|
||||
return new AnnotationEncodedValue(dexFile, in);
|
||||
case VALUE_NULL:
|
||||
return NullEncodedValue.NullValue;
|
||||
case VALUE_BOOLEAN:
|
||||
return BooleanEncodedValue.getBooleanEncodedValue(valueArg);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int compareTo(EncodedValue o) {
|
||||
int comp = getValueType().compareTo(o.getValueType());
|
||||
if (comp == 0) {
|
||||
comp = compareValue(o);
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the value of this <code>EncodedValue</code> against the value of the given <EncodedValue>, which
|
||||
* is guaranteed to be of the same type as this <code>EncodedValue</code>
|
||||
* @param o The <code>EncodedValue</code> to compare against
|
||||
* @return A standard comparison integer value
|
||||
*/
|
||||
protected abstract int compareValue(EncodedValue o);
|
||||
|
||||
/**
|
||||
* @return the <code>ValueType</code> representing the type of this <code>EncodedValue</code>
|
||||
*/
|
||||
public abstract ValueType getValueType();
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this==o) {
|
||||
return true;
|
||||
}
|
||||
if (o==null || !(o instanceof EncodedValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.compareTo((EncodedValue)o) == 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.EncodedValue;
|
||||
|
||||
import org.jf.dexlib.FieldIdItem;
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.EncodedValueUtils;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
public class EnumEncodedValue extends EncodedValue {
|
||||
public final FieldIdItem value;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>EnumEncodedValue</code> by reading the field index from the given <code>Input</code>
|
||||
* object. The <code>Input</code>'s cursor should be set to the 2nd byte of the encoded value, and the high 3 bits
|
||||
* of the first byte should be passed as the valueArg parameter
|
||||
* @param dexFile The <code>DexFile</code> that is being read in
|
||||
* @param in The <code>Input</code> object to read from
|
||||
* @param valueArg The high 3 bits of the first byte of this encoded value
|
||||
*/
|
||||
protected EnumEncodedValue(DexFile dexFile, Input in, byte valueArg) {
|
||||
int index = (int) EncodedValueUtils.decodeUnsignedIntegralValue(in.readBytes(valueArg+1));
|
||||
value = dexFile.FieldIdsSection.getItemByIndex(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>EnumEncodedValue</code> with the given <code>FieldIdItem</code> value
|
||||
* @param value The <code>FieldIdItem</code> value
|
||||
*/
|
||||
public EnumEncodedValue(FieldIdItem value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeValue(AnnotatedOutput out) {
|
||||
byte[] bytes = EncodedValueUtils.encodeUnsignedIntegralValue(value.getIndex());
|
||||
out.writeByte(ValueType.VALUE_ENUM.value | ((bytes.length - 1) << 5));
|
||||
out.write(bytes);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int placeValue(int offset) {
|
||||
return offset + EncodedValueUtils.getRequiredBytesForUnsignedIntegralValue(value.getIndex()) + 1;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int compareValue(EncodedValue o) {
|
||||
EnumEncodedValue other = (EnumEncodedValue)o;
|
||||
|
||||
return value.getIndex() - other.value.getIndex();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ValueType getValueType() {
|
||||
return ValueType.VALUE_ENUM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value.hashCode();
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.EncodedValue;
|
||||
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.FieldIdItem;
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.EncodedValueUtils;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
public class FieldEncodedValue extends EncodedValue {
|
||||
public final FieldIdItem value;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>FieldEncodedValue</code> by reading the field index from the given <code>Input</code>
|
||||
* object. The <code>Input</code>'s cursor should be set to the 2nd byte of the encoded value, and the high 3 bits
|
||||
* of the first byte should be passed as the valueArg parameter
|
||||
* @param dexFile The <code>DexFile</code> that is being read in
|
||||
* @param in The <code>Input</code> object to read from
|
||||
* @param valueArg The high 3 bits of the first byte of this encoded value
|
||||
*/
|
||||
protected FieldEncodedValue(DexFile dexFile, Input in, byte valueArg) {
|
||||
int index = (int) EncodedValueUtils.decodeUnsignedIntegralValue(in.readBytes(valueArg+1));
|
||||
value = dexFile.FieldIdsSection.getItemByIndex(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>FieldEncodedValue</code> with the given <code>FieldIdItem</code> value
|
||||
* @param value The <code>FieldIdItem</code> value
|
||||
*/
|
||||
public FieldEncodedValue(FieldIdItem value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeValue(AnnotatedOutput out) {
|
||||
byte[] bytes = EncodedValueUtils.encodeUnsignedIntegralValue(value.getIndex());
|
||||
out.writeByte(ValueType.VALUE_FIELD.value | ((bytes.length - 1) << 5));
|
||||
out.write(bytes);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int placeValue(int offset) {
|
||||
return offset + EncodedValueUtils.getRequiredBytesForUnsignedIntegralValue(value.getIndex()) + 1;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int compareValue(EncodedValue o) {
|
||||
FieldEncodedValue other = (FieldEncodedValue)o;
|
||||
|
||||
return value.getIndex()-other.value.getIndex();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ValueType getValueType() {
|
||||
return ValueType.VALUE_FIELD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value.hashCode();
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.EncodedValue;
|
||||
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.EncodedValueUtils;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
public class FloatEncodedValue extends EncodedValue {
|
||||
public final float value;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>FloatEncodedValue</code> by reading the value from the given <code>Input</code> object.
|
||||
* The <code>Input</code>'s cursor should be set to the 2nd byte of the encoded value, and the high 3 bits of
|
||||
* the first byte should be passed as the valueArg parameter
|
||||
* @param in The <code>Input</code> object to read from
|
||||
* @param valueArg The high 3 bits of the first byte of this encoded value
|
||||
*/
|
||||
protected FloatEncodedValue(Input in, byte valueArg) {
|
||||
long longValue = EncodedValueUtils.decodeRightZeroExtendedValue(in.readBytes(valueArg + 1));
|
||||
value = Float.intBitsToFloat((int)((longValue >> 32) & 0xFFFFFFFFL));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>FloatEncodedValue</code> with the given value
|
||||
* @param value The value
|
||||
*/
|
||||
public FloatEncodedValue(float value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeValue(AnnotatedOutput out) {
|
||||
byte[] bytes = EncodedValueUtils.encodeRightZeroExtendedValue(((long)Float.floatToRawIntBits(value)) << 32);
|
||||
out.writeByte(ValueType.VALUE_FLOAT.value | ((bytes.length - 1) << 5));
|
||||
out.write(bytes);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int placeValue(int offset) {
|
||||
return offset + 1 + EncodedValueUtils.getRequiredBytesForRightZeroExtendedValue(
|
||||
((long)Float.floatToRawIntBits(value)) << 32);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int compareValue(EncodedValue o) {
|
||||
FloatEncodedValue other = (FloatEncodedValue)o;
|
||||
|
||||
return Float.compare(value, other.value);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ValueType getValueType() {
|
||||
return ValueType.VALUE_FLOAT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Float.floatToRawIntBits(value);
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.EncodedValue;
|
||||
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
import org.jf.dexlib.Util.EncodedValueUtils;
|
||||
|
||||
public class IntEncodedValue extends EncodedValue {
|
||||
public final int value;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>IntEncodedValue</code> by reading the value from the given <code>Input</code> object.
|
||||
* The <code>Input</code>'s cursor should be set to the 2nd byte of the encoded value, and the high 3 bits of
|
||||
* the first byte should be passed as the valueArg parameter
|
||||
* @param in The <code>Input</code> object to read from
|
||||
* @param valueArg The high 3 bits of the first byte of this encoded value
|
||||
*/
|
||||
protected IntEncodedValue(Input in, byte valueArg) {
|
||||
value = (int)EncodedValueUtils.decodeSignedIntegralValue(in.readBytes(valueArg+1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>IntEncodedValue</code> with the given value
|
||||
* @param value The value
|
||||
*/
|
||||
public IntEncodedValue(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeValue(AnnotatedOutput out) {
|
||||
byte[] bytes = EncodedValueUtils.encodeSignedIntegralValue(value);
|
||||
out.writeByte(ValueType.VALUE_INT.value | ((bytes.length - 1) << 5));
|
||||
out.write(bytes);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int placeValue(int offset) {
|
||||
return offset + EncodedValueUtils.getRequiredBytesForSignedIntegralValue(value) + 1;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int compareValue(EncodedValue o) {
|
||||
IntEncodedValue other = (IntEncodedValue)o;
|
||||
|
||||
return value - other.value;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ValueType getValueType() {
|
||||
return ValueType.VALUE_INT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value;
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.EncodedValue;
|
||||
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.EncodedValueUtils;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
public class LongEncodedValue extends EncodedValue {
|
||||
public final long value;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>LongEncodedValue</code> by reading the value from the given <code>Input</code> object.
|
||||
* The <code>Input</code>'s cursor should be set to the 2nd byte of the encoded value, and the high 3 bits of
|
||||
* the first byte should be passed as the valueArg parameter
|
||||
* @param in The <code>Input</code> object to read from
|
||||
* @param valueArg The high 3 bits of the first byte of this encoded value
|
||||
*/
|
||||
protected LongEncodedValue(Input in, byte valueArg) {
|
||||
value = EncodedValueUtils.decodeSignedIntegralValue(in.readBytes(valueArg+1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>LongEncodedValue</code> with the given value
|
||||
* @param value The value
|
||||
*/
|
||||
public LongEncodedValue(long value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeValue(AnnotatedOutput out) {
|
||||
byte[] bytes = EncodedValueUtils.encodeSignedIntegralValue(value);
|
||||
out.writeByte(ValueType.VALUE_LONG.value | ((bytes.length - 1) << 5));
|
||||
out.write(bytes);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int placeValue(int offset) {
|
||||
return offset + EncodedValueUtils.getRequiredBytesForSignedIntegralValue(value) + 1;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int compareValue(EncodedValue o) {
|
||||
LongEncodedValue other = (LongEncodedValue)o;
|
||||
|
||||
return Long.signum(value - other.value);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ValueType getValueType() {
|
||||
return ValueType.VALUE_LONG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (int)value;
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.EncodedValue;
|
||||
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.MethodIdItem;
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.EncodedValueUtils;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
public class MethodEncodedValue extends EncodedValue {
|
||||
public final MethodIdItem value;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>MethodEncodedValue</code> by reading the method index from the given <code>Input</code>
|
||||
* object. The <code>Input</code>'s cursor should be set to the 2nd byte of the encoded value, and the high 3 bits
|
||||
* of the first byte should be passed as the valueArg parameter
|
||||
* @param dexFile The <code>DexFile</code> that is being read in
|
||||
* @param in The <code>Input</code> object to read from
|
||||
* @param valueArg The high 3 bits of the first byte of this encoded value
|
||||
*/
|
||||
protected MethodEncodedValue(DexFile dexFile, Input in, byte valueArg) {
|
||||
int index = (int) EncodedValueUtils.decodeUnsignedIntegralValue(in.readBytes(valueArg+1));
|
||||
value = dexFile.MethodIdsSection.getItemByIndex(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>MethodEncodedValue</code> with the given <code>MethodIdItem</code> value
|
||||
* @param value The <code>MethodIdItem</code> value
|
||||
*/
|
||||
public MethodEncodedValue(MethodIdItem value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeValue(AnnotatedOutput out) {
|
||||
byte[] bytes = EncodedValueUtils.encodeUnsignedIntegralValue(value.getIndex());
|
||||
out.writeByte(ValueType.VALUE_METHOD.value | ((bytes.length - 1) << 5));
|
||||
out.write(bytes);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int placeValue(int offset) {
|
||||
return offset + EncodedValueUtils.getRequiredBytesForUnsignedIntegralValue(value.getIndex()) + 1;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int compareValue(EncodedValue o) {
|
||||
MethodEncodedValue other = (MethodEncodedValue)o;
|
||||
|
||||
return value.getIndex() - other.value.getIndex();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ValueType getValueType() {
|
||||
return ValueType.VALUE_METHOD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value.hashCode();
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.EncodedValue;
|
||||
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
public class NullEncodedValue extends EncodedValue {
|
||||
/**
|
||||
* The singleton value
|
||||
*/
|
||||
public static final NullEncodedValue NullValue = new NullEncodedValue();
|
||||
|
||||
/**
|
||||
* Constructs a new <code>NullEncodedValue</code>
|
||||
*/
|
||||
private NullEncodedValue() {
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeValue(AnnotatedOutput out) {
|
||||
out.writeByte(ValueType.VALUE_NULL.value);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int placeValue(int offset) {
|
||||
return offset + 1;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int compareValue(EncodedValue o) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ValueType getValueType() {
|
||||
return ValueType.VALUE_NULL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 1;
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.EncodedValue;
|
||||
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.EncodedValueUtils;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
public class ShortEncodedValue extends EncodedValue {
|
||||
public final short value;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>ShortEncodedValue</code> by reading the value from the given <code>Input</code> object.
|
||||
* The <code>Input</code>'s cursor should be set to the 2nd byte of the encoded value, and the high 3 bits of
|
||||
* the first byte should be passed as the valueArg parameter
|
||||
* @param in The <code>Input</code> object to read from
|
||||
* @param valueArg The high 3 bits of the first byte of this encoded value
|
||||
*/
|
||||
protected ShortEncodedValue(Input in, byte valueArg) {
|
||||
value = (short) EncodedValueUtils.decodeSignedIntegralValue(in.readBytes(valueArg+1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>ShortEncodedValue</code> with the given value
|
||||
* @param value The value
|
||||
*/
|
||||
public ShortEncodedValue(short value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeValue(AnnotatedOutput out) {
|
||||
byte[] bytes = EncodedValueUtils.encodeSignedIntegralValue(value);
|
||||
out.writeByte(ValueType.VALUE_SHORT.value | ((bytes.length - 1) << 5));
|
||||
out.write(bytes);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int placeValue(int offset) {
|
||||
return offset + EncodedValueUtils.getRequiredBytesForSignedIntegralValue(value) + 1;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int compareValue(EncodedValue o) {
|
||||
ShortEncodedValue other = (ShortEncodedValue)o;
|
||||
|
||||
return value - other.value;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ValueType getValueType() {
|
||||
return ValueType.VALUE_SHORT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value;
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.EncodedValue;
|
||||
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.EncodedValueUtils;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
import org.jf.dexlib.StringIdItem;
|
||||
import org.jf.dexlib.DexFile;
|
||||
|
||||
public class StringEncodedValue extends EncodedValue {
|
||||
public final StringIdItem value;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>StringEncodedValue</code> by reading the string index from the given <code>Input</code>
|
||||
* object. The <code>Input</code>'s cursor should be set to the 2nd byte of the encoded value, and the high 3 bits
|
||||
* of the first byte should be passed as the valueArg parameter
|
||||
* @param dexFile The <code>DexFile</code> that is being read in
|
||||
* @param in The <code>Input</code> object to read from
|
||||
* @param valueArg The high 3 bits of the first byte of this encoded value
|
||||
*/
|
||||
protected StringEncodedValue(DexFile dexFile, Input in, byte valueArg) {
|
||||
int index = (int)EncodedValueUtils.decodeUnsignedIntegralValue(in.readBytes(valueArg+1));
|
||||
value = dexFile.StringIdsSection.getItemByIndex(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>StringEncodedValue</code> with the given <code>StringIdItem</code> value
|
||||
* @param value The <code>StringIdItem</code> value
|
||||
*/
|
||||
public StringEncodedValue(StringIdItem value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeValue(AnnotatedOutput out) {
|
||||
byte[] bytes = EncodedValueUtils.encodeUnsignedIntegralValue(value.getIndex());
|
||||
out.writeByte(ValueType.VALUE_STRING.value | ((bytes.length - 1) << 5));
|
||||
out.write(bytes);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int placeValue(int offset) {
|
||||
return offset + EncodedValueUtils.getRequiredBytesForUnsignedIntegralValue(value.getIndex()) + 1;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int compareValue(EncodedValue o) {
|
||||
StringEncodedValue other = (StringEncodedValue)o;
|
||||
|
||||
return value.getIndex() - other.value.getIndex();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ValueType getValueType() {
|
||||
return ValueType.VALUE_STRING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value.hashCode();
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.EncodedValue;
|
||||
|
||||
import org.jf.dexlib.DexFile;
|
||||
import org.jf.dexlib.TypeIdItem;
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.EncodedValueUtils;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
public class TypeEncodedValue extends EncodedValue {
|
||||
public final TypeIdItem value;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>TypeEncodedValue</code> by reading the type index from the given <code>Input</code>
|
||||
* object. The <code>Input</code>'s cursor should be set to the 2nd byte of the encoded value, and the high 3 bits
|
||||
* of the first byte should be passed as the valueArg parameter
|
||||
* @param dexFile The <code>DexFile</code> that is being read in
|
||||
* @param in The <code>Input</code> object to read from
|
||||
* @param valueArg The high 3 bits of the first byte of this encoded value
|
||||
*/
|
||||
protected TypeEncodedValue(DexFile dexFile, Input in, byte valueArg) {
|
||||
int index = (int) EncodedValueUtils.decodeUnsignedIntegralValue(in.readBytes(valueArg+1));
|
||||
value = dexFile.TypeIdsSection.getItemByIndex(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <code>TypeEncodedValue</code> with the given <code>TypeIdItem</code> value
|
||||
* @param value The <code>TypeIdItem</code> value
|
||||
*/
|
||||
public TypeEncodedValue(TypeIdItem value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeValue(AnnotatedOutput out) {
|
||||
byte[] bytes = EncodedValueUtils.encodeUnsignedIntegralValue(value.getIndex());
|
||||
out.writeByte(ValueType.VALUE_TYPE.value | ((bytes.length - 1) << 5));
|
||||
out.write(bytes);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int placeValue(int offset) {
|
||||
return offset + EncodedValueUtils.getRequiredBytesForUnsignedIntegralValue(value.getIndex()) + 1;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int compareValue(EncodedValue o) {
|
||||
TypeEncodedValue other = (TypeEncodedValue)o;
|
||||
|
||||
return value.getIndex() - other.value.getIndex();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ValueType getValueType() {
|
||||
return ValueType.VALUE_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value.hashCode();
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.EncodedValue;
|
||||
|
||||
import org.jf.dexlib.Util.SparseArray;
|
||||
|
||||
public enum ValueType {
|
||||
|
||||
VALUE_BYTE((byte) 0x00),
|
||||
VALUE_SHORT((byte) 0x02),
|
||||
VALUE_CHAR((byte) 0x03),
|
||||
VALUE_INT((byte) 0x04),
|
||||
VALUE_LONG((byte) 0x06),
|
||||
VALUE_FLOAT((byte) 0x10),
|
||||
VALUE_DOUBLE((byte) 0x11),
|
||||
VALUE_STRING((byte) 0x17),
|
||||
VALUE_TYPE((byte) 0x18),
|
||||
VALUE_FIELD((byte) 0x19),
|
||||
VALUE_METHOD((byte) 0x1a),
|
||||
VALUE_ENUM((byte) 0x1b),
|
||||
VALUE_ARRAY((byte) 0x1c),
|
||||
VALUE_ANNOTATION((byte) 0x1d),
|
||||
VALUE_NULL((byte) 0x1e),
|
||||
VALUE_BOOLEAN((byte) 0x1f);
|
||||
|
||||
/**
|
||||
* A map to facilitate looking up a <code>ValueType</code> by byte value
|
||||
*/
|
||||
private final static SparseArray<ValueType> valueTypeIntegerMap;
|
||||
|
||||
static {
|
||||
/** build the <code>valueTypeIntegerMap</code> object */
|
||||
valueTypeIntegerMap = new SparseArray<ValueType>(16);
|
||||
|
||||
for (ValueType valueType : ValueType.values()) {
|
||||
valueTypeIntegerMap.put(valueType.value, valueType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The byte value for this ValueType
|
||||
*/
|
||||
public final byte value;
|
||||
|
||||
private ValueType(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a byte value to the corresponding ValueType enum value,
|
||||
* or null if the value isn't a valid ValueType value
|
||||
*
|
||||
* @param valueType the byte value to convert to a ValueType
|
||||
* @return the ValueType enum value corresponding to valueType, or null
|
||||
* if not a valid ValueType value
|
||||
*/
|
||||
public static ValueType fromByte(byte valueType) {
|
||||
return valueTypeIntegerMap.get(valueType);
|
||||
}
|
||||
}
|
196
dexlib/src/main/java/org/jf/dexlib/FieldIdItem.java
Normal file
196
dexlib/src/main/java/org/jf/dexlib/FieldIdItem.java
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
public class FieldIdItem extends Item<FieldIdItem> {
|
||||
private int hashCode = 0;
|
||||
|
||||
private TypeIdItem classType;
|
||||
private TypeIdItem fieldType;
|
||||
private StringIdItem fieldName;
|
||||
|
||||
/**
|
||||
* Creates a new uninitialized <code>FieldIdItem</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
*/
|
||||
protected FieldIdItem(DexFile dexFile) {
|
||||
super(dexFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>FieldIdItem</code> for the given class, type and name
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param classType the class that the field is a member of
|
||||
* @param fieldType the type of the field
|
||||
* @param fieldName the name of the field
|
||||
*/
|
||||
private FieldIdItem(DexFile dexFile, TypeIdItem classType, TypeIdItem fieldType, StringIdItem fieldName) {
|
||||
this(dexFile);
|
||||
|
||||
assert classType.dexFile == dexFile;
|
||||
assert fieldType.dexFile == dexFile;
|
||||
assert fieldName.dexFile == dexFile;
|
||||
|
||||
this.classType = classType;
|
||||
this.fieldType = fieldType;
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <code>FieldIdItem</code> for the given values, and that has been interned into
|
||||
* the given <code>DexFile</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param classType the class that the field is a member of
|
||||
* @param fieldType the type of the field
|
||||
* @param fieldName the name of the field
|
||||
* @return a <code>FieldIdItem</code> for the given values, and that has been interned into
|
||||
* the given <code>DexFile</code>
|
||||
*/
|
||||
public static FieldIdItem getInternedFieldIdItem(DexFile dexFile, TypeIdItem classType, TypeIdItem fieldType,
|
||||
StringIdItem fieldName) {
|
||||
FieldIdItem fieldIdItem = new FieldIdItem(dexFile, classType, fieldType, fieldName);
|
||||
return dexFile.FieldIdsSection.intern(fieldIdItem);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void readItem(Input in, ReadContext readContext) {
|
||||
classType = dexFile.TypeIdsSection.getItemByIndex(in.readShort());
|
||||
fieldType = dexFile.TypeIdsSection.getItemByIndex(in.readShort());
|
||||
fieldName = dexFile.StringIdsSection.getItemByIndex(in.readInt());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int placeItem(int offset) {
|
||||
return offset + 8;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void writeItem(AnnotatedOutput out) {
|
||||
if (out.annotates()) {
|
||||
out.annotate(2, classType.getConciseIdentity());
|
||||
out.annotate(2, fieldType.getConciseIdentity());
|
||||
out.annotate(4, fieldName.getConciseIdentity());
|
||||
}
|
||||
|
||||
out.writeShort(classType.getIndex());
|
||||
out.writeShort(fieldType.getIndex());
|
||||
out.writeInt(fieldName.getIndex());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_FIELD_ID_ITEM;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String getConciseIdentity() {
|
||||
String parentClass = classType.getTypeDescriptor();
|
||||
//strip off the leading L and trailing ;
|
||||
parentClass = parentClass.substring(1, parentClass.length() - 1);
|
||||
|
||||
return parentClass + "/" + fieldName.getStringValue() +
|
||||
":" + fieldType.getTypeDescriptor();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int compareTo(FieldIdItem o) {
|
||||
int result = classType.compareTo(o.classType);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = fieldName.compareTo(o.fieldName);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return fieldType.compareTo(o.fieldType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the class that this field is a member of
|
||||
*/
|
||||
public TypeIdItem getContainingClass() {
|
||||
return classType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the type of this field
|
||||
*/
|
||||
public TypeIdItem getFieldType() {
|
||||
return fieldType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the field name
|
||||
*/
|
||||
public StringIdItem getFieldName() {
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate and cache the hashcode
|
||||
*/
|
||||
private void calcHashCode() {
|
||||
hashCode = classType.hashCode();
|
||||
hashCode = 31 * hashCode + fieldType.hashCode();
|
||||
hashCode = 31 * hashCode + fieldName.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
//there's a small possibility that the actual hash code will be 0. If so, we'll
|
||||
//just end up recalculating it each time
|
||||
if (hashCode == 0)
|
||||
calcHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this==o) {
|
||||
return true;
|
||||
}
|
||||
if (o==null || !this.getClass().equals(o.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//This assumes that the referenced items have been interned in both objects.
|
||||
//This is a valid assumption because all outside code must use the static
|
||||
//"getInterned..." style methods to make new items, and any item created
|
||||
//internally is guaranteed to be interned
|
||||
FieldIdItem other = (FieldIdItem)o;
|
||||
return (classType == other.classType &&
|
||||
fieldType == other.fieldType &&
|
||||
fieldName == other.fieldName);
|
||||
}
|
||||
}
|
208
dexlib/src/main/java/org/jf/dexlib/HeaderItem.java
Normal file
208
dexlib/src/main/java/org/jf/dexlib/HeaderItem.java
Normal file
@ -0,0 +1,208 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
import org.jf.dexlib.Util.Input;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
public class HeaderItem extends Item<HeaderItem> {
|
||||
/**
|
||||
* non-null; the file format magic number, represented as the
|
||||
* low-order bytes of a string
|
||||
*/
|
||||
private static final String MAGIC = "dex\n035" + '\0';
|
||||
|
||||
/** size of this section, in bytes */
|
||||
private static final int HEADER_SIZE = 0x70;
|
||||
|
||||
/** the endianness constants */
|
||||
private static final int LITTLE_ENDIAN = 0x12345678;
|
||||
private static final int BIG_ENDIAN = 0x78562312;
|
||||
|
||||
/**
|
||||
* Create a new uninitialized <code>HeaderItem</code>
|
||||
* @param dexFile The <code>DexFile</code> containing this <code>HeaderItem</code>
|
||||
*/
|
||||
protected HeaderItem(final DexFile dexFile) {
|
||||
super(dexFile);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void readItem(Input in, ReadContext readContext) {
|
||||
byte[] expectedMagic = MAGIC.getBytes(Charset.forName("US-ASCII"));
|
||||
byte[] readMagic = in.readBytes(8);
|
||||
|
||||
for (int i=0; i<8; i++) {
|
||||
if (expectedMagic[i] != readMagic[i]) {
|
||||
throw new RuntimeException("The magic value is not the expected value");
|
||||
}
|
||||
}
|
||||
|
||||
in.readBytes(20); //checksum
|
||||
in.readInt(); //signature
|
||||
in.readInt(); //filesize
|
||||
if (in.readInt() != HEADER_SIZE) {
|
||||
throw new RuntimeException("The header size is not the expected value (0x70)");
|
||||
}
|
||||
|
||||
int endianTag = in.readInt();
|
||||
if (endianTag == BIG_ENDIAN) {
|
||||
throw new RuntimeException("This dex file is big endian. Only little endian is currently supported.");
|
||||
} else if (endianTag != LITTLE_ENDIAN) {
|
||||
throw new RuntimeException("The endian tag is not 0x12345678 or 0x78563412");
|
||||
}
|
||||
|
||||
//link_size
|
||||
if (in.readInt() != 0) {
|
||||
throw new RuntimeException("This dex file has a link section, which is not supported");
|
||||
}
|
||||
|
||||
//link_off
|
||||
if (in.readInt() != 0) {
|
||||
throw new RuntimeException("This dex file has a link section, which is not supported");
|
||||
}
|
||||
|
||||
int sectionSize;
|
||||
int sectionOffset;
|
||||
|
||||
//map_offset
|
||||
sectionOffset = in.readInt();
|
||||
readContext.addSection(ItemType.TYPE_MAP_LIST, 1, sectionOffset);
|
||||
|
||||
//string_id_item
|
||||
sectionSize = in.readInt();
|
||||
sectionOffset = in.readInt();
|
||||
readContext.addSection(ItemType.TYPE_STRING_ID_ITEM, sectionSize, sectionOffset);
|
||||
|
||||
//type_id_item
|
||||
sectionSize = in.readInt();
|
||||
sectionOffset = in.readInt();
|
||||
readContext.addSection(ItemType.TYPE_TYPE_ID_ITEM, sectionSize, sectionOffset);
|
||||
|
||||
//proto_id_item
|
||||
sectionSize = in.readInt();
|
||||
sectionOffset = in.readInt();
|
||||
readContext.addSection(ItemType.TYPE_PROTO_ID_ITEM, sectionSize, sectionOffset);
|
||||
|
||||
//field_id_item
|
||||
sectionSize = in.readInt();
|
||||
sectionOffset = in.readInt();
|
||||
readContext.addSection(ItemType.TYPE_FIELD_ID_ITEM, sectionSize, sectionOffset);
|
||||
|
||||
//method_id_item
|
||||
sectionSize = in.readInt();
|
||||
sectionOffset = in.readInt();
|
||||
readContext.addSection(ItemType.TYPE_METHOD_ID_ITEM, sectionSize, sectionOffset);
|
||||
|
||||
//class_data_item
|
||||
sectionSize = in.readInt();
|
||||
sectionOffset = in.readInt();
|
||||
readContext.addSection(ItemType.TYPE_CLASS_DEF_ITEM, sectionSize, sectionOffset);
|
||||
|
||||
in.readInt(); //data_size
|
||||
in.readInt(); //data_off
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int placeItem(int offset) {
|
||||
return HEADER_SIZE;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void writeItem(AnnotatedOutput out) {
|
||||
if (out.annotates()) {
|
||||
//TODO: add human readable representations of the underlying data where appropriate
|
||||
out.annotate(8, "magic");
|
||||
out.annotate(4, "checksum");
|
||||
out.annotate(20, "signature");
|
||||
out.annotate(4, "file_size");
|
||||
out.annotate(4, "header_size");
|
||||
out.annotate(4, "endian_tag");
|
||||
out.annotate(4, "link_size");
|
||||
out.annotate(4, "link_off");
|
||||
out.annotate(4, "map_off");
|
||||
out.annotate(4, "string_ids_size");
|
||||
out.annotate(4, "string_ids_off");
|
||||
out.annotate(4, "type_ids_size");
|
||||
out.annotate(4, "type_ids_off");
|
||||
out.annotate(4, "proto_ids_size");
|
||||
out.annotate(4, "proto_ids_off");
|
||||
out.annotate(4, "field_ids_size");
|
||||
out.annotate(4, "field_ids_off");
|
||||
out.annotate(4, "method_ids_size");
|
||||
out.annotate(4, "method_ids_off");
|
||||
out.annotate(4, "class_defs_size");
|
||||
out.annotate(4, "class_defs_off");
|
||||
out.annotate(4, "data_size");
|
||||
out.annotate(4, "data_off");
|
||||
}
|
||||
|
||||
out.write(MAGIC.getBytes(Charset.forName("US-ASCII")));
|
||||
out.writeInt(0); //checksum
|
||||
out.write(new byte[20]); //signature
|
||||
out.writeInt(dexFile.getFileSize());
|
||||
out.writeInt(HEADER_SIZE);
|
||||
out.writeInt(LITTLE_ENDIAN);
|
||||
out.writeInt(0); //link_size
|
||||
out.writeInt(0); //link_off
|
||||
out.writeInt(dexFile.MapItem.getOffset());
|
||||
out.writeInt(dexFile.StringIdsSection.getItems().size());
|
||||
out.writeInt(dexFile.StringIdsSection.getOffset());
|
||||
out.writeInt(dexFile.TypeIdsSection.getItems().size());
|
||||
out.writeInt(dexFile.TypeIdsSection.getOffset());
|
||||
out.writeInt(dexFile.ProtoIdsSection.getItems().size());
|
||||
out.writeInt(dexFile.ProtoIdsSection.getOffset());
|
||||
out.writeInt(dexFile.FieldIdsSection.getItems().size());
|
||||
out.writeInt(dexFile.FieldIdsSection.getOffset());
|
||||
out.writeInt(dexFile.MethodIdsSection.getItems().size());
|
||||
out.writeInt(dexFile.MethodIdsSection.getOffset());
|
||||
out.writeInt(dexFile.ClassDefsSection.getItems().size());
|
||||
out.writeInt(dexFile.ClassDefsSection.getOffset());
|
||||
out.writeInt(dexFile.getDataSize());
|
||||
out.writeInt(dexFile.getDataOffset());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_HEADER_ITEM;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String getConciseIdentity() {
|
||||
return "header_item";
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int compareTo(HeaderItem o) {
|
||||
//there is only 1 header item
|
||||
return 0;
|
||||
}
|
||||
}
|
67
dexlib/src/main/java/org/jf/dexlib/IndexedSection.java
Normal file
67
dexlib/src/main/java/org/jf/dexlib/IndexedSection.java
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.Util.Input;
|
||||
|
||||
public class IndexedSection<T extends Item> extends Section<T> {
|
||||
|
||||
/**
|
||||
* Create a new indexed section
|
||||
* @param dexFile The <code>DexFile</code> that this section belongs to
|
||||
* @param itemType The itemType that this section will hold
|
||||
*/
|
||||
public IndexedSection(DexFile dexFile, ItemType itemType) {
|
||||
super(dexFile, itemType);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void readItems(Input in, ReadContext readContext) {
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
T item = (T)ItemFactory.makeItem(ItemType, DexFile);
|
||||
items.set(i, item);
|
||||
item.readFrom(in, i, readContext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the item at the specified index in this section
|
||||
* @param index the index of the item to get
|
||||
* @return the item at the specified index in this section
|
||||
* @throws IndexOutOfBoundsException if index is outside the bounds of this section
|
||||
*/
|
||||
public T getItemByIndex(int index) {
|
||||
if (index == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//if index is out of bounds, just let it throw an exception
|
||||
return items.get(index);
|
||||
}
|
||||
}
|
185
dexlib/src/main/java/org/jf/dexlib/Item.java
Normal file
185
dexlib/src/main/java/org/jf/dexlib/Item.java
Normal file
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.AlignmentUtils;
|
||||
|
||||
public abstract class Item<T extends Item> implements Comparable<T> {
|
||||
/**
|
||||
* The offset of this item in the dex file, or -1 if not known
|
||||
*/
|
||||
private int offset = -1;
|
||||
|
||||
/**
|
||||
* The index of this item in the containing section, or -1 if not known
|
||||
*/
|
||||
private int index = -1;
|
||||
|
||||
/**
|
||||
* The DexFile that this item is associatedr with
|
||||
*/
|
||||
protected final DexFile dexFile;
|
||||
|
||||
/**
|
||||
* The constructor that is used when reading in a <code>DexFile</code>
|
||||
* @param dexFile the <code>DexFile</code> that this item is associated with
|
||||
*/
|
||||
protected Item(DexFile dexFile) {
|
||||
this.dexFile = dexFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read in the item from the given input stream, and initialize the index
|
||||
* @param in the <code>Input</code> object to read from
|
||||
* @param index the index within the containing section of the item being read in
|
||||
* @param readContext a <code>ReadContext</code> object to hold information that is
|
||||
* only needed while reading in a file
|
||||
*/
|
||||
protected void readFrom(Input in, int index, ReadContext readContext) {
|
||||
assert in.getCursor() % getItemType().ItemAlignment == 0:"The Input cursor is not aligned";
|
||||
|
||||
this.offset = in.getCursor();
|
||||
this.index = index;
|
||||
this.readItem(in, readContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Place the item at the given offset and index, and return the offset of the byte following this item
|
||||
* @param offset The offset to place the item at
|
||||
* @param index The index of the item within the containing section
|
||||
* @return The offset of the byte following this item
|
||||
*/
|
||||
protected int placeAt(int offset, int index) {
|
||||
assert offset % getItemType().ItemAlignment == 0:"The offset is not aligned";
|
||||
|
||||
this.offset = offset;
|
||||
this.index = index;
|
||||
return this.placeItem(offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write and annotate this item to the output stream
|
||||
* @param out The output stream to write and annotate to
|
||||
*/
|
||||
protected void writeTo(AnnotatedOutput out) {
|
||||
assert out.getCursor() % getItemType().ItemAlignment == 0:"The Output cursor is not aligned";
|
||||
|
||||
if (out.getCursor() != offset) {
|
||||
throw new RuntimeException("Item was placed at offset 0x" + Integer.toHexString(offset) +
|
||||
"but is being written to offset 0x" + Integer.toHexString(out.getCursor()));
|
||||
}
|
||||
|
||||
if (out.annotates()) {
|
||||
out.annotate(0, "[0x" + Integer.toHexString(index) + "] " + this.getItemType().TypeName);
|
||||
}
|
||||
|
||||
out.indent();
|
||||
writeItem(out);
|
||||
out.deindent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a human readable form of this item
|
||||
* @return a human readable form of this item
|
||||
*/
|
||||
public String toString() {
|
||||
return getConciseIdentity();
|
||||
}
|
||||
|
||||
/**
|
||||
* The method in the concrete item subclass that actually reads in the data for the item
|
||||
*
|
||||
* The logic in this method can assume that the given Input object is valid and is
|
||||
* aligned as neccessary.
|
||||
*
|
||||
* This method is for internal use only
|
||||
* @param in the <code>Input</code> object to read from
|
||||
* @param readContext a <code>ReadContext</code> object to hold information that is
|
||||
* only needed while reading in a file
|
||||
*/
|
||||
protected abstract void readItem(Input in, ReadContext readContext);
|
||||
|
||||
/**
|
||||
* The method should finalize the layout of the item and return the offset of the byte
|
||||
* immediately following the item.
|
||||
*
|
||||
* The implementation of this method can assume that the offset argument has already been
|
||||
* aligned based on the item's alignment requirements
|
||||
*
|
||||
* This method is for internal use only
|
||||
* @param offset the (pre-aligned) offset to place the item at
|
||||
* @return the size of the item, in bytes
|
||||
*/
|
||||
protected abstract int placeItem(int offset);
|
||||
|
||||
/**
|
||||
* The method in the concrete item subclass that actually writes and annotates the data
|
||||
* for the item.
|
||||
*
|
||||
* The logic in this method can assume that the given Output object is valid and is
|
||||
* aligned as neccessary
|
||||
*
|
||||
* @param out The <code>AnnotatedOutput</code> object to write/annotate to
|
||||
*/
|
||||
protected abstract void writeItem(AnnotatedOutput out);
|
||||
|
||||
/**
|
||||
* @return An ItemType enum that represents the item type of this item
|
||||
*/
|
||||
public abstract ItemType getItemType();
|
||||
|
||||
/**
|
||||
* @return A concise (human-readable) string value that conveys the identity of this item
|
||||
*/
|
||||
public abstract String getConciseIdentity();
|
||||
|
||||
|
||||
/**
|
||||
* @return the offset in the dex file where this item is located
|
||||
*/
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the index of this item within the item's containing section
|
||||
*/
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the <code>DexFile</code> that contains this item
|
||||
*/
|
||||
public DexFile getDexFile() {
|
||||
return dexFile;
|
||||
}
|
||||
}
|
71
dexlib/src/main/java/org/jf/dexlib/ItemFactory.java
Normal file
71
dexlib/src/main/java/org/jf/dexlib/ItemFactory.java
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
class ItemFactory {
|
||||
protected static Item makeItem(ItemType itemType, DexFile dexFile) {
|
||||
switch (itemType) {
|
||||
case TYPE_STRING_ID_ITEM:
|
||||
return new StringIdItem(dexFile);
|
||||
case TYPE_TYPE_ID_ITEM:
|
||||
return new TypeIdItem(dexFile);
|
||||
case TYPE_PROTO_ID_ITEM:
|
||||
return new ProtoIdItem(dexFile);
|
||||
case TYPE_FIELD_ID_ITEM:
|
||||
return new FieldIdItem(dexFile);
|
||||
case TYPE_METHOD_ID_ITEM:
|
||||
return new MethodIdItem(dexFile);
|
||||
case TYPE_CLASS_DEF_ITEM:
|
||||
return new ClassDefItem(dexFile);
|
||||
case TYPE_TYPE_LIST:
|
||||
return new TypeListItem(dexFile);
|
||||
case TYPE_ANNOTATION_SET_REF_LIST:
|
||||
return new AnnotationSetRefList(dexFile);
|
||||
case TYPE_ANNOTATION_SET_ITEM:
|
||||
return new AnnotationSetItem(dexFile);
|
||||
case TYPE_CLASS_DATA_ITEM:
|
||||
return new ClassDataItem(dexFile);
|
||||
case TYPE_CODE_ITEM:
|
||||
return new CodeItem(dexFile);
|
||||
case TYPE_STRING_DATA_ITEM:
|
||||
return new StringDataItem(dexFile);
|
||||
case TYPE_DEBUG_INFO_ITEM:
|
||||
return new DebugInfoItem(dexFile);
|
||||
case TYPE_ANNOTATION_ITEM:
|
||||
return new AnnotationItem(dexFile);
|
||||
case TYPE_ENCODED_ARRAY_ITEM:
|
||||
return new EncodedArrayItem(dexFile);
|
||||
case TYPE_ANNOTATIONS_DIRECTORY_ITEM:
|
||||
return new AnnotationDirectoryItem(dexFile);
|
||||
default:
|
||||
assert false;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
123
dexlib/src/main/java/org/jf/dexlib/ItemType.java
Normal file
123
dexlib/src/main/java/org/jf/dexlib/ItemType.java
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* Enumeration of all the top-level item types.
|
||||
*/
|
||||
public enum ItemType {
|
||||
TYPE_HEADER_ITEM( 0x0000, 17, 4, "header_item"),
|
||||
TYPE_STRING_ID_ITEM( 0x0001, 0, 4, "string_id_item"),
|
||||
TYPE_TYPE_ID_ITEM( 0x0002, 1, 4, "type_id_item"),
|
||||
TYPE_PROTO_ID_ITEM( 0x0003, 2, 4, "proto_id_item"),
|
||||
TYPE_FIELD_ID_ITEM( 0x0004, 3, 4, "field_id_item"),
|
||||
TYPE_METHOD_ID_ITEM( 0x0005, 4, 4, "method_id_item"),
|
||||
TYPE_CLASS_DEF_ITEM( 0x0006, 5, 4, "class_def_item"),
|
||||
TYPE_MAP_LIST( 0x1000, 16, 4, "map_list"),
|
||||
TYPE_TYPE_LIST( 0x1001, 6, 4, "type_list"),
|
||||
TYPE_ANNOTATION_SET_REF_LIST( 0x1002, 7, 4, "annotation_set_ref_list"),
|
||||
TYPE_ANNOTATION_SET_ITEM( 0x1003, 8, 4, "annotation_set_item"),
|
||||
TYPE_CLASS_DATA_ITEM( 0x2000, 9, 1, "class_data_item"),
|
||||
TYPE_CODE_ITEM( 0x2001, 10, 4, "code_item"),
|
||||
TYPE_STRING_DATA_ITEM( 0x2002, 11, 1, "string_data_item"),
|
||||
TYPE_DEBUG_INFO_ITEM( 0x2003, 12, 1, "debug_info_item"),
|
||||
TYPE_ANNOTATION_ITEM( 0x2004, 13, 1, "annotation_item"),
|
||||
TYPE_ENCODED_ARRAY_ITEM( 0x2005, 14, 1, "encoded_array_item"),
|
||||
TYPE_ANNOTATIONS_DIRECTORY_ITEM(0x2006, 15, 4, "annotations_directory_item");
|
||||
|
||||
/** A map to facilitate looking up an <code>ItemType</code> by ordinal */
|
||||
private final static TreeMap<Integer, ItemType> itemTypeIntegerMap;
|
||||
|
||||
/** builds the <code>itemTypeIntegerMap</code> object */
|
||||
static {
|
||||
itemTypeIntegerMap = new TreeMap<Integer, ItemType>();
|
||||
|
||||
for (ItemType itemType: ItemType.values()) {
|
||||
itemTypeIntegerMap.put(itemType.MapValue, itemType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* value when represented in a MapItem
|
||||
*/
|
||||
public final int MapValue;
|
||||
|
||||
/**
|
||||
* name of the type
|
||||
*/
|
||||
public final String TypeName;
|
||||
|
||||
/**
|
||||
* index for this item's section
|
||||
*/
|
||||
public final int SectionIndex;
|
||||
|
||||
/**
|
||||
* the alignment for this item type
|
||||
*/
|
||||
public final int ItemAlignment;
|
||||
/**
|
||||
* Constructs an instance.
|
||||
*
|
||||
* @param mapValue value when represented in a MapItem
|
||||
* @param sectionIndex index for this item's section
|
||||
* @param itemAlignment the byte alignment required by this item
|
||||
* @param typeName non-null; name of the type
|
||||
*/
|
||||
private ItemType(int mapValue, int sectionIndex, int itemAlignment, String typeName) {
|
||||
this.MapValue = mapValue;
|
||||
this.SectionIndex = sectionIndex;
|
||||
this.ItemAlignment = itemAlignment;
|
||||
this.TypeName = typeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an int value to the corresponding ItemType enum value,
|
||||
* or null if the value isn't a valid ItemType value
|
||||
*
|
||||
* @param itemType the int value to convert to an ItemType
|
||||
* @return the ItemType enum value corresponding to itemType, or null
|
||||
* if not a valid ItemType value
|
||||
*/
|
||||
public static ItemType fromInt(int itemType) {
|
||||
return itemTypeIntegerMap.get(itemType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is an indexed item, or false if its an offsetted item
|
||||
* @return true if this is an indexed item, or false if its an offsetted item
|
||||
*/
|
||||
public boolean isIndexedItem() {
|
||||
return MapValue <= 0x1000;
|
||||
}
|
||||
}
|
126
dexlib/src/main/java/org/jf/dexlib/MapItem.java
Normal file
126
dexlib/src/main/java/org/jf/dexlib/MapItem.java
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
import org.jf.dexlib.Util.Hex;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
/**
|
||||
* This item represents a map_list item from the dex specification. It contains a
|
||||
* SectionInfo instance for every section in the DexFile, with the number of items
|
||||
* in and offset of that section.
|
||||
*/
|
||||
public class MapItem extends Item<MapItem> {
|
||||
/**
|
||||
* This item is read in immediately after the HeaderItem, and the section info contained
|
||||
* by this item is added to the ReadContext object, which is used when reading in the other
|
||||
* sections in the dex file.
|
||||
*
|
||||
* This item should be placed last. It depends on the fact that the other sections
|
||||
* in the file have been placed.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a new uninitialized <code>MapItem</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
*/
|
||||
protected MapItem(final DexFile dexFile) {
|
||||
super(dexFile);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int placeItem(int offset) {
|
||||
Section[] sections = dexFile.getOrderedSections();
|
||||
//the list returned by getOrderedSections doesn't contain the header
|
||||
//or map section, so add 2 to the length
|
||||
return offset + (sections.length + 2) * 12;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void readItem(Input in, ReadContext readContext) {
|
||||
int size = in.readInt();
|
||||
|
||||
for (int i=0; i<size; i++) {
|
||||
ItemType itemType = ItemType.fromInt(in.readShort());
|
||||
|
||||
//unused
|
||||
in.readShort();
|
||||
|
||||
int sectionSize = in.readInt();
|
||||
int sectionOffset = in.readInt();
|
||||
|
||||
readContext.addSection(itemType, sectionSize, sectionOffset);
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void writeItem(AnnotatedOutput out) {
|
||||
Assert.assertTrue(getOffset() > 0);
|
||||
|
||||
writeSectionInfo(out, ItemType.TYPE_HEADER_ITEM, 1, 0);
|
||||
|
||||
for (Section section: dexFile.getOrderedSections()) {
|
||||
writeSectionInfo(out, section.ItemType, section.getItems().size(), section.getOffset());
|
||||
}
|
||||
|
||||
writeSectionInfo(out, ItemType.TYPE_MAP_LIST, 1, dexFile.MapItem.getOffset());
|
||||
}
|
||||
|
||||
private void writeSectionInfo(AnnotatedOutput out, ItemType itemType, int sectionSize, int sectionOffset) {
|
||||
if (out.annotates()) {
|
||||
out.annotate(2, "ItemType: " + itemType);
|
||||
out.annotate(2, "unused");
|
||||
out.annotate(4, "Section Size: " + sectionSize);
|
||||
out.annotate(4, "Section Offset: " + Hex.u4(sectionOffset));
|
||||
}
|
||||
|
||||
out.writeShort(itemType.MapValue);
|
||||
out.writeShort(0);
|
||||
out.writeInt(sectionSize);
|
||||
out.writeInt(sectionOffset);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_MAP_LIST;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int compareTo(MapItem o) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String getConciseIdentity() {
|
||||
return "map_item";
|
||||
}
|
||||
}
|
198
dexlib/src/main/java/org/jf/dexlib/MethodIdItem.java
Normal file
198
dexlib/src/main/java/org/jf/dexlib/MethodIdItem.java
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
public class MethodIdItem extends Item<MethodIdItem> {
|
||||
private int hashCode = 0;
|
||||
|
||||
private TypeIdItem classType;
|
||||
private ProtoIdItem methodPrototype;
|
||||
private StringIdItem methodName;
|
||||
|
||||
/**
|
||||
* Creates a new uninitialized <code>MethodIdItem</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
*/
|
||||
protected MethodIdItem(DexFile dexFile) {
|
||||
super(dexFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>MethodIdItem</code> for the given class, type and name
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param classType the class that the method is a member of
|
||||
* @param methodPrototype the type of the method
|
||||
* @param methodName the name of the method
|
||||
*/
|
||||
private MethodIdItem(DexFile dexFile, TypeIdItem classType, ProtoIdItem methodPrototype, StringIdItem methodName) {
|
||||
this(dexFile);
|
||||
this.classType = classType;
|
||||
this.methodPrototype = methodPrototype;
|
||||
this.methodName = methodName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <code>MethodIdItem</code> for the given values, and that has been interned into
|
||||
* the given <code>DexFile</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param classType the class that the method is a member of
|
||||
* @param methodPrototype the type of the method
|
||||
* @param methodName the name of the method
|
||||
* @return a <code>MethodIdItem</code> for the given values, and that has been interned into
|
||||
* the given <code>DexFile</code>
|
||||
*/
|
||||
public static MethodIdItem getInternedMethodIdItem(DexFile dexFile, TypeIdItem classType,
|
||||
ProtoIdItem methodPrototype, StringIdItem methodName) {
|
||||
MethodIdItem methodIdItem = new MethodIdItem(dexFile, classType, methodPrototype, methodName);
|
||||
return dexFile.MethodIdsSection.intern(methodIdItem);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void readItem(Input in, ReadContext readContext) {
|
||||
classType = dexFile.TypeIdsSection.getItemByIndex(in.readShort());
|
||||
methodPrototype = dexFile.ProtoIdsSection.getItemByIndex(in.readShort());
|
||||
methodName = dexFile.StringIdsSection.getItemByIndex(in.readInt());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int placeItem(int offset) {
|
||||
return offset + 8;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void writeItem(AnnotatedOutput out) {
|
||||
if (out.annotates()) {
|
||||
out.annotate(2, classType.getConciseIdentity());
|
||||
out.annotate(2, methodPrototype.getConciseIdentity());
|
||||
out.annotate(4, methodName.getConciseIdentity());
|
||||
}
|
||||
|
||||
out.writeShort(classType.getIndex());
|
||||
out.writeShort(methodPrototype.getIndex());
|
||||
out.writeInt(methodName.getIndex());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_METHOD_ID_ITEM;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String getConciseIdentity() {
|
||||
return "method_id_item: " + getMethodString();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int compareTo(MethodIdItem o) {
|
||||
int result = classType.compareTo(o.classType);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = methodName.compareTo(o.methodName);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return methodPrototype.compareTo(o.methodPrototype);
|
||||
}
|
||||
|
||||
private String cachedMethodString = null;
|
||||
/**
|
||||
* @return a string formatted like LclassName;->methodName(TTTT..)R
|
||||
*/
|
||||
public String getMethodString() {
|
||||
if (cachedMethodString == null) {
|
||||
cachedMethodString = classType.getTypeDescriptor() + "->" + methodName.getStringValue() +
|
||||
methodPrototype.getPrototypeString();
|
||||
}
|
||||
return cachedMethodString;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the method prototype
|
||||
*/
|
||||
public ProtoIdItem getPrototype() {
|
||||
return methodPrototype;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name of the method
|
||||
*/
|
||||
public StringIdItem getMethodName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the class this method is a member of
|
||||
*/
|
||||
public TypeIdItem getContainingClass() {
|
||||
return classType;
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate and cache the hashcode
|
||||
*/
|
||||
private void calcHashCode() {
|
||||
hashCode = classType.hashCode();
|
||||
hashCode = 31 * hashCode + methodPrototype.hashCode();
|
||||
hashCode = 31 * hashCode + methodName.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
//there's a small possibility that the actual hash code will be 0. If so, we'll
|
||||
//just end up recalculating it each time
|
||||
if (hashCode == 0)
|
||||
calcHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this==o) {
|
||||
return true;
|
||||
}
|
||||
if (o==null || !this.getClass().equals(o.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//This assumes that the referenced items have been interned in both objects.
|
||||
//This is a valid assumption because all outside code must use the static
|
||||
//"getInterned..." style methods to make new items, and any item created
|
||||
//internally is guaranteed to be interned
|
||||
MethodIdItem other = (MethodIdItem)o;
|
||||
return (classType == other.classType &&
|
||||
methodPrototype == other.methodPrototype &&
|
||||
methodName == other.methodName);
|
||||
}
|
||||
}
|
83
dexlib/src/main/java/org/jf/dexlib/OffsettedSection.java
Normal file
83
dexlib/src/main/java/org/jf/dexlib/OffsettedSection.java
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.SparseArray;
|
||||
import org.jf.dexlib.Util.Hex;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
public class OffsettedSection<T extends Item> extends Section<T> {
|
||||
public OffsettedSection(DexFile dexFile, ItemType itemType) {
|
||||
super(dexFile, itemType);
|
||||
}
|
||||
|
||||
public void readItems(Input in, ReadContext readContext) {
|
||||
SparseArray<T> precreatedItems = (SparseArray<T>)readContext.getItemsByType(ItemType);
|
||||
|
||||
assert precreatedItems.size() <= items.size(): "Trying to read " + items.size() + " items, but this section " +
|
||||
"already contains " + precreatedItems.size() + " items.";
|
||||
|
||||
int precreatedIndex = 0;
|
||||
int nextPrecreatedOffset = Integer.MAX_VALUE;
|
||||
|
||||
if (precreatedItems.size() > 0) {
|
||||
nextPrecreatedOffset = precreatedItems.keyAt(0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
assert items.get(i) == null;
|
||||
|
||||
T item = null;
|
||||
in.alignTo(ItemType.ItemAlignment);
|
||||
int currentOffset = in.getCursor();
|
||||
|
||||
if (currentOffset == nextPrecreatedOffset) {
|
||||
item = precreatedItems.valueAt(precreatedIndex++);
|
||||
if (precreatedIndex < precreatedItems.size()) {
|
||||
nextPrecreatedOffset = precreatedItems.keyAt(precreatedIndex);
|
||||
} else {
|
||||
nextPrecreatedOffset = Integer.MAX_VALUE;
|
||||
}
|
||||
} else if (currentOffset > nextPrecreatedOffset) {
|
||||
//we passed by the next precreated item, something is wrong
|
||||
throw new RuntimeException("The pre-created item at offset 0x" + Hex.u4(nextPrecreatedOffset)
|
||||
+ " was not read");
|
||||
} else {
|
||||
item = (T)ItemFactory.makeItem(ItemType, DexFile);
|
||||
}
|
||||
|
||||
items.set(i, item);
|
||||
item.readFrom(in, i, readContext);
|
||||
}
|
||||
|
||||
readContext.setItemsForSection(ItemType, items);
|
||||
}
|
||||
}
|
203
dexlib/src/main/java/org/jf/dexlib/ProtoIdItem.java
Normal file
203
dexlib/src/main/java/org/jf/dexlib/ProtoIdItem.java
Normal file
@ -0,0 +1,203 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
public class ProtoIdItem extends Item<ProtoIdItem> {
|
||||
private int hashCode = 0;
|
||||
|
||||
private StringIdItem shortyDescriptor;
|
||||
private TypeIdItem returnType;
|
||||
private TypeListItem parameters;
|
||||
|
||||
/**
|
||||
* Creates a new uninitialized <code>ProtoIdItem</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
*/
|
||||
protected ProtoIdItem(DexFile dexFile) {
|
||||
super(dexFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>ProtoIdItem</code> with the given values
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param returnType the return type
|
||||
* @param parameters a <code>TypeListItem</code> containing a list of the parameter types
|
||||
*/
|
||||
private ProtoIdItem(DexFile dexFile, TypeIdItem returnType, TypeListItem parameters) {
|
||||
this(dexFile);
|
||||
|
||||
String shortyString = returnType.toShorty();
|
||||
if (parameters != null) {
|
||||
shortyString += parameters.getShortyString();
|
||||
}
|
||||
this.shortyDescriptor = StringIdItem.getInternedStringIdItem(dexFile, shortyString);
|
||||
this.returnType = returnType;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <code>ProtoIdItem</code> for the given values, and that has been interned into
|
||||
* the given <code>DexFile</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param returnType the return type
|
||||
* @param parameters a <code>TypeListItem</code> containing a list of the parameter types
|
||||
* @return a <code>ProtoIdItem</code> for the given values, and that has been interned into
|
||||
* the given <code>DexFile</code>
|
||||
*/
|
||||
public static ProtoIdItem getInternedProtoIdItem(DexFile dexFile, TypeIdItem returnType, TypeListItem parameters) {
|
||||
ProtoIdItem protoIdItem = new ProtoIdItem(dexFile, returnType, parameters);
|
||||
return dexFile.ProtoIdsSection.intern(protoIdItem);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void readItem(Input in, ReadContext readContext) {
|
||||
shortyDescriptor = dexFile.StringIdsSection.getItemByIndex(in.readInt());
|
||||
returnType = dexFile.TypeIdsSection.getItemByIndex(in.readInt());
|
||||
parameters = (TypeListItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_TYPE_LIST, in.readInt());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int placeItem(int offset) {
|
||||
return offset + 12;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void writeItem(AnnotatedOutput out) {
|
||||
if (out.annotates()) {
|
||||
out.annotate(4, "shorty_descriptor: " + shortyDescriptor.getStringValue());
|
||||
out.annotate(4, "return_type: " + returnType.getTypeDescriptor());
|
||||
|
||||
if (parameters == null) {
|
||||
out.annotate(4, "parameters:");
|
||||
} else {
|
||||
out.annotate(4, "parameters: " + parameters.getTypeListString());
|
||||
}
|
||||
}
|
||||
|
||||
out.writeInt(shortyDescriptor.getIndex());
|
||||
out.writeInt(returnType.getIndex());
|
||||
out.writeInt(parameters == null?0:parameters.getOffset());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_PROTO_ID_ITEM;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int compareTo(ProtoIdItem o) {
|
||||
int result = returnType.compareTo(o.returnType);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (parameters == null) {
|
||||
if (o.parameters == null) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
} else if (o.parameters == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return parameters.compareTo(o.parameters);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String getConciseIdentity() {
|
||||
return "proto_id_item: " + getPrototypeString();
|
||||
}
|
||||
|
||||
private String cachedPrototypeString = null;
|
||||
/**
|
||||
* @return a string in the format (TTTT..)R where TTTT.. are the parameter types and R is the return type
|
||||
*/
|
||||
public String getPrototypeString() {
|
||||
if (cachedPrototypeString == null) {
|
||||
StringBuilder sb = new StringBuilder("(");
|
||||
if (parameters != null) {
|
||||
sb.append(parameters.getTypeListString());
|
||||
}
|
||||
sb.append(")");
|
||||
sb.append(returnType.getTypeDescriptor());
|
||||
|
||||
cachedPrototypeString = sb.toString();
|
||||
}
|
||||
return cachedPrototypeString;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of registers required for the parameters of this <code>ProtoIdItem</code>
|
||||
*/
|
||||
public int getParameterRegisterCount() {
|
||||
if (parameters == null) {
|
||||
return 0;
|
||||
} else {
|
||||
return parameters.getRegisterCount();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate and cache the hashcode
|
||||
*/
|
||||
private void calcHashCode() {
|
||||
hashCode = returnType.hashCode();
|
||||
hashCode = 31 * hashCode + parameters.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
//there's a small possibility that the actual hash code will be 0. If so, we'll
|
||||
//just end up recalculating it each time
|
||||
if (hashCode == 0)
|
||||
calcHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this==o) {
|
||||
return true;
|
||||
}
|
||||
if (o==null || !this.getClass().equals(o.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//This assumes that the referenced items have been interned in both objects.
|
||||
//This is a valid assumption because all outside code must use the static
|
||||
//"getInterned..." style methods to make new items, and any item created
|
||||
//internally is guaranteed to be interned
|
||||
ProtoIdItem other = (ProtoIdItem)o;
|
||||
return (returnType == other.returnType &&
|
||||
parameters == other.parameters);
|
||||
}
|
||||
}
|
219
dexlib/src/main/java/org/jf/dexlib/ReadContext.java
Normal file
219
dexlib/src/main/java/org/jf/dexlib/ReadContext.java
Normal file
@ -0,0 +1,219 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.Util.SparseArray;
|
||||
import junit.framework.Assert;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* This class stores context information that is only needed when reading in a dex file
|
||||
* Namely, it handles "pre-creating" items when an item needs to resolve some other item
|
||||
* that it references, and keeps track of those pre-created items, so the corresponding section
|
||||
* for the pre-created items uses them, instead of creating new items
|
||||
*/
|
||||
class ReadContext {
|
||||
private final DexFile dexFile;
|
||||
|
||||
private SparseArray<TypeListItem> typeListItems = new SparseArray<TypeListItem>(0);
|
||||
private SparseArray<AnnotationSetRefList> annotationSetRefLists = new SparseArray<AnnotationSetRefList>(0);
|
||||
private SparseArray<AnnotationSetItem> annotationSetItems = new SparseArray<AnnotationSetItem>(0);
|
||||
private SparseArray<ClassDataItem> classDataItems = new SparseArray<ClassDataItem>(0);
|
||||
private SparseArray<CodeItem> codeItems = new SparseArray<CodeItem>(0);
|
||||
private SparseArray<StringDataItem> stringDataItems = new SparseArray<StringDataItem>(0);
|
||||
private SparseArray<DebugInfoItem> debugInfoItems = new SparseArray<DebugInfoItem>(0);
|
||||
private SparseArray<AnnotationItem> annotationItems = new SparseArray<AnnotationItem>(0);
|
||||
private SparseArray<EncodedArrayItem> encodedArrayItems = new SparseArray<EncodedArrayItem>();
|
||||
private SparseArray<AnnotationDirectoryItem> annotationDirectoryItems = new SparseArray<AnnotationDirectoryItem>();
|
||||
|
||||
private SparseArray[] itemsByType = new SparseArray[] {
|
||||
null, //string_id_item
|
||||
null, //type_id_item
|
||||
null, //proto_id_item
|
||||
null, //field_id_item
|
||||
null, //method_id_item
|
||||
null, //class_def_item
|
||||
typeListItems,
|
||||
annotationSetRefLists,
|
||||
annotationSetItems,
|
||||
classDataItems,
|
||||
codeItems,
|
||||
stringDataItems,
|
||||
debugInfoItems,
|
||||
annotationItems,
|
||||
encodedArrayItems,
|
||||
annotationDirectoryItems,
|
||||
null, //map_list
|
||||
null //header_item
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The section sizes that are passed in while reading HeaderItem/MapItem, via the
|
||||
* addSection method.
|
||||
*/
|
||||
private int[] sectionSizes = new int[18];
|
||||
|
||||
/**
|
||||
* The section offsets that are passed in while reading MapItem/HeaderItem, via the
|
||||
* addSection method.
|
||||
*/
|
||||
private int[] sectionOffsets = new int[18];
|
||||
|
||||
/**
|
||||
* Creates a new ReadContext instance.
|
||||
* @param dexFile The dex file that is being read in
|
||||
*/
|
||||
public ReadContext(DexFile dexFile) {
|
||||
this.dexFile = dexFile;
|
||||
|
||||
for (int i=0; i<18; i++) {
|
||||
sectionSizes[i] = -1;
|
||||
sectionOffsets[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a SparseArray containing the items of the given type
|
||||
* that have been pre-created while reading in other sections.
|
||||
*
|
||||
* If the given ItemType isn't an offsetted item, this method will
|
||||
* return null
|
||||
* @param itemType The type of item to get
|
||||
* @return a SparseArray containing the items of the given type
|
||||
* that have been pre-created while reading in other sections, or
|
||||
* null if the ItemType isn't an offsetted item
|
||||
*/
|
||||
public SparseArray getItemsByType(ItemType itemType) {
|
||||
return itemsByType[itemType.SectionIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or creates an offsetted item of the specified type for the
|
||||
* given offset. Multiple calls to this method with the same itemType
|
||||
* and offset will return the same item.
|
||||
*
|
||||
* It should not be assumed that the item that is returned will be
|
||||
* initialized. It is only guaranteed that the item will be read in
|
||||
* and initiliazed after the entire dex file has been read in.
|
||||
*
|
||||
* Note that it *is* guaranteed that this exact item will be added to
|
||||
* its corresponding section and read in. In other words, when the
|
||||
* corresponding section is being read in, it will use any items for
|
||||
* that have been "pre-created" by this method, and only create
|
||||
* new items for offsets that haven't been pre-created yet.
|
||||
*
|
||||
* @param itemType The type of item to get
|
||||
* @param offset The offset of the StringDataItem
|
||||
* @return a StringDataItem for the given offset
|
||||
*/
|
||||
public Item getOffsettedItemByOffset(ItemType itemType, int offset) {
|
||||
assert !itemType.isIndexedItem();
|
||||
|
||||
if (offset == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
SparseArray<Item> sa = itemsByType[itemType.SectionIndex];
|
||||
Item item = sa.get(offset);
|
||||
if (item == null) {
|
||||
item = ItemFactory.makeItem(itemType, dexFile);
|
||||
sa.put(offset, item);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the size and offset information for the given offset
|
||||
* @param itemType the item type of the section
|
||||
* @param sectionSize the size of the section
|
||||
* @param sectionOffset the offset of the section
|
||||
*/
|
||||
public void addSection(final ItemType itemType, int sectionSize, int sectionOffset) {
|
||||
if (!itemType.isIndexedItem()) {
|
||||
itemsByType[itemType.SectionIndex].ensureCapacity(sectionSize);
|
||||
}
|
||||
int storedSectionSize = sectionSizes[itemType.SectionIndex];
|
||||
if (storedSectionSize == -1) {
|
||||
sectionSizes[itemType.SectionIndex] = sectionSize;
|
||||
} else {
|
||||
if (storedSectionSize != sectionSize) {
|
||||
throw new RuntimeException("The section size in the header and map for item type "
|
||||
+ itemType + " do not match");
|
||||
}
|
||||
}
|
||||
|
||||
int storedSectionOffset = sectionOffsets[itemType.SectionIndex];
|
||||
if (storedSectionOffset == -1) {
|
||||
sectionOffsets[itemType.SectionIndex] = sectionOffset;
|
||||
} else {
|
||||
if (storedSectionOffset != sectionOffset) {
|
||||
throw new RuntimeException("The section offset in the header and map for item type "
|
||||
+ itemType + " do not match");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the items for the specified section. This should be called by an offsetted section
|
||||
* after it is finished reading in all its items.
|
||||
* @param itemType the item type of the section. This must be an offsetted item type
|
||||
* @param items the full list of items in the section, ordered by offset
|
||||
*/
|
||||
public void setItemsForSection(ItemType itemType, List<? extends Item> items) {
|
||||
assert !itemType.isIndexedItem();
|
||||
|
||||
SparseArray<Item> sa = itemsByType[itemType.SectionIndex];
|
||||
|
||||
sa.clear();
|
||||
sa.ensureCapacity(items.size());
|
||||
for (Item item: items) {
|
||||
sa.append(item.getOffset(), item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param itemType the item type of the section
|
||||
* @return the size of the given section as it was read in from the map item
|
||||
*/
|
||||
public int getSectionSize(ItemType itemType) {
|
||||
return sectionSizes[itemType.SectionIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param itemType the item type of the section
|
||||
* @return the offset of the given section as it was read in from the map item
|
||||
*/
|
||||
public int getSectionOffset(ItemType itemType) {
|
||||
return sectionOffsets[itemType.SectionIndex];
|
||||
}
|
||||
}
|
210
dexlib/src/main/java/org/jf/dexlib/Section.java
Normal file
210
dexlib/src/main/java/org/jf/dexlib/Section.java
Normal file
@ -0,0 +1,210 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.AlignmentUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
public abstract class Section<T extends Item> {
|
||||
/**
|
||||
* A list of the items that this section contains.
|
||||
* If the section has been placed, this list should be in the order that the items
|
||||
* will written to the dex file
|
||||
*/
|
||||
protected final ArrayList<T> items;
|
||||
|
||||
/**
|
||||
* A HashMap of the items in this section. This is used when interning items, to determine
|
||||
* if this section already has an item equivalent to the one that is being interned.
|
||||
* Both the key and the value should be the same object
|
||||
*/
|
||||
protected HashMap<T,T> uniqueItems = null;
|
||||
|
||||
/**
|
||||
* The offset of this section within the <code>DexFile</code>
|
||||
*/
|
||||
protected int offset = -1;
|
||||
|
||||
/**
|
||||
* The type of item that this section holds
|
||||
*/
|
||||
public final ItemType ItemType;
|
||||
|
||||
/**
|
||||
* The <code>DexFile</code> that this section belongs to
|
||||
*/
|
||||
public final DexFile DexFile;
|
||||
|
||||
/**
|
||||
* Create a new section
|
||||
* @param dexFile The <code>DexFile</code> that this section belongs to
|
||||
* @param itemType The itemType that this section will hold
|
||||
*/
|
||||
protected Section(DexFile dexFile, ItemType itemType) {
|
||||
this.DexFile = dexFile;
|
||||
items = new ArrayList<T>();
|
||||
this.ItemType = itemType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize the location of all items, and place them starting at the given offset
|
||||
* @param offset The offset where this section should be placed
|
||||
* @return the offset of the byte immediate after the last item in this section
|
||||
*/
|
||||
protected int placeAt(int offset) {
|
||||
if (items.size() > 0) {
|
||||
offset = AlignmentUtils.alignOffset(offset, ItemType.ItemAlignment);
|
||||
this.offset = offset;
|
||||
|
||||
for (int i=0; i < items.size(); i++) {
|
||||
T item = items.get(i);
|
||||
Assert.assertTrue("This section contains a null item", item != null);
|
||||
offset = AlignmentUtils.alignOffset(offset, ItemType.ItemAlignment);
|
||||
offset = item.placeAt(offset, i);
|
||||
}
|
||||
} else {
|
||||
this.offset = -1;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the items to the given <code>AnnotatedOutput</code>
|
||||
* @param out the <code>AnnotatedOutput</code> object to write to
|
||||
*/
|
||||
protected void writeTo(AnnotatedOutput out) {
|
||||
for (Item item: items) {
|
||||
Assert.assertTrue("This section contains a null item", item != null);
|
||||
out.alignTo(ItemType.ItemAlignment);
|
||||
item.writeTo(out);
|
||||
out.annotate(0, " ");
|
||||
}
|
||||
out.annotate(0, " ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the specified number of items from the given <code>Input</code> object
|
||||
* @param size The number of items to read
|
||||
* @param in The <code>Input</code> object to read from
|
||||
* @param readContext a <code>ReadContext</code> object to hold information that is
|
||||
* only needed while reading in a file
|
||||
*/
|
||||
protected void readFrom(int size, Input in, ReadContext readContext) {
|
||||
//readItems() expects that the list will already be the correct size, so add null items
|
||||
//until we reach the specified size
|
||||
items.ensureCapacity(size);
|
||||
for (int i = items.size(); i < size; i++) {
|
||||
items.add(null);
|
||||
}
|
||||
|
||||
in.alignTo(ItemType.ItemAlignment);
|
||||
offset = in.getCursor();
|
||||
|
||||
//call the subclass's method that actually reads in the items
|
||||
readItems(in, readContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method in the concrete item subclass should read in all the items from the given <code>Input</code>
|
||||
* object, using any pre-created items as applicable (i.e. items that were created prior to reading in the
|
||||
* section, by other items requesting items from this section that they reference by index/offset)
|
||||
* @param in the <code>Input</code>
|
||||
* @param readContext a <code>ReadContext</code> object to hold information that is
|
||||
* only needed while reading in a file
|
||||
*/
|
||||
protected abstract void readItems(Input in, ReadContext readContext);
|
||||
|
||||
/**
|
||||
* Gets the offset where the first item in this section is placed
|
||||
* @return the ofset where the first item in this section is placed
|
||||
*/
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a the items contained in this section as a read-only list
|
||||
* @return A read-only <code>List</code> object containing the items in this section
|
||||
*/
|
||||
public List<T> getItems() {
|
||||
return Collections.unmodifiableList(items);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks if an item that is equivalent to the given item has already been added. If found,
|
||||
* it returns that item. If not found, it adds the given item to this section and returns it.
|
||||
* @param item the item to intern
|
||||
* @return An item from this section that is equivalent to the given item. It may or may not be the same
|
||||
* as the item passed to this method.
|
||||
*/
|
||||
protected T intern(T item) {
|
||||
T internedItem = getInternedItem(item);
|
||||
if (internedItem == null) {
|
||||
uniqueItems.put(item, item);
|
||||
return item;
|
||||
}
|
||||
return internedItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the interned item that is equivalent to the given item, or null
|
||||
* @param item the item to check
|
||||
* @return the interned item that is equivalent to the given item, or null
|
||||
*/
|
||||
protected T getInternedItem(T item) {
|
||||
if (uniqueItems == null) {
|
||||
buildInternedItemMap();
|
||||
}
|
||||
return uniqueItems.get(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the interned item map from the items that are in this section
|
||||
*/
|
||||
private void buildInternedItemMap() {
|
||||
uniqueItems = new HashMap<T,T>();
|
||||
for (T item: items) {
|
||||
Assert.assertTrue("item shouldn't be null here", item != null);
|
||||
uniqueItems.put(item, item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the items in the section
|
||||
*/
|
||||
protected void sortSection() {
|
||||
Collections.sort(items);
|
||||
}
|
||||
}
|
149
dexlib/src/main/java/org/jf/dexlib/StringDataItem.java
Normal file
149
dexlib/src/main/java/org/jf/dexlib/StringDataItem.java
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.Util.*;
|
||||
|
||||
public class StringDataItem extends Item<StringDataItem> {
|
||||
private int hashCode = 0;
|
||||
|
||||
private String stringValue;
|
||||
|
||||
/**
|
||||
* Creates a new uninitialized <code>StringDataItem</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
*/
|
||||
protected StringDataItem(DexFile dexFile) {
|
||||
super(dexFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>StringDataItem</code> for the given string
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param stringValue The string value that this item represents
|
||||
*/
|
||||
private StringDataItem(DexFile dexFile, String stringValue) {
|
||||
super(dexFile);
|
||||
|
||||
this.stringValue = stringValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <code>StringDataItem</code> for the given values, and that has been interned into
|
||||
* the given <code>DexFile</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param value The string value that this item represents
|
||||
* @return a <code>StringDataItem</code> for the given values, and that has been interned into
|
||||
* the given <code>DexFile</code>
|
||||
*/
|
||||
public static StringDataItem getInternedStringDataItem(DexFile dexFile, String value) {
|
||||
StringDataItem StringDataItem = new StringDataItem(dexFile, value);
|
||||
return dexFile.StringDataSection.intern(StringDataItem);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void readItem(Input in, ReadContext readContext) {
|
||||
in.readUnsignedLeb128(); //string length
|
||||
stringValue = Utf8Utils.utf8BytesToString(in.readNullTerminatedBytes());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int placeItem(int offset) {
|
||||
return offset + 4 + Utf8Utils.stringToUtf8Bytes(stringValue).length + 1;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void writeItem(AnnotatedOutput out) {
|
||||
byte[] encodedValue = Utf8Utils.stringToUtf8Bytes(stringValue);
|
||||
if (out.annotates()) {
|
||||
out.annotate(stringValue.length(), "string_size");
|
||||
out.annotate(encodedValue.length + 1, "string_data (" + Utf8Utils.escapeString(stringValue) + ")");
|
||||
}
|
||||
|
||||
out.writeUnsignedLeb128(stringValue.length());
|
||||
out.write(encodedValue);
|
||||
out.writeByte(0);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_STRING_DATA_ITEM;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String getConciseIdentity() {
|
||||
return "string_data_item: " + Utf8Utils.escapeString(getStringValue());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int compareTo(StringDataItem o) {
|
||||
return getStringValue().compareTo(o.getStringValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the string value of this item as a <code>String</code>
|
||||
* @return the string value of this item as a String
|
||||
*/
|
||||
public String getStringValue() {
|
||||
return stringValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate and cache the hashcode
|
||||
*/
|
||||
private void calcHashCode() {
|
||||
hashCode = getStringValue().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
//there's a small possibility that the actual hash code will be 0. If so, we'll
|
||||
//just end up recalculating it each time
|
||||
if (hashCode == 0)
|
||||
calcHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this==o) {
|
||||
return true;
|
||||
}
|
||||
if (o==null || !this.getClass().equals(o.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//This assumes that the referenced items have been interned in both objects.
|
||||
//This is a valid assumption because all outside code must use the static
|
||||
//"getInterned..." style methods to make new items, and any item created
|
||||
//internally is guaranteed to be interned
|
||||
StringDataItem other = (StringDataItem)o;
|
||||
return getStringValue().equals(other.getStringValue());
|
||||
}
|
||||
}
|
154
dexlib/src/main/java/org/jf/dexlib/StringIdItem.java
Normal file
154
dexlib/src/main/java/org/jf/dexlib/StringIdItem.java
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.Util.Utf8Utils;
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
public class StringIdItem extends Item<StringIdItem> {
|
||||
private StringDataItem stringDataItem;
|
||||
|
||||
/**
|
||||
* Creates a new uninitialized <code>StringIdItem</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
*/
|
||||
protected StringIdItem(DexFile dexFile) {
|
||||
super(dexFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>StringIdItem</code> for the given <code>StringDataItem</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param stringDataItem The <code>StringDataItem</code> that this <code>StringIdItem</code> represents
|
||||
*/
|
||||
protected StringIdItem(DexFile dexFile, StringDataItem stringDataItem) {
|
||||
super(dexFile);
|
||||
this.stringDataItem = stringDataItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>StringIdItem</code> and associated <code>StringDataItem</code>
|
||||
* for the given <code>String</code> value
|
||||
* @param dexFile The <code>DexFile</code> that this item will belong to
|
||||
* @param stringValue The string value that this item represents
|
||||
*/
|
||||
private StringIdItem(DexFile dexFile, String stringValue) {
|
||||
this(dexFile, StringDataItem.getInternedStringDataItem(dexFile, stringValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <code>StringIdItem</code> for the given values, and that has been interned into
|
||||
* the given <code>DexFile</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item will belong to
|
||||
* @param stringValue The string value that this item represents
|
||||
* @return a <code>StringIdItem</code> for the given values, and that has been interned into
|
||||
* the given <code>DexFile</code>
|
||||
*/
|
||||
public static StringIdItem getInternedStringIdItem(DexFile dexFile, String stringValue) {
|
||||
StringIdItem stringIdItem = new StringIdItem(dexFile, stringValue);
|
||||
return dexFile.StringIdsSection.intern(stringIdItem);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void readItem(Input in, ReadContext readContext) {
|
||||
int stringDataOffset = in.readInt();
|
||||
|
||||
stringDataItem = (StringDataItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_STRING_DATA_ITEM,
|
||||
stringDataOffset);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int placeItem(int offset) {
|
||||
return offset + 4;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void writeItem(AnnotatedOutput out) {
|
||||
if (out.annotates()) {
|
||||
out.annotate(4, stringDataItem.getConciseIdentity());
|
||||
}
|
||||
|
||||
out.writeInt(stringDataItem.getOffset());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_STRING_ID_ITEM;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String getConciseIdentity() {
|
||||
return "string_id_item: " + Utf8Utils.escapeString(getStringValue());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int compareTo(StringIdItem o) {
|
||||
//sort by the string value
|
||||
return getStringValue().compareTo(o.getStringValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the <code>String</code> value that this <code>StringIdItem</code> represents
|
||||
* @return the <code>String</code> value that this <code>StringIdItem</code> represents
|
||||
*/
|
||||
public String getStringValue() {
|
||||
return stringDataItem.getStringValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the <code>StringDataItem</code> that this <code>StringIdItem</code> references
|
||||
* @return the <code>StringDataItem</code> that this <code>StringIdItem</code> references
|
||||
*/
|
||||
public StringDataItem getStringDataItem() {
|
||||
return stringDataItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return stringDataItem.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this==o) {
|
||||
return true;
|
||||
}
|
||||
if (o==null || !this.getClass().equals(o.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//This assumes that the referenced items have been interned in both objects.
|
||||
//This is a valid assumption because all outside code must use the static
|
||||
//"getInterned..." style methods to make new items, and any item created
|
||||
//internally is guaranteed to be interned
|
||||
StringIdItem other = (StringIdItem)o;
|
||||
return stringDataItem == other.stringDataItem;
|
||||
}
|
||||
}
|
163
dexlib/src/main/java/org/jf/dexlib/TypeIdItem.java
Normal file
163
dexlib/src/main/java/org/jf/dexlib/TypeIdItem.java
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
public class TypeIdItem extends Item<TypeIdItem> {
|
||||
private StringIdItem typeDescriptor;
|
||||
|
||||
/**
|
||||
* Creates a new uninitialized <code>TypeIdItem</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
*/
|
||||
protected TypeIdItem(DexFile dexFile) {
|
||||
super(dexFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>TypeIdItem</code> for the given <code>StringIdItem</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item will belong to
|
||||
* @param typeDescriptor The <code>StringIdItem</code> containing the type descriptor that
|
||||
* this <code>TypeIdItem</code> represents
|
||||
*/
|
||||
private TypeIdItem(DexFile dexFile, StringIdItem typeDescriptor) {
|
||||
super(dexFile);
|
||||
this.typeDescriptor = typeDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <code>TypeIdItem</code> for the given values, and that has been interned into
|
||||
* the given <code>DexFile</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item will belong to
|
||||
* @param typeDescriptor The <code>StringIdItem</code> containing the type descriptor that
|
||||
* @return a <code>TypeIdItem</code> for the given values, and that has been interned into
|
||||
* the given <code>DexFile</code>
|
||||
*/
|
||||
public static TypeIdItem getInternedTypeIdItem(DexFile dexFile, StringIdItem typeDescriptor) {
|
||||
TypeIdItem typeIdItem = new TypeIdItem(dexFile, typeDescriptor);
|
||||
return dexFile.TypeIdsSection.intern(typeIdItem);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void readItem(Input in, ReadContext readContext) {
|
||||
int stringIdIndex = in.readInt();
|
||||
this.typeDescriptor = dexFile.StringIdsSection.getItemByIndex(stringIdIndex);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int placeItem(int offset) {
|
||||
return offset + 4;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void writeItem(AnnotatedOutput out) {
|
||||
if (out.annotates()) {
|
||||
out.annotate(4, typeDescriptor.getConciseIdentity());
|
||||
}
|
||||
|
||||
out.writeInt(typeDescriptor.getIndex());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_TYPE_ID_ITEM;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String getConciseIdentity() {
|
||||
return "type_id_item: " + getTypeDescriptor();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int compareTo(TypeIdItem o) {
|
||||
//sort by the index of the StringIdItem
|
||||
return typeDescriptor.compareTo(o.typeDescriptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type descriptor as a <code>String</code> for this type
|
||||
* @return the type descriptor as a <code>String</code> for this type
|
||||
*/
|
||||
public String getTypeDescriptor() {
|
||||
return typeDescriptor.getStringValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "shorty" representation of this type, used to create the shorty prototype string for a method
|
||||
* @return the "shorty" representation of this type, used to create the shorty prototype string for a method
|
||||
*/
|
||||
public String toShorty() {
|
||||
String type = getTypeDescriptor();
|
||||
if (type.length() > 1) {
|
||||
return "L";
|
||||
} else {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the number of 2-byte registers that an instance of this type requires
|
||||
* @return The number of 2-byte registers that an instance of this type requires
|
||||
*/
|
||||
public int getRegisterCount() {
|
||||
String type = this.getTypeDescriptor();
|
||||
/** Only the long and double primitive types are 2 words,
|
||||
* everything else is a single word
|
||||
*/
|
||||
if (type.equals("J") || type.equals("D")) {
|
||||
return 2;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return typeDescriptor.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this==o) {
|
||||
return true;
|
||||
}
|
||||
if (o==null || !this.getClass().equals(o.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//This assumes that the referenced items have been interned in both objects.
|
||||
//This is a valid assumption because all outside code must use the static
|
||||
//"getInterned..." style methods to make new items, and any item created
|
||||
//internally is guaranteed to be interned
|
||||
TypeIdItem other = (TypeIdItem)o;
|
||||
return typeDescriptor == other.typeDescriptor;
|
||||
}
|
||||
}
|
255
dexlib/src/main/java/org/jf/dexlib/TypeListItem.java
Normal file
255
dexlib/src/main/java/org/jf/dexlib/TypeListItem.java
Normal file
@ -0,0 +1,255 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib;
|
||||
|
||||
import org.jf.dexlib.Util.Input;
|
||||
import org.jf.dexlib.Util.AnnotatedOutput;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TypeListItem extends Item<TypeListItem> {
|
||||
private int hashCode = 0;
|
||||
|
||||
private TypeIdItem[] typeList;
|
||||
|
||||
/**
|
||||
* Creates a new uninitialized <code>TypeListItem</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
*/
|
||||
protected TypeListItem(DexFile dexFile) {
|
||||
super(dexFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>TypeListItem</code> for the given string
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param typeList A list of the types that this <code>TypeListItem</code> represents
|
||||
*/
|
||||
private TypeListItem(DexFile dexFile, List<TypeIdItem> typeList) {
|
||||
super(dexFile);
|
||||
|
||||
this.typeList = new TypeIdItem[typeList.size()];
|
||||
typeList.toArray(this.typeList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <code>TypeListItem</code> for the given values, and that has been interned into
|
||||
* the given <code>DexFile</code>
|
||||
* @param dexFile The <code>DexFile</code> that this item belongs to
|
||||
* @param typeList A list of the types that this <code>TypeListItem</code> represents
|
||||
* @return a <code>TypeListItem</code> for the given values, and that has been interned into
|
||||
* the given <code>DexFile</code>
|
||||
*/
|
||||
public static TypeListItem getInternedTypeListItem(DexFile dexFile, List<TypeIdItem> typeList) {
|
||||
TypeListItem typeListItem = new TypeListItem(dexFile, typeList);
|
||||
return dexFile.TypeListsSection.intern(typeListItem);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void readItem(Input in, ReadContext readContext) {
|
||||
int size = in.readInt();
|
||||
typeList = new TypeIdItem[size];
|
||||
for (int i=0; i<size; i++) {
|
||||
int typeIndex = in.readShort();
|
||||
typeList[i] = dexFile.TypeIdsSection.getItemByIndex(typeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected int placeItem(int offset) {
|
||||
return offset + 4 + typeList.length * 2;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void writeItem(AnnotatedOutput out) {
|
||||
//yes, the code to write the item is duplicated. This eliminates the need to iterate over the list twice
|
||||
|
||||
if (out.annotates()) {
|
||||
out.annotate(4, "size: " + typeList.length);
|
||||
out.writeInt(typeList.length);
|
||||
|
||||
for (TypeIdItem typeIdItem: typeList) {
|
||||
out.annotate(2, typeIdItem.getConciseIdentity());
|
||||
out.writeShort(typeIdItem.getIndex());
|
||||
}
|
||||
} else {
|
||||
|
||||
out.writeInt(typeList.length);
|
||||
for (TypeIdItem typeIdItem: typeList) {
|
||||
out.writeShort(typeIdItem.getIndex());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public ItemType getItemType() {
|
||||
return ItemType.TYPE_TYPE_LIST;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String getConciseIdentity() {
|
||||
return "type_list: " + getTypeListString();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int compareTo(TypeListItem o) {
|
||||
if (o == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int thisSize = typeList.length;
|
||||
int otherSize = o.typeList.length;
|
||||
int size = Math.min(thisSize, otherSize);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
int result = typeList[i].compareTo(o.typeList[i]);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (thisSize < otherSize) {
|
||||
return -1;
|
||||
} else if (thisSize > otherSize) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of registers required for this <code>TypeListItem</code>
|
||||
*/
|
||||
public int getRegisterCount() {
|
||||
int wordCount = 0;
|
||||
for (TypeIdItem typeIdItem: typeList) {
|
||||
wordCount += typeIdItem.getRegisterCount();
|
||||
}
|
||||
return wordCount;
|
||||
}
|
||||
|
||||
private String cachedTypeListString = null;
|
||||
/**
|
||||
* @return a string consisting of the type descriptors in this <code>TypeListItem</code>
|
||||
* that are directly concatenated together
|
||||
*/
|
||||
public String getTypeListString() {
|
||||
|
||||
if (cachedTypeListString == null) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (TypeIdItem typeIdItem: typeList) {
|
||||
sb.append(typeIdItem.getTypeDescriptor());
|
||||
}
|
||||
cachedTypeListString = sb.toString();
|
||||
}
|
||||
return cachedTypeListString;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a string consisting of the shorty form of the type descriptors in this
|
||||
* <code>TypeListItem</code> that are directly concatenated together
|
||||
*/
|
||||
public String getShortyString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (TypeIdItem typeIdItem: typeList) {
|
||||
sb.append(typeIdItem.toShorty());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param index the index of the <code>TypeIdItem</code> to get
|
||||
* @return the <code>TypeIdItem</code> at the given index
|
||||
*/
|
||||
public TypeIdItem getTypeIdItem(int index) {
|
||||
return typeList[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of types in this <code>TypeListItem</code>
|
||||
*/
|
||||
public int getTypeCount() {
|
||||
return typeList.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an array of the <code>TypeIdItems</code> in this <code>TypeListItem</code>
|
||||
*/
|
||||
public TypeIdItem[] getTypes() {
|
||||
return typeList.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate and cache the hashcode
|
||||
*/
|
||||
private void calcHashCode() {
|
||||
int hashCode = 1;
|
||||
|
||||
for (TypeIdItem typeIdItem: typeList) {
|
||||
hashCode = 31 * hashCode + typeIdItem.hashCode();
|
||||
}
|
||||
this.hashCode = hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
//there's a small possibility that the actual hash code will be 0. If so, we'll
|
||||
//just end up recalculating it each time
|
||||
if (hashCode == 0)
|
||||
calcHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this==o) {
|
||||
return true;
|
||||
}
|
||||
if (o==null || !this.getClass().equals(o.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//This assumes that the referenced items have been interned in both objects.
|
||||
//This is a valid assumption because all outside code must use the static
|
||||
//"getInterned..." style methods to make new items, and any item created
|
||||
//internally is guaranteed to be interned
|
||||
TypeListItem other = (TypeListItem)o;
|
||||
if (typeList.length != other.typeList.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i=0; i<typeList.length; i++) {
|
||||
if (typeList[i] != other.typeList[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
125
dexlib/src/main/java/org/jf/dexlib/Util/AccessFlags.java
Normal file
125
dexlib/src/main/java/org/jf/dexlib/Util/AccessFlags.java
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public enum AccessFlags
|
||||
{
|
||||
PUBLIC(0x1, "public", true, true, true),
|
||||
PRIVATE(0x2, "private", true, true, true),
|
||||
PROTECTED(0x4, "protected", true, true, true),
|
||||
STATIC(0x8, "static", true, true, true),
|
||||
FINAL(0x10, "final", true, true, true),
|
||||
SYNCHRONIZED(0x20, "synchronized", false, true, false),
|
||||
VOLATILE(0x40, "volatile", false, false, true),
|
||||
BRIDGE(0x40, "bridge", false, true, false),
|
||||
TRANSIENT(0x80, "transient", false, false, true),
|
||||
VARARGS(0x80, "varargs", false, true, false),
|
||||
NATIVE(0x100, "native", false, true, false),
|
||||
INTERFACE(0x200, "interface", true, false, false),
|
||||
ABSTRACT(0x400, "abstract", true, true, false),
|
||||
STRICTFP(0x800, "strictfp", false, true, false),
|
||||
SYNTHETIC(0x1000, "synthetic", true, true, true),
|
||||
ANNOTATION(0x2000, "annotation", true, false, false),
|
||||
ENUM(0x4000, "enum", true, false, true),
|
||||
CONSTRUCTOR(0x10000, "constructor", false, true, false),
|
||||
DECLARED_SYNCHRONIZED(0x20000, "declared-synchronized", false, true, false);
|
||||
|
||||
private int value;
|
||||
private String accessFlagName;
|
||||
private boolean validForClass;
|
||||
private boolean validForMethod;
|
||||
private boolean validForField;
|
||||
|
||||
private static HashMap<String, AccessFlags> accessFlagsByName;
|
||||
|
||||
static {
|
||||
accessFlagsByName = new HashMap<String, AccessFlags>();
|
||||
for (AccessFlags accessFlag: AccessFlags.values()) {
|
||||
accessFlagsByName.put(accessFlag.accessFlagName, accessFlag);
|
||||
}
|
||||
}
|
||||
|
||||
private AccessFlags(int value, String accessFlagName, boolean validForClass, boolean validForMethod,
|
||||
boolean validForField) {
|
||||
this.value = value;
|
||||
this.accessFlagName = accessFlagName;
|
||||
this.validForClass = validForClass;
|
||||
this.validForMethod = validForMethod;
|
||||
this.validForField = validForField;
|
||||
}
|
||||
|
||||
public static List<AccessFlags> getAccessFlagsForClass(int accessFlagValue) {
|
||||
ArrayList<AccessFlags> accessFlags = new ArrayList<AccessFlags>();
|
||||
|
||||
for (AccessFlags accessFlag: AccessFlags.values()) {
|
||||
if (accessFlag.validForClass && (accessFlagValue & accessFlag.value) != 0) {
|
||||
accessFlags.add(accessFlag);
|
||||
}
|
||||
}
|
||||
return accessFlags;
|
||||
}
|
||||
|
||||
public static List<AccessFlags> getAccessFlagsForMethod(int accessFlagValue) {
|
||||
ArrayList<AccessFlags> accessFlags = new ArrayList<AccessFlags>();
|
||||
|
||||
for (AccessFlags accessFlag: AccessFlags.values()) {
|
||||
if (accessFlag.validForMethod && (accessFlagValue & accessFlag.value) != 0) {
|
||||
accessFlags.add(accessFlag);
|
||||
}
|
||||
}
|
||||
return accessFlags;
|
||||
}
|
||||
|
||||
public static List<AccessFlags> getAccessFlagsForField(int accessFlagValue) {
|
||||
ArrayList<AccessFlags> accessFlags = new ArrayList<AccessFlags>();
|
||||
|
||||
for (AccessFlags accessFlag: AccessFlags.values()) {
|
||||
if (accessFlag.validForField && (accessFlagValue & accessFlag.value) != 0) {
|
||||
accessFlags.add(accessFlag);
|
||||
}
|
||||
}
|
||||
return accessFlags;
|
||||
}
|
||||
|
||||
public static AccessFlags getAccessFlag(String accessFlag) {
|
||||
return accessFlagsByName.get(accessFlag);
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return accessFlagName;
|
||||
}
|
||||
}
|
39
dexlib/src/main/java/org/jf/dexlib/Util/AlignmentUtils.java
Normal file
39
dexlib/src/main/java/org/jf/dexlib/Util/AlignmentUtils.java
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
public abstract class AlignmentUtils {
|
||||
public static int alignOffset(int offset, int alignment) {
|
||||
int mask = alignment - 1;
|
||||
Assert.assertFalse("bogus alignment", (alignment < 0) || ((mask & alignment) != 0));
|
||||
return (offset + mask) & ~mask;
|
||||
}
|
||||
}
|
97
dexlib/src/main/java/org/jf/dexlib/Util/AnnotatedOutput.java
Normal file
97
dexlib/src/main/java/org/jf/dexlib/Util/AnnotatedOutput.java
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util;
|
||||
|
||||
import org.jf.dexlib.Util.Output;
|
||||
|
||||
/**
|
||||
* Interface for a binary output destination that may be augmented
|
||||
* with textual annotations.
|
||||
*/
|
||||
public interface AnnotatedOutput
|
||||
extends Output {
|
||||
/**
|
||||
* Get whether this instance will actually keep annotations.
|
||||
*
|
||||
* @return <code>true</code> iff annotations are being kept
|
||||
*/
|
||||
public boolean annotates();
|
||||
|
||||
/**
|
||||
* Get whether this instance is intended to keep verbose annotations.
|
||||
* Annotators may use the result of calling this method to inform their
|
||||
* annotation activity.
|
||||
*
|
||||
* @return <code>true</code> iff annotations are to be verbose
|
||||
*/
|
||||
public boolean isVerbose();
|
||||
|
||||
/**
|
||||
* Add an annotation for the subsequent output. Any previously
|
||||
* open annotation will be closed by this call, and the new
|
||||
* annotation marks all subsequent output until another annotation
|
||||
* call.
|
||||
*
|
||||
* @param msg non-null; the annotation message
|
||||
*/
|
||||
public void annotate(String msg);
|
||||
|
||||
/**
|
||||
* Add an annotation for a specified amount of subsequent
|
||||
* output. Any previously open annotation will be closed by this
|
||||
* call. If there is already pending annotation from one or more
|
||||
* previous calls to this method, the new call "consumes" output
|
||||
* after all the output covered by the previous calls.
|
||||
*
|
||||
* @param amt >= 0; the amount of output for this annotation to
|
||||
* cover
|
||||
* @param msg non-null; the annotation message
|
||||
*/
|
||||
public void annotate(int amt, String msg);
|
||||
|
||||
/**
|
||||
* End the most recent annotation. Subsequent output will be unannotated,
|
||||
* until the next call to {@link #annotate}.
|
||||
*/
|
||||
public void endAnnotation();
|
||||
|
||||
/**
|
||||
* Get the maximum width of the annotated output. This is advisory:
|
||||
* Implementations of this interface are encouraged to deal with too-wide
|
||||
* output, but annotaters are encouraged to attempt to avoid exceeding
|
||||
* the indicated width.
|
||||
*
|
||||
* @return >= 1; the maximum width
|
||||
*/
|
||||
public int getAnnotationWidth();
|
||||
|
||||
public void setIndentAmount(int indentAmount);
|
||||
public void indent();
|
||||
public void deindent();
|
||||
}
|
74
dexlib/src/main/java/org/jf/dexlib/Util/ArrayUtils.java
Normal file
74
dexlib/src/main/java/org/jf/dexlib/Util/ArrayUtils.java
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.TreeMap;
|
||||
import java.util.Collections;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
|
||||
public class ArrayUtils {
|
||||
/**
|
||||
* Utility method to sort two related arrays - that is, two arrays where the elements are related to each other
|
||||
* by their position in the array. i.e. firstArray[0] is related to secondArray[0], firstArray[1] is related to
|
||||
* secondArray[1], and so on. The first array is sorted based on its implementation of Comparable, and the 2nd
|
||||
* array is sorted by it's related item in the first array, so that the same elements are still related to each
|
||||
* other after the sort
|
||||
* @param firstArray The first array, which contains the values to sort
|
||||
* @param secondArray The second array, which will be sorted based on the values in the first array
|
||||
* @param <A> The type of element in the first array
|
||||
* @param <B> the type of element in the second array
|
||||
*/
|
||||
public static <A extends Comparable<A>, B> void sortTwoArrays(A[] firstArray, B[] secondArray)
|
||||
{
|
||||
if (firstArray.length != secondArray.length) {
|
||||
throw new RuntimeException("Both arrays must be of the same length");
|
||||
}
|
||||
|
||||
class element
|
||||
{
|
||||
public A first;
|
||||
public B second;
|
||||
}
|
||||
|
||||
element[] elements = new element[firstArray.length];
|
||||
|
||||
Arrays.sort(elements, new Comparator<element>(){
|
||||
public int compare(element a, element b) {
|
||||
return a.first.compareTo(b.first);
|
||||
}
|
||||
});
|
||||
|
||||
for (int i=0; i<elements.length; i++) {
|
||||
firstArray[i] = elements[i].first;
|
||||
secondArray[i] = elements[i].second;
|
||||
}
|
||||
}
|
||||
}
|
257
dexlib/src/main/java/org/jf/dexlib/Util/ByteArray.java
Normal file
257
dexlib/src/main/java/org/jf/dexlib/Util/ByteArray.java
Normal file
@ -0,0 +1,257 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util;
|
||||
|
||||
/**
|
||||
* Wrapper for a <code>byte[]</code>, which provides read-only access and
|
||||
* can "reveal" a partial slice of the underlying array.
|
||||
*
|
||||
* <b>Note:</b> Multibyte accessors all use big-endian order.
|
||||
*/
|
||||
public final class ByteArray {
|
||||
/** non-null; underlying array */
|
||||
private final byte[] bytes;
|
||||
|
||||
/** <code>>= 0</code>; start index of the slice (inclusive) */
|
||||
private final int start;
|
||||
|
||||
/** <code>>= 0, <= bytes.length</code>; size computed as
|
||||
* <code>end - start</code> (in the constructor) */
|
||||
private final int size;
|
||||
|
||||
/**
|
||||
* Constructs an instance.
|
||||
*
|
||||
* @param bytes non-null; the underlying array
|
||||
* @param start <code>>= 0</code>; start index of the slice (inclusive)
|
||||
* @param end <code>>= start, <= bytes.length</code>; end index of
|
||||
* the slice (exclusive)
|
||||
*/
|
||||
public ByteArray(byte[] bytes, int start, int end) {
|
||||
if (bytes == null) {
|
||||
throw new NullPointerException("bytes == null");
|
||||
}
|
||||
|
||||
if (start < 0) {
|
||||
throw new IllegalArgumentException("start < 0");
|
||||
}
|
||||
|
||||
if (end < start) {
|
||||
throw new IllegalArgumentException("end < start");
|
||||
}
|
||||
|
||||
if (end > bytes.length) {
|
||||
throw new IllegalArgumentException("end > bytes.length");
|
||||
}
|
||||
|
||||
this.bytes = bytes;
|
||||
this.start = start;
|
||||
this.size = end - start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance from an entire <code>byte[]</code>.
|
||||
*
|
||||
* @param bytes non-null; the underlying array
|
||||
*/
|
||||
public ByteArray(byte[] bytes) {
|
||||
this(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of the array, in bytes.
|
||||
*
|
||||
* @return >= 0; the size
|
||||
*/
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a slice (that is, a sub-array) of this instance.
|
||||
*
|
||||
* @param start <code>>= 0</code>; start index of the slice (inclusive)
|
||||
* @param end <code>>= start, <= size()</code>; end index of
|
||||
* the slice (exclusive)
|
||||
* @return non-null; the slice
|
||||
*/
|
||||
public ByteArray slice(int start, int end) {
|
||||
checkOffsets(start, end);
|
||||
return new ByteArray(bytes, start + this.start, end + this.start);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offset into the given array represented by the given
|
||||
* offset into this instance.
|
||||
*
|
||||
* @param offset offset into this instance
|
||||
* @param bytes non-null; (alleged) underlying array
|
||||
* @return corresponding offset into <code>bytes</code>
|
||||
* @throws IllegalArgumentException thrown if <code>bytes</code> is
|
||||
* not the underlying array of this instance
|
||||
*/
|
||||
public int underlyingOffset(int offset, byte[] bytes) {
|
||||
if (bytes != this.bytes) {
|
||||
throw new IllegalArgumentException("wrong bytes");
|
||||
}
|
||||
|
||||
return start + offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <code>signed byte</code> value at a particular offset.
|
||||
*
|
||||
* @param off <code>>= 0, < size(); offset to fetch
|
||||
* @return <code>signed byte</code> at that offset
|
||||
*/
|
||||
public int getByte(int off) {
|
||||
checkOffsets(off, off + 1);
|
||||
return getByte0(off);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <code>signed short</code> value at a particular offset.
|
||||
*
|
||||
* @param off <code>>= 0, < (size() - 1); offset to fetch
|
||||
* @return <code>signed short</code> at that offset
|
||||
*/
|
||||
public int getShort(int off) {
|
||||
checkOffsets(off, off + 2);
|
||||
return (getByte0(off) << 8) | getUnsignedByte0(off + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <code>signed int</code> value at a particular offset.
|
||||
*
|
||||
* @param off <code>>= 0, < (size() - 3); offset to fetch
|
||||
* @return <code>signed int</code> at that offset
|
||||
*/
|
||||
public int getInt(int off) {
|
||||
checkOffsets(off, off + 4);
|
||||
return (getByte0(off) << 24) |
|
||||
(getUnsignedByte0(off + 1) << 16) |
|
||||
(getUnsignedByte0(off + 2) << 8) |
|
||||
getUnsignedByte0(off + 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <code>signed long</code> value at a particular offset.
|
||||
*
|
||||
* @param off <code>>= 0, < (size() - 7); offset to fetch
|
||||
* @return <code>signed int</code> at that offset
|
||||
*/
|
||||
public long getLong(int off) {
|
||||
checkOffsets(off, off + 8);
|
||||
int part1 = (getByte0(off) << 24) |
|
||||
(getUnsignedByte0(off + 1) << 16) |
|
||||
(getUnsignedByte0(off + 2) << 8) |
|
||||
getUnsignedByte0(off + 3);
|
||||
int part2 = (getByte0(off + 4) << 24) |
|
||||
(getUnsignedByte0(off + 5) << 16) |
|
||||
(getUnsignedByte0(off + 6) << 8) |
|
||||
getUnsignedByte0(off + 7);
|
||||
|
||||
return (part2 & 0xffffffffL) | ((long) part1) << 32;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <code>unsigned byte</code> value at a particular offset.
|
||||
*
|
||||
* @param off <code>>= 0, < size(); offset to fetch
|
||||
* @return <code>unsigned byte</code> at that offset
|
||||
*/
|
||||
public int getUnsignedByte(int off) {
|
||||
checkOffsets(off, off + 1);
|
||||
return getUnsignedByte0(off);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <code>unsigned short</code> value at a particular offset.
|
||||
*
|
||||
* @param off <code>>= 0, < (size() - 1); offset to fetch
|
||||
* @return <code>unsigned short</code> at that offset
|
||||
*/
|
||||
public int getUnsignedShort(int off) {
|
||||
checkOffsets(off, off + 2);
|
||||
return (getUnsignedByte0(off) << 8) | getUnsignedByte0(off + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the contents of this instance into the given raw
|
||||
* <code>byte[]</code> at the given offset. The given array must be
|
||||
* large enough.
|
||||
*
|
||||
* @param out non-null; array to hold the output
|
||||
* @param offset non-null; index into <code>out</code> for the first
|
||||
* byte of output
|
||||
*/
|
||||
public void getBytes(byte[] out, int offset) {
|
||||
if ((out.length - offset) < size) {
|
||||
throw new IndexOutOfBoundsException("(out.length - offset) < " +
|
||||
"size()");
|
||||
}
|
||||
|
||||
System.arraycopy(bytes, start, out, offset, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a range of offsets for validity, throwing if invalid.
|
||||
*
|
||||
* @param s start offset (inclusive)
|
||||
* @param e end offset (exclusive)
|
||||
*/
|
||||
private void checkOffsets(int s, int e) {
|
||||
if ((s < 0) || (e < s) || (e > size)) {
|
||||
throw new IllegalArgumentException("bad range: " + s + ".." + e +
|
||||
"; actual size " + size);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <code>signed byte</code> value at the given offset,
|
||||
* without doing any argument checking.
|
||||
*
|
||||
* @param off offset to fetch
|
||||
* @return byte at that offset
|
||||
*/
|
||||
private int getByte0(int off) {
|
||||
return bytes[start + off];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <code>unsigned byte</code> value at the given offset,
|
||||
* without doing any argument checking.
|
||||
*
|
||||
* @param off offset to fetch
|
||||
* @return byte at that offset
|
||||
*/
|
||||
private int getUnsignedByte0(int off) {
|
||||
return bytes[start + off] & 0xff;
|
||||
}
|
||||
}
|
@ -0,0 +1,682 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Implementation of {@link AnnotatedOutput} which stores the written data
|
||||
* into a <code>byte[]</code>.
|
||||
*
|
||||
* <p><b>Note:</b> As per the {@link Output} interface, multi-byte
|
||||
* writes all use little-endian order.</p>
|
||||
*/
|
||||
public final class ByteArrayAnnotatedOutput
|
||||
implements AnnotatedOutput {
|
||||
/** default size for stretchy instances */
|
||||
private static final int DEFAULT_SIZE = 1000;
|
||||
|
||||
/**
|
||||
* whether the instance is stretchy, that is, whether its array
|
||||
* may be resized to increase capacity
|
||||
*/
|
||||
private final boolean stretchy;
|
||||
|
||||
/** non-null; the data itself */
|
||||
private byte[] data;
|
||||
|
||||
/** >= 0; current output cursor */
|
||||
private int cursor;
|
||||
|
||||
/** whether annotations are to be verbose */
|
||||
private boolean verbose;
|
||||
|
||||
/**
|
||||
* null-ok; list of annotations, or <code>null</code> if this instance
|
||||
* isn't keeping them
|
||||
*/
|
||||
private ArrayList<Annotation> annotations;
|
||||
|
||||
/** >= 40 (if used); the desired maximum annotation width */
|
||||
private int annotationWidth;
|
||||
|
||||
/**
|
||||
* >= 8 (if used); the number of bytes of hex output to use
|
||||
* in annotations
|
||||
*/
|
||||
private int hexCols;
|
||||
|
||||
private int currentIndent = 0;
|
||||
private int indentAmount = 2;
|
||||
|
||||
/**
|
||||
* Constructs an instance with a fixed maximum size. Note that the
|
||||
* given array is the only one that will be used to store data. In
|
||||
* particular, no reallocation will occur in order to expand the
|
||||
* capacity of the resulting instance. Also, the constructed
|
||||
* instance does not keep annotations by default.
|
||||
*
|
||||
* @param data non-null; data array to use for output
|
||||
*/
|
||||
public ByteArrayAnnotatedOutput(byte[] data) {
|
||||
this(data, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a "stretchy" instance. The underlying array may be
|
||||
* reallocated. The constructed instance does not keep annotations
|
||||
* by default.
|
||||
*/
|
||||
public ByteArrayAnnotatedOutput() {
|
||||
this(new byte[DEFAULT_SIZE], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal constructor.
|
||||
*
|
||||
* @param data non-null; data array to use for output
|
||||
* @param stretchy whether the instance is to be stretchy
|
||||
*/
|
||||
private ByteArrayAnnotatedOutput(byte[] data, boolean stretchy) {
|
||||
if (data == null) {
|
||||
throw new NullPointerException("data == null");
|
||||
}
|
||||
|
||||
this.stretchy = stretchy;
|
||||
this.data = data;
|
||||
this.cursor = 0;
|
||||
this.verbose = false;
|
||||
this.annotations = null;
|
||||
this.annotationWidth = 0;
|
||||
this.hexCols = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying <code>byte[]</code> of this instance, which
|
||||
* may be larger than the number of bytes written
|
||||
*
|
||||
* @see #toByteArray
|
||||
*
|
||||
* @return non-null; the <code>byte[]</code>
|
||||
*/
|
||||
public byte[] getArray() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns a new <code>byte[]</code> that contains
|
||||
* the written contents exactly (that is, with no extra unwritten
|
||||
* bytes at the end).
|
||||
*
|
||||
* @see #getArray
|
||||
*
|
||||
* @return non-null; an appropriately-constructed array
|
||||
*/
|
||||
public byte[] toByteArray() {
|
||||
byte[] result = new byte[cursor];
|
||||
System.arraycopy(data, 0, result, 0, cursor);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int getCursor() {
|
||||
return cursor;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void assertCursor(int expectedCursor) {
|
||||
if (cursor != expectedCursor) {
|
||||
throw new ExceptionWithContext("expected cursor " +
|
||||
expectedCursor + "; actual value: " + cursor);
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeByte(int value) {
|
||||
int writeAt = cursor;
|
||||
int end = writeAt + 1;
|
||||
|
||||
if (stretchy) {
|
||||
ensureCapacity(end);
|
||||
} else if (end > data.length) {
|
||||
throwBounds();
|
||||
return;
|
||||
}
|
||||
|
||||
data[writeAt] = (byte) value;
|
||||
cursor = end;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeShort(int value) {
|
||||
int writeAt = cursor;
|
||||
int end = writeAt + 2;
|
||||
|
||||
if (stretchy) {
|
||||
ensureCapacity(end);
|
||||
} else if (end > data.length) {
|
||||
throwBounds();
|
||||
return;
|
||||
}
|
||||
|
||||
data[writeAt] = (byte) value;
|
||||
data[writeAt + 1] = (byte) (value >> 8);
|
||||
cursor = end;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeInt(int value) {
|
||||
int writeAt = cursor;
|
||||
int end = writeAt + 4;
|
||||
|
||||
if (stretchy) {
|
||||
ensureCapacity(end);
|
||||
} else if (end > data.length) {
|
||||
throwBounds();
|
||||
return;
|
||||
}
|
||||
|
||||
data[writeAt] = (byte) value;
|
||||
data[writeAt + 1] = (byte) (value >> 8);
|
||||
data[writeAt + 2] = (byte) (value >> 16);
|
||||
data[writeAt + 3] = (byte) (value >> 24);
|
||||
cursor = end;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeLong(long value) {
|
||||
int writeAt = cursor;
|
||||
int end = writeAt + 8;
|
||||
|
||||
if (stretchy) {
|
||||
ensureCapacity(end);
|
||||
} else if (end > data.length) {
|
||||
throwBounds();
|
||||
return;
|
||||
}
|
||||
|
||||
int half = (int) value;
|
||||
data[writeAt] = (byte) half;
|
||||
data[writeAt + 1] = (byte) (half >> 8);
|
||||
data[writeAt + 2] = (byte) (half >> 16);
|
||||
data[writeAt + 3] = (byte) (half >> 24);
|
||||
|
||||
half = (int) (value >> 32);
|
||||
data[writeAt + 4] = (byte) half;
|
||||
data[writeAt + 5] = (byte) (half >> 8);
|
||||
data[writeAt + 6] = (byte) (half >> 16);
|
||||
data[writeAt + 7] = (byte) (half >> 24);
|
||||
|
||||
cursor = end;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int writeUnsignedLeb128(int value) {
|
||||
long remaining = (value & 0xFFFFFFFFL) >> 7;
|
||||
long lValue = value;
|
||||
int count = 0;
|
||||
|
||||
while (remaining != 0) {
|
||||
writeByte((int)(lValue & 0x7f) | 0x80);
|
||||
lValue = remaining;
|
||||
remaining >>= 7;
|
||||
count++;
|
||||
}
|
||||
|
||||
writeByte((int)(lValue & 0x7f));
|
||||
return count + 1;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int writeSignedLeb128(int value) {
|
||||
int remaining = value >> 7;
|
||||
int count = 0;
|
||||
boolean hasMore = true;
|
||||
int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1;
|
||||
|
||||
while (hasMore) {
|
||||
hasMore = (remaining != end)
|
||||
|| ((remaining & 1) != ((value >> 6) & 1));
|
||||
|
||||
writeByte((value & 0x7f) | (hasMore ? 0x80 : 0));
|
||||
value = remaining;
|
||||
remaining >>= 7;
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void write(ByteArray bytes) {
|
||||
int blen = bytes.size();
|
||||
int writeAt = cursor;
|
||||
int end = writeAt + blen;
|
||||
|
||||
if (stretchy) {
|
||||
ensureCapacity(end);
|
||||
} else if (end > data.length) {
|
||||
throwBounds();
|
||||
return;
|
||||
}
|
||||
|
||||
bytes.getBytes(data, writeAt);
|
||||
cursor = end;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void write(byte[] bytes, int offset, int length) {
|
||||
int writeAt = cursor;
|
||||
int end = writeAt + length;
|
||||
int bytesEnd = offset + length;
|
||||
|
||||
// twos-complement math trick: ((x < 0) || (y < 0)) <=> ((x|y) < 0)
|
||||
if (((offset | length | end) < 0) || (bytesEnd > bytes.length)) {
|
||||
throw new IndexOutOfBoundsException("bytes.length " +
|
||||
bytes.length + "; " +
|
||||
offset + "..!" + end);
|
||||
}
|
||||
|
||||
if (stretchy) {
|
||||
ensureCapacity(end);
|
||||
} else if (end > data.length) {
|
||||
throwBounds();
|
||||
return;
|
||||
}
|
||||
|
||||
System.arraycopy(bytes, offset, data, writeAt, length);
|
||||
cursor = end;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void write(byte[] bytes) {
|
||||
write(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeZeroes(int count) {
|
||||
if (count < 0) {
|
||||
throw new IllegalArgumentException("count < 0");
|
||||
}
|
||||
|
||||
int end = cursor + count;
|
||||
|
||||
if (stretchy) {
|
||||
ensureCapacity(end);
|
||||
} else if (end > data.length) {
|
||||
throwBounds();
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* There is no need to actually write zeroes, since the array is
|
||||
* already preinitialized with zeroes.
|
||||
*/
|
||||
|
||||
cursor = end;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void alignTo(int alignment) {
|
||||
int mask = alignment - 1;
|
||||
|
||||
if ((alignment < 0) || ((mask & alignment) != 0)) {
|
||||
throw new IllegalArgumentException("bogus alignment");
|
||||
}
|
||||
|
||||
int end = (cursor + mask) & ~mask;
|
||||
|
||||
if (stretchy) {
|
||||
ensureCapacity(end);
|
||||
} else if (end > data.length) {
|
||||
throwBounds();
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* There is no need to actually write zeroes, since the array is
|
||||
* already preinitialized with zeroes.
|
||||
*/
|
||||
|
||||
cursor = end;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public boolean annotates() {
|
||||
return (annotations != null);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public boolean isVerbose() {
|
||||
return verbose;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void annotate(String msg) {
|
||||
if (annotations == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
endAnnotation();
|
||||
annotations.add(new Annotation(cursor, msg, currentIndent));
|
||||
}
|
||||
|
||||
public void indent() {
|
||||
currentIndent++;
|
||||
}
|
||||
|
||||
public void deindent() {
|
||||
currentIndent--;
|
||||
if (currentIndent < 0) {
|
||||
currentIndent = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void setIndentAmount(int indentAmount) {
|
||||
this.indentAmount = indentAmount;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void annotate(int amt, String msg) {
|
||||
if (annotations == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
endAnnotation();
|
||||
|
||||
int asz = annotations.size();
|
||||
int lastEnd = (asz == 0) ? 0 : annotations.get(asz - 1).getEnd();
|
||||
int startAt;
|
||||
|
||||
if (lastEnd <= cursor) {
|
||||
startAt = cursor;
|
||||
} else {
|
||||
startAt = lastEnd;
|
||||
}
|
||||
|
||||
annotations.add(new Annotation(startAt, startAt + amt, msg, currentIndent));
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void endAnnotation() {
|
||||
if (annotations == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int sz = annotations.size();
|
||||
|
||||
if (sz != 0) {
|
||||
annotations.get(sz - 1).setEndIfUnset(cursor);
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int getAnnotationWidth() {
|
||||
int leftWidth = 8 + (hexCols * 2) + (hexCols / 2);
|
||||
|
||||
return annotationWidth - leftWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that this instance should keep annotations. This method may
|
||||
* be called only once per instance, and only before any data has been
|
||||
* written to the it.
|
||||
*
|
||||
* @param annotationWidth >= 40; the desired maximum annotation width
|
||||
* @param verbose whether or not to indicate verbose annotations
|
||||
*/
|
||||
public void enableAnnotations(int annotationWidth, boolean verbose) {
|
||||
if ((annotations != null) || (cursor != 0)) {
|
||||
throw new RuntimeException("cannot enable annotations");
|
||||
}
|
||||
|
||||
if (annotationWidth < 40) {
|
||||
throw new IllegalArgumentException("annotationWidth < 40");
|
||||
}
|
||||
|
||||
int hexCols = (((annotationWidth - 7) / 15) + 1) & ~1;
|
||||
if (hexCols < 6) {
|
||||
hexCols = 6;
|
||||
} else if (hexCols > 10) {
|
||||
hexCols = 10;
|
||||
}
|
||||
|
||||
this.annotations = new ArrayList<Annotation>(1000);
|
||||
this.annotationWidth = annotationWidth;
|
||||
this.hexCols = hexCols;
|
||||
this.verbose = verbose;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes up annotation processing. This closes off any open
|
||||
* annotations and removes annotations that don't refer to written
|
||||
* data.
|
||||
*/
|
||||
public void finishAnnotating() {
|
||||
// Close off the final annotation, if any.
|
||||
endAnnotation();
|
||||
|
||||
// Remove annotations that refer to unwritten data.
|
||||
if (annotations != null) {
|
||||
int asz = annotations.size();
|
||||
while (asz > 0) {
|
||||
Annotation last = annotations.get(asz - 1);
|
||||
if (last.getStart() > cursor) {
|
||||
annotations.remove(asz - 1);
|
||||
asz--;
|
||||
} else if (last.getEnd() > cursor) {
|
||||
last.setEnd(cursor);
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the annotated content of this instance to the given writer.
|
||||
*
|
||||
* @param out non-null; where to write to
|
||||
*/
|
||||
public void writeAnnotationsTo(Writer out) throws IOException {
|
||||
int width2 = getAnnotationWidth();
|
||||
int width1 = annotationWidth - width2 - 1;
|
||||
|
||||
StringBuilder padding = new StringBuilder();
|
||||
for (int i=0; i<1000; i++) {
|
||||
padding.append(' ');
|
||||
}
|
||||
|
||||
TwoColumnOutput twoc = new TwoColumnOutput(out, width1, width2, "|");
|
||||
Writer left = twoc.getLeft();
|
||||
Writer right = twoc.getRight();
|
||||
int leftAt = 0; // left-hand byte output cursor
|
||||
int rightAt = 0; // right-hand annotation index
|
||||
int rightSz = annotations.size();
|
||||
|
||||
while ((leftAt < cursor) && (rightAt < rightSz)) {
|
||||
Annotation a = annotations.get(rightAt);
|
||||
int start = a.getStart();
|
||||
int end;
|
||||
String text;
|
||||
|
||||
if (leftAt < start) {
|
||||
// This is an area with no annotation.
|
||||
end = start;
|
||||
start = leftAt;
|
||||
text = "";
|
||||
} else {
|
||||
// This is an area with an annotation.
|
||||
end = a.getEnd();
|
||||
text = padding.substring(0, a.getIndent() * this.indentAmount) + a.getText();
|
||||
rightAt++;
|
||||
}
|
||||
|
||||
left.write(Hex.dump(data, start, end - start, start, hexCols, 6));
|
||||
right.write(text);
|
||||
twoc.flush();
|
||||
leftAt = end;
|
||||
}
|
||||
|
||||
if (leftAt < cursor) {
|
||||
// There is unannotated output at the end.
|
||||
left.write(Hex.dump(data, leftAt, cursor - leftAt, leftAt,
|
||||
hexCols, 6));
|
||||
}
|
||||
|
||||
while (rightAt < rightSz) {
|
||||
// There are zero-byte annotations at the end.
|
||||
right.write(annotations.get(rightAt).getText());
|
||||
rightAt++;
|
||||
}
|
||||
|
||||
twoc.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws the excpetion for when an attempt is made to write past the
|
||||
* end of the instance.
|
||||
*/
|
||||
private static void throwBounds() {
|
||||
throw new IndexOutOfBoundsException("attempt to write past the end");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reallocates the underlying array if necessary. Calls to this method
|
||||
* should be guarded by a test of {@link #stretchy}.
|
||||
*
|
||||
* @param desiredSize >= 0; the desired minimum total size of the array
|
||||
*/
|
||||
private void ensureCapacity(int desiredSize) {
|
||||
if (data.length < desiredSize) {
|
||||
byte[] newData = new byte[desiredSize * 2 + 1000];
|
||||
System.arraycopy(data, 0, newData, 0, cursor);
|
||||
data = newData;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotation on output.
|
||||
*/
|
||||
private static class Annotation {
|
||||
/** >= 0; start of annotated range (inclusive) */
|
||||
private final int start;
|
||||
|
||||
/**
|
||||
* >= 0; end of annotated range (exclusive);
|
||||
* <code>Integer.MAX_VALUE</code> if unclosed
|
||||
*/
|
||||
private int end;
|
||||
|
||||
/** non-null; annotation text */
|
||||
private final String text;
|
||||
|
||||
private int indent;
|
||||
|
||||
/**
|
||||
* Constructs an instance.
|
||||
*
|
||||
* @param start >= 0; start of annotated range
|
||||
* @param end >= start; end of annotated range (exclusive) or
|
||||
* <code>Integer.MAX_VALUE</code> if unclosed
|
||||
* @param text non-null; annotation text
|
||||
*/
|
||||
public Annotation(int start, int end, String text, int indent) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.text = text;
|
||||
this.indent = indent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance. It is initally unclosed.
|
||||
*
|
||||
* @param start >= 0; start of annotated range
|
||||
* @param text non-null; annotation text
|
||||
*/
|
||||
public Annotation(int start, String text, int indent) {
|
||||
this(start, Integer.MAX_VALUE, text, indent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the end as given, but only if the instance is unclosed;
|
||||
* otherwise, do nothing.
|
||||
*
|
||||
* @param end >= start; the end
|
||||
*/
|
||||
public void setEndIfUnset(int end) {
|
||||
if (this.end == Integer.MAX_VALUE) {
|
||||
this.end = end;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the end as given.
|
||||
*
|
||||
* @param end >= start; the end
|
||||
*/
|
||||
public void setEnd(int end) {
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the start.
|
||||
*
|
||||
* @return the start
|
||||
*/
|
||||
public int getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the end.
|
||||
*
|
||||
* @return the end
|
||||
*/
|
||||
public int getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the text.
|
||||
*
|
||||
* @return non-null; the text
|
||||
*/
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public int getIndent() {
|
||||
return indent;
|
||||
}
|
||||
}
|
||||
}
|
318
dexlib/src/main/java/org/jf/dexlib/Util/ByteArrayInput.java
Normal file
318
dexlib/src/main/java/org/jf/dexlib/Util/ByteArrayInput.java
Normal file
@ -0,0 +1,318 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util;
|
||||
|
||||
/**
|
||||
* Implementation of {@link Input} which reads the data from a
|
||||
* <code>byte[]</code> instance.
|
||||
*
|
||||
* <p><b>Note:</b> As per the {@link Input } interface, multi-byte
|
||||
* reads all use little-endian order.</p>
|
||||
*/
|
||||
public class ByteArrayInput
|
||||
implements Input {
|
||||
|
||||
/** non-null; the data itself */
|
||||
private byte[] data;
|
||||
|
||||
/** >= 0; current read cursor */
|
||||
private int cursor;
|
||||
|
||||
/**
|
||||
* Constructs an instance with the given data
|
||||
*
|
||||
* @param data non-null; data array to use for input
|
||||
*/
|
||||
public ByteArrayInput(byte[] data) {
|
||||
if (data == null) {
|
||||
throw new NullPointerException("data == null");
|
||||
}
|
||||
|
||||
this.data = data;
|
||||
this.cursor = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying <code>byte[]</code> of this instance
|
||||
*
|
||||
* @return non-null; the <code>byte[]</code>
|
||||
*/
|
||||
public byte[] getArray() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int getCursor() {
|
||||
return cursor;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void setCursor(int cursor) {
|
||||
if (cursor < 0 || cursor >= data.length)
|
||||
throw new IndexOutOfBoundsException("The provided cursor value " +
|
||||
"is not within the bounds of this instance's data array");
|
||||
this.cursor = cursor;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void assertCursor(int expectedCursor) {
|
||||
if (cursor != expectedCursor) {
|
||||
throw new ExceptionWithContext("expected cursor " +
|
||||
expectedCursor + "; actual value: " + cursor);
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public byte readByte() {
|
||||
int readAt = cursor;
|
||||
int end = readAt + 1;
|
||||
|
||||
if (end > data.length) {
|
||||
throwBounds();
|
||||
}
|
||||
|
||||
cursor = end;
|
||||
return data[readAt];
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int readShort() {
|
||||
int readAt = cursor;
|
||||
int end = readAt + 2;
|
||||
|
||||
if (end > data.length) {
|
||||
throwBounds();
|
||||
}
|
||||
|
||||
cursor = end;
|
||||
return (int)((data[readAt] & 0xff) +
|
||||
((data[readAt + 1] & 0xff) << 8));
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int readInt() {
|
||||
int readAt = cursor;
|
||||
int end = readAt + 4;
|
||||
|
||||
if (end > data.length) {
|
||||
throwBounds();
|
||||
}
|
||||
|
||||
cursor = end;
|
||||
return (data[readAt] & 0xff) +
|
||||
((data[readAt + 1] & 0xff) << 8) +
|
||||
((data[readAt + 2] & 0xff) << 16) +
|
||||
((data[readAt + 3] & 0xff) << 24);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public long readLong() {
|
||||
int readAt = cursor;
|
||||
int end = readAt + 8;
|
||||
|
||||
if (end > data.length) {
|
||||
throwBounds();
|
||||
}
|
||||
|
||||
cursor = end;
|
||||
|
||||
return (data[readAt] & 0xffL) |
|
||||
((data[readAt + 1] & 0xffL) << 8) |
|
||||
((data[readAt + 2] & 0xffL) << 16) |
|
||||
((data[readAt + 3] & 0xffL) << 24) |
|
||||
((data[readAt + 4] & 0xffL) << 32) |
|
||||
((data[readAt + 5] & 0xffL) << 40) |
|
||||
((data[readAt + 6] & 0xffL) << 48) |
|
||||
((data[readAt + 7] & 0xffL) << 58);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int readUnsignedLeb128() {
|
||||
int end = cursor;
|
||||
int currentByteValue;
|
||||
int result;
|
||||
|
||||
result = data[end++] & 0xff;
|
||||
if (result > 0x7f) {
|
||||
currentByteValue = data[end++] & 0xff;
|
||||
result = (result & 0x7f) | ((currentByteValue & 0x7f) << 7);
|
||||
if (currentByteValue > 0x7f) {
|
||||
currentByteValue = data[end++] & 0xff;
|
||||
result |= (currentByteValue & 0x7f) << 14;
|
||||
if (currentByteValue > 0x7f) {
|
||||
currentByteValue = data[end++] & 0xff;
|
||||
result |= (currentByteValue & 0x7f) << 21;
|
||||
if (currentByteValue > 0x7f) {
|
||||
currentByteValue = data[end++] & 0xff;
|
||||
if (currentByteValue > 0x0f) {
|
||||
throwInvalidLeb();
|
||||
}
|
||||
result |= currentByteValue << 28;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cursor = end;
|
||||
return result;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int readSignedLeb128() {
|
||||
int end = cursor;
|
||||
int currentByteValue;
|
||||
int result;
|
||||
|
||||
result = data[end++] & 0xff;
|
||||
if (result <= 0x7f) {
|
||||
result = (result << 25) >> 25;
|
||||
} else {
|
||||
currentByteValue = data[end++] & 0xff;
|
||||
result = (result & 0x7f) | ((currentByteValue & 0x7f) << 7);
|
||||
if (currentByteValue <= 0x7f) {
|
||||
result = (result << 18) >> 18;
|
||||
} else {
|
||||
currentByteValue = data[end++] & 0xff;
|
||||
result |= (currentByteValue & 0x7f) << 14;
|
||||
if (currentByteValue <= 0x7f) {
|
||||
result = (result << 11) >> 11;
|
||||
} else {
|
||||
currentByteValue = data[end++] & 0xff;
|
||||
result |= (currentByteValue & 0x7f) << 21;
|
||||
if (currentByteValue <= 0x7f) {
|
||||
result = (result << 4) >> 4;
|
||||
} else {
|
||||
currentByteValue = data[end++] & 0xff;
|
||||
if (currentByteValue > 0x0f) {
|
||||
throwInvalidLeb();
|
||||
}
|
||||
result |= currentByteValue << 28;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cursor = end;
|
||||
return result;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void read(byte[] bytes, int offset, int length) {
|
||||
int end = cursor + length;
|
||||
|
||||
if (end > data.length) {
|
||||
throwBounds();
|
||||
}
|
||||
|
||||
System.arraycopy(data, cursor, bytes, offset, length);
|
||||
cursor = end;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void read(byte[] bytes) {
|
||||
int length = bytes.length;
|
||||
int end = cursor + length;
|
||||
|
||||
if (end > data.length) {
|
||||
throwBounds();
|
||||
}
|
||||
|
||||
System.arraycopy(data, cursor, bytes, 0, length);
|
||||
cursor = end;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public byte[] readBytes(int length) {
|
||||
int end = cursor + length;
|
||||
|
||||
if (end > data.length) {
|
||||
throwBounds();
|
||||
}
|
||||
|
||||
byte[] result = new byte[length];
|
||||
System.arraycopy(data, cursor, result, 0, length);
|
||||
cursor = end;
|
||||
return result;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public byte[] readNullTerminatedBytes() {
|
||||
int startPosition = cursor;
|
||||
while (data[cursor] != 0) {
|
||||
cursor++;
|
||||
if (cursor >= data.length) {
|
||||
throwBounds();
|
||||
}
|
||||
}
|
||||
int byteCount = cursor - startPosition;
|
||||
//skip the terminating null
|
||||
cursor++;
|
||||
|
||||
byte[] result = new byte[byteCount];
|
||||
System.arraycopy(data, startPosition, result, 0, byteCount);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void skipBytes(int count) {
|
||||
int end = cursor + count;
|
||||
|
||||
if (end > data.length) {
|
||||
throwBounds();
|
||||
}
|
||||
|
||||
cursor = end;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void alignTo(int alignment) {
|
||||
int end = AlignmentUtils.alignOffset(cursor, alignment);
|
||||
|
||||
if (end > data.length) {
|
||||
throwBounds();
|
||||
}
|
||||
|
||||
cursor = end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws the excpetion for when an attempt is made to read past the
|
||||
* end of the instance.
|
||||
*/
|
||||
private static void throwBounds() {
|
||||
throw new IndexOutOfBoundsException("attempt to read past the end");
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws the exception for when an invalid LEB128 value is encountered
|
||||
*/
|
||||
private static void throwInvalidLeb() {
|
||||
throw new RuntimeException("invalid LEB128 integer encountered");
|
||||
}
|
||||
}
|
570
dexlib/src/main/java/org/jf/dexlib/Util/ByteArrayOutput.java
Normal file
570
dexlib/src/main/java/org/jf/dexlib/Util/ByteArrayOutput.java
Normal file
@ -0,0 +1,570 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jf.dexlib.Util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Implementation of {@link AnnotatedOutput} which stores the written data
|
||||
* into a <code>byte[]</code>.
|
||||
*
|
||||
* <p><b>Note:</b> As per the {@link Output} interface, multi-byte
|
||||
* writes all use little-endian order.</p>
|
||||
*/
|
||||
public final class ByteArrayOutput implements Output
|
||||
{
|
||||
/** default size for stretchy instances */
|
||||
private static final int DEFAULT_SIZE = 1000;
|
||||
|
||||
/**
|
||||
* whether the instance is stretchy, that is, whether its array
|
||||
* may be resized to increase capacity
|
||||
*/
|
||||
private final boolean stretchy;
|
||||
|
||||
/** non-null; the data itself */
|
||||
private byte[] data;
|
||||
|
||||
/** >= 0; current output cursor */
|
||||
private int cursor;
|
||||
|
||||
/** whether annotations are to be verbose */
|
||||
private boolean verbose;
|
||||
|
||||
/**
|
||||
* null-ok; list of annotations, or <code>null</code> if this instance
|
||||
* isn't keeping them
|
||||
*/
|
||||
private ArrayList<Annotation> annotations;
|
||||
|
||||
/** >= 40 (if used); the desired maximum annotation width */
|
||||
private int annotationWidth;
|
||||
|
||||
/**
|
||||
* >= 8 (if used); the number of bytes of hex output to use
|
||||
* in annotations
|
||||
*/
|
||||
private int hexCols;
|
||||
|
||||
/**
|
||||
* Constructs an instance with a fixed maximum size. Note that the
|
||||
* given array is the only one that will be used to store data. In
|
||||
* particular, no reallocation will occur in order to expand the
|
||||
* capacity of the resulting instance. Also, the constructed
|
||||
* instance does not keep annotations by default.
|
||||
*
|
||||
* @param data non-null; data array to use for output
|
||||
*/
|
||||
public ByteArrayOutput(byte[] data) {
|
||||
this(data, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a "stretchy" instance. The underlying array may be
|
||||
* reallocated. The constructed instance does not keep annotations
|
||||
* by default.
|
||||
*/
|
||||
public ByteArrayOutput() {
|
||||
this(new byte[DEFAULT_SIZE], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal constructor.
|
||||
*
|
||||
* @param data non-null; data array to use for output
|
||||
* @param stretchy whether the instance is to be stretchy
|
||||
*/
|
||||
private ByteArrayOutput(byte[] data, boolean stretchy) {
|
||||
if (data == null) {
|
||||
throw new NullPointerException("data == null");
|
||||
}
|
||||
|
||||
this.stretchy = stretchy;
|
||||
this.data = data;
|
||||
this.cursor = 0;
|
||||
this.verbose = false;
|
||||
this.annotations = null;
|
||||
this.annotationWidth = 0;
|
||||
this.hexCols = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying <code>byte[]</code> of this instance, which
|
||||
* may be larger than the number of bytes written
|
||||
*
|
||||
* @see #toByteArray
|
||||
*
|
||||
* @return non-null; the <code>byte[]</code>
|
||||
*/
|
||||
public byte[] getArray() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns a new <code>byte[]</code> that contains
|
||||
* the written contents exactly (that is, with no extra unwritten
|
||||
* bytes at the end).
|
||||
*
|
||||
* @see #getArray
|
||||
*
|
||||
* @return non-null; an appropriately-constructed array
|
||||
*/
|
||||
public byte[] toByteArray() {
|
||||
byte[] result = new byte[cursor];
|
||||
System.arraycopy(data, 0, result, 0, cursor);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int getCursor() {
|
||||
return cursor;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void assertCursor(int expectedCursor) {
|
||||
if (cursor != expectedCursor) {
|
||||
throw new ExceptionWithContext("expected cursor " +
|
||||
expectedCursor + "; actual value: " + cursor);
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeByte(int value) {
|
||||
int writeAt = cursor;
|
||||
int end = writeAt + 1;
|
||||
|
||||
if (stretchy) {
|
||||
ensureCapacity(end);
|
||||
} else if (end > data.length) {
|
||||
throwBounds();
|
||||
return;
|
||||
}
|
||||
|
||||
data[writeAt] = (byte) value;
|
||||
cursor = end;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeShort(int value) {
|
||||
int writeAt = cursor;
|
||||
int end = writeAt + 2;
|
||||
|
||||
if (stretchy) {
|
||||
ensureCapacity(end);
|
||||
} else if (end > data.length) {
|
||||
throwBounds();
|
||||
return;
|
||||
}
|
||||
|
||||
data[writeAt] = (byte) value;
|
||||
data[writeAt + 1] = (byte) (value >> 8);
|
||||
cursor = end;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeInt(int value) {
|
||||
int writeAt = cursor;
|
||||
int end = writeAt + 4;
|
||||
|
||||
if (stretchy) {
|
||||
ensureCapacity(end);
|
||||
} else if (end > data.length) {
|
||||
throwBounds();
|
||||
return;
|
||||
}
|
||||
|
||||
data[writeAt] = (byte) value;
|
||||
data[writeAt + 1] = (byte) (value >> 8);
|
||||
data[writeAt + 2] = (byte) (value >> 16);
|
||||
data[writeAt + 3] = (byte) (value >> 24);
|
||||
cursor = end;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeLong(long value) {
|
||||
int writeAt = cursor;
|
||||
int end = writeAt + 8;
|
||||
|
||||
if (stretchy) {
|
||||
ensureCapacity(end);
|
||||
} else if (end > data.length) {
|
||||
throwBounds();
|
||||
return;
|
||||
}
|
||||
|
||||
int half = (int) value;
|
||||
data[writeAt] = (byte) half;
|
||||
data[writeAt + 1] = (byte) (half >> 8);
|
||||
data[writeAt + 2] = (byte) (half >> 16);
|
||||
data[writeAt + 3] = (byte) (half >> 24);
|
||||
|
||||
half = (int) (value >> 32);
|
||||
data[writeAt + 4] = (byte) half;
|
||||
data[writeAt + 5] = (byte) (half >> 8);
|
||||
data[writeAt + 6] = (byte) (half >> 16);
|
||||
data[writeAt + 7] = (byte) (half >> 24);
|
||||
|
||||
cursor = end;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int writeUnsignedLeb128(int value) {
|
||||
int remaining = value >> 7;
|
||||
int count = 0;
|
||||
|
||||
while (remaining != 0) {
|
||||
writeByte((value & 0x7f) | 0x80);
|
||||
value = remaining;
|
||||
remaining >>= 7;
|
||||
count++;
|
||||
}
|
||||
|
||||
writeByte(value & 0x7f);
|
||||
return count + 1;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int writeSignedLeb128(int value) {
|
||||
int remaining = value >> 7;
|
||||
int count = 0;
|
||||
boolean hasMore = true;
|
||||
int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1;
|
||||
|
||||
while (hasMore) {
|
||||
hasMore = (remaining != end)
|
||||
|| ((remaining & 1) != ((value >> 6) & 1));
|
||||
|
||||
writeByte((value & 0x7f) | (hasMore ? 0x80 : 0));
|
||||
value = remaining;
|
||||
remaining >>= 7;
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void write(ByteArray bytes) {
|
||||
int blen = bytes.size();
|
||||
int writeAt = cursor;
|
||||
int end = writeAt + blen;
|
||||
|
||||
if (stretchy) {
|
||||
ensureCapacity(end);
|
||||
} else if (end > data.length) {
|
||||
throwBounds();
|
||||
return;
|
||||
}
|
||||
|
||||
bytes.getBytes(data, writeAt);
|
||||
cursor = end;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void write(byte[] bytes, int offset, int length) {
|
||||
int writeAt = cursor;
|
||||
int end = writeAt + length;
|
||||
int bytesEnd = offset + length;
|
||||
|
||||
// twos-complement math trick: ((x < 0) || (y < 0)) <=> ((x|y) < 0)
|
||||
if (((offset | length | end) < 0) || (bytesEnd > bytes.length)) {
|
||||
throw new IndexOutOfBoundsException("bytes.length " +
|
||||
bytes.length + "; " +
|
||||
offset + "..!" + end);
|
||||
}
|
||||
|
||||
if (stretchy) {
|
||||
ensureCapacity(end);
|
||||
} else if (end > data.length) {
|
||||
throwBounds();
|
||||
return;
|
||||
}
|
||||
|
||||
System.arraycopy(bytes, offset, data, writeAt, length);
|
||||
cursor = end;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void write(byte[] bytes) {
|
||||
write(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void writeZeroes(int count) {
|
||||
if (count < 0) {
|
||||
throw new IllegalArgumentException("count < 0");
|
||||
}
|
||||
|
||||
int end = cursor + count;
|
||||
|
||||
if (stretchy) {
|
||||
ensureCapacity(end);
|
||||
} else if (end > data.length) {
|
||||
throwBounds();
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* There is no need to actually write zeroes, since the array is
|
||||
* already preinitialized with zeroes.
|
||||
*/
|
||||
|
||||
cursor = end;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void alignTo(int alignment) {
|
||||
int end = AlignmentUtils.alignOffset(cursor, alignment);
|
||||
|
||||
if (stretchy) {
|
||||
ensureCapacity(end);
|
||||
} else if (end > data.length) {
|
||||
throwBounds();
|
||||
return;
|
||||
}
|
||||
cursor = end;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public boolean annotates() {
|
||||
return (annotations != null);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public boolean isVerbose() {
|
||||
return verbose;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void annotate(String msg) {
|
||||
if (annotations == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
endAnnotation();
|
||||
annotations.add(new Annotation(cursor, msg));
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void annotate(int amt, String msg) {
|
||||
if (annotations == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
endAnnotation();
|
||||
|
||||
int asz = annotations.size();
|
||||
int lastEnd = (asz == 0) ? 0 : annotations.get(asz - 1).getEnd();
|
||||
int startAt;
|
||||
|
||||
if (lastEnd <= cursor) {
|
||||
startAt = cursor;
|
||||
} else {
|
||||
startAt = lastEnd;
|
||||
}
|
||||
|
||||
annotations.add(new Annotation(startAt, startAt + amt, msg));
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void endAnnotation() {
|
||||
if (annotations == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int sz = annotations.size();
|
||||
|
||||
if (sz != 0) {
|
||||
annotations.get(sz - 1).setEndIfUnset(cursor);
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public int getAnnotationWidth() {
|
||||
int leftWidth = 8 + (hexCols * 2) + (hexCols / 2);
|
||||
|
||||
return annotationWidth - leftWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that this instance should keep annotations. This method may
|
||||
* be called only once per instance, and only before any data has been
|
||||
* written to the it.
|
||||
*
|
||||
* @param annotationWidth >= 40; the desired maximum annotation width
|
||||
* @param verbose whether or not to indicate verbose annotations
|
||||
*/
|
||||
public void enableAnnotations(int annotationWidth, boolean verbose) {
|
||||
if ((annotations != null) || (cursor != 0)) {
|
||||
throw new RuntimeException("cannot enable annotations");
|
||||
}
|
||||
|
||||
if (annotationWidth < 40) {
|
||||
throw new IllegalArgumentException("annotationWidth < 40");
|
||||
}
|
||||
|
||||
int hexCols = (((annotationWidth - 7) / 15) + 1) & ~1;
|
||||
if (hexCols < 6) {
|
||||
hexCols = 6;
|
||||
} else if (hexCols > 10) {
|
||||
hexCols = 10;
|
||||
}
|
||||
|
||||
this.annotations = new ArrayList<Annotation>(1000);
|
||||
this.annotationWidth = annotationWidth;
|
||||
this.hexCols = hexCols;
|
||||
this.verbose = verbose;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes up annotation processing. This closes off any open
|
||||
* annotations and removes annotations that don't refer to written
|
||||
* data.
|
||||
*/
|
||||
public void finishAnnotating() {
|
||||
// Close off the final annotation, if any.
|
||||
endAnnotation();
|
||||
|
||||
// Remove annotations that refer to unwritten data.
|
||||
if (annotations != null) {
|
||||
int asz = annotations.size();
|
||||
while (asz > 0) {
|
||||
Annotation last = annotations.get(asz - 1);
|
||||
if (last.getStart() > cursor) {
|
||||
annotations.remove(asz - 1);
|
||||
asz--;
|
||||
} else if (last.getEnd() > cursor) {
|
||||
last.setEnd(cursor);
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws the excpetion for when an attempt is made to write past the
|
||||
* end of the instance.
|
||||
*/
|
||||
private static void throwBounds() {
|
||||
throw new IndexOutOfBoundsException("attempt to write past the end");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reallocates the underlying array if necessary. Calls to this method
|
||||
* should be guarded by a test of {@link #stretchy}.
|
||||
*
|
||||
* @param desiredSize >= 0; the desired minimum total size of the array
|
||||
*/
|
||||
private void ensureCapacity(int desiredSize) {
|
||||
if (data.length < desiredSize) {
|
||||
byte[] newData = new byte[desiredSize * 2 + 1000];
|
||||
System.arraycopy(data, 0, newData, 0, cursor);
|
||||
data = newData;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotation on output.
|
||||
*/
|
||||
private static class Annotation {
|
||||
/** >= 0; start of annotated range (inclusive) */
|
||||
private final int start;
|
||||
|
||||
/**
|
||||
* >= 0; end of annotated range (exclusive);
|
||||
* <code>Integer.MAX_VALUE</code> if unclosed
|
||||
*/
|
||||
private int end;
|
||||
|
||||
/** non-null; annotation text */
|
||||
private final String text;
|
||||
|
||||
/**
|
||||
* Constructs an instance.
|
||||
*
|
||||
* @param start >= 0; start of annotated range
|
||||
* @param end >= start; end of annotated range (exclusive) or
|
||||
* <code>Integer.MAX_VALUE</code> if unclosed
|
||||
* @param text non-null; annotation text
|
||||
*/
|
||||
public Annotation(int start, int end, String text) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance. It is initally unclosed.
|
||||
*
|
||||
* @param start >= 0; start of annotated range
|
||||
* @param text non-null; annotation text
|
||||
*/
|
||||
public Annotation(int start, String text) {
|
||||
this(start, Integer.MAX_VALUE, text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the end as given, but only if the instance is unclosed;
|
||||
* otherwise, do nothing.
|
||||
*
|
||||
* @param end >= start; the end
|
||||
*/
|
||||
public void setEndIfUnset(int end) {
|
||||
if (this.end == Integer.MAX_VALUE) {
|
||||
this.end = end;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the end as given.
|
||||
*
|
||||
* @param end >= start; the end
|
||||
*/
|
||||
public void setEnd(int end) {
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the start.
|
||||
*
|
||||
* @return the start
|
||||
*/
|
||||
public int getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the end.
|
||||
*
|
||||
* @return the end
|
||||
*/
|
||||
public int getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the text.
|
||||
*
|
||||
* @return non-null; the text
|
||||
*/
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
143
dexlib/src/main/java/org/jf/dexlib/Util/EncodedValueUtils.java
Normal file
143
dexlib/src/main/java/org/jf/dexlib/Util/EncodedValueUtils.java
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util;
|
||||
|
||||
public class EncodedValueUtils {
|
||||
public static byte getRequiredBytesForSignedIntegralValue(long value) {
|
||||
/*
|
||||
* Figure out how many bits are needed to represent the value,
|
||||
* including a sign bit: The bit count is subtracted from 65
|
||||
* and not 64 to account for the sign bit. The xor operation
|
||||
* has the effect of leaving non-negative values alone and
|
||||
* unary complementing negative values (so that a leading zero
|
||||
* count always returns a useful number for our present
|
||||
* purpose).
|
||||
*/
|
||||
int requiredBits =
|
||||
65 - Long.numberOfLeadingZeros(value ^ (value >> 63));
|
||||
|
||||
// Round up the requiredBits to a number of bytes.
|
||||
return (byte)((requiredBits + 0x07) >> 3);
|
||||
}
|
||||
|
||||
public static long decodeSignedIntegralValue(byte[] bytes) {
|
||||
long value = 0;
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
value |= (((long)(bytes[i] & 0xFF)) << (i * 8));
|
||||
}
|
||||
|
||||
int shift = (8 - bytes.length) * 8;
|
||||
return value << shift >> shift;
|
||||
}
|
||||
|
||||
public static byte[] encodeSignedIntegralValue(long value) {
|
||||
int requiredBytes = getRequiredBytesForSignedIntegralValue(value);
|
||||
|
||||
byte[] bytes = new byte[requiredBytes];
|
||||
|
||||
for (int i = 0; i < requiredBytes; i++) {
|
||||
bytes[i] = (byte) value;
|
||||
value >>= 8;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static byte getRequiredBytesForUnsignedIntegralValue(long value) {
|
||||
// Figure out how many bits are needed to represent the value.
|
||||
int requiredBits = 64 - Long.numberOfLeadingZeros(value);
|
||||
if (requiredBits == 0) {
|
||||
requiredBits = 1;
|
||||
}
|
||||
|
||||
// Round up the requiredBits to a number of bytes.
|
||||
return (byte)((requiredBits + 0x07) >> 3);
|
||||
}
|
||||
|
||||
public static long decodeUnsignedIntegralValue(byte[] bytes) {
|
||||
long value = 0;
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
value |= (((long)(bytes[i] & 0xFF)) << i * 8);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public static byte[] encodeUnsignedIntegralValue(long value) {
|
||||
int requiredBytes = getRequiredBytesForUnsignedIntegralValue(value);
|
||||
|
||||
byte[] bytes = new byte[requiredBytes];
|
||||
|
||||
for (int i = 0; i < requiredBytes; i++) {
|
||||
bytes[i] = (byte) value;
|
||||
value >>= 8;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static int getRequiredBytesForRightZeroExtendedValue(long value) {
|
||||
// Figure out how many bits are needed to represent the value.
|
||||
int requiredBits = 64 - Long.numberOfTrailingZeros(value);
|
||||
if (requiredBits == 0) {
|
||||
requiredBits = 1;
|
||||
}
|
||||
|
||||
// Round up the requiredBits to a number of bytes.
|
||||
return (requiredBits + 0x07) >> 3;
|
||||
}
|
||||
|
||||
public static long decodeRightZeroExtendedValue(byte[] bytes) {
|
||||
long value = 0;
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
value |= (((long)(bytes[i] & 0xFF)) << (i * 8));
|
||||
}
|
||||
return value << (8 - bytes.length) * 8;
|
||||
}
|
||||
|
||||
public static byte[] encodeRightZeroExtendedValue(long value) {
|
||||
int requiredBytes = getRequiredBytesForRightZeroExtendedValue(value);
|
||||
|
||||
// Scootch the first bits to be written down to the low-order bits.
|
||||
value >>= 64 - (requiredBytes * 8);
|
||||
|
||||
byte[] bytes = new byte[requiredBytes];
|
||||
|
||||
for(int i = 0; i < requiredBytes; i++) {
|
||||
bytes[i] = (byte)value;
|
||||
value >>= 8;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
}
|
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Exception which carries around structured context.
|
||||
*/
|
||||
public class ExceptionWithContext
|
||||
extends RuntimeException {
|
||||
/** non-null; human-oriented context of the exception */
|
||||
private StringBuffer context;
|
||||
|
||||
/**
|
||||
* Augments the given exception with the given context, and return the
|
||||
* result. The result is either the given exception if it was an
|
||||
* {@link ExceptionWithContext}, or a newly-constructed exception if it
|
||||
* was not.
|
||||
*
|
||||
* @param ex non-null; the exception to augment
|
||||
* @param str non-null; context to add
|
||||
* @return non-null; an appropriate instance
|
||||
*/
|
||||
public static ExceptionWithContext withContext(Throwable ex, String str) {
|
||||
ExceptionWithContext ewc;
|
||||
|
||||
if (ex instanceof ExceptionWithContext) {
|
||||
ewc = (ExceptionWithContext) ex;
|
||||
} else {
|
||||
ewc = new ExceptionWithContext(ex);
|
||||
}
|
||||
|
||||
ewc.addContext(str);
|
||||
return ewc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance.
|
||||
*
|
||||
* @param message human-oriented message
|
||||
*/
|
||||
public ExceptionWithContext(String message) {
|
||||
this(message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance.
|
||||
*
|
||||
* @param cause null-ok; exception that caused this one
|
||||
*/
|
||||
public ExceptionWithContext(Throwable cause) {
|
||||
this(null, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance.
|
||||
*
|
||||
* @param message human-oriented message
|
||||
* @param cause null-ok; exception that caused this one
|
||||
*/
|
||||
public ExceptionWithContext(String message, Throwable cause) {
|
||||
super((message != null) ? message :
|
||||
(cause != null) ? cause.getMessage() : null,
|
||||
cause);
|
||||
|
||||
if (cause instanceof ExceptionWithContext) {
|
||||
String ctx = ((ExceptionWithContext) cause).context.toString();
|
||||
context = new StringBuffer(ctx.length() + 200);
|
||||
context.append(ctx);
|
||||
} else {
|
||||
context = new StringBuffer(200);
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void printStackTrace(PrintStream out) {
|
||||
super.printStackTrace(out);
|
||||
out.println(context);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void printStackTrace(PrintWriter out) {
|
||||
super.printStackTrace(out);
|
||||
out.println(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a line of context to this instance.
|
||||
*
|
||||
* @param str non-null; new context
|
||||
*/
|
||||
public void addContext(String str) {
|
||||
if (str == null) {
|
||||
throw new NullPointerException("str == null");
|
||||
}
|
||||
|
||||
context.append(str);
|
||||
if (!str.endsWith("\n")) {
|
||||
context.append('\n');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the context.
|
||||
*
|
||||
* @return non-null; the context
|
||||
*/
|
||||
public String getContext() {
|
||||
return context.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the message and context.
|
||||
*
|
||||
* @param out non-null; where to print to
|
||||
*/
|
||||
public void printContext(PrintStream out) {
|
||||
out.println(getMessage());
|
||||
out.print(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the message and context.
|
||||
*
|
||||
* @param out non-null; where to print to
|
||||
*/
|
||||
public void printContext(PrintWriter out) {
|
||||
out.println(getMessage());
|
||||
out.print(context);
|
||||
}
|
||||
}
|
92
dexlib/src/main/java/org/jf/dexlib/Util/FileUtils.java
Normal file
92
dexlib/src/main/java/org/jf/dexlib/Util/FileUtils.java
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jf.dexlib.Util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* File I/O utilities.
|
||||
*/
|
||||
public final class FileUtils {
|
||||
/**
|
||||
* This class is uninstantiable.
|
||||
*/
|
||||
private FileUtils() {
|
||||
// This space intentionally left blank.
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the named file, translating {@link IOException} to a
|
||||
* {@link RuntimeException} of some sort.
|
||||
*
|
||||
* @param fileName non-null; name of the file to read
|
||||
* @return non-null; contents of the file
|
||||
*/
|
||||
public static byte[] readFile(String fileName) {
|
||||
File file = new File(fileName);
|
||||
return readFile(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the given file, translating {@link IOException} to a
|
||||
* {@link RuntimeException} of some sort.
|
||||
*
|
||||
* @param file non-null; the file to read
|
||||
* @return non-null; contents of the file
|
||||
*/
|
||||
public static byte[] readFile(File file) {
|
||||
if (!file.exists()) {
|
||||
throw new RuntimeException(file + ": file not found");
|
||||
}
|
||||
|
||||
if (!file.isFile()) {
|
||||
throw new RuntimeException(file + ": not a file");
|
||||
}
|
||||
|
||||
if (!file.canRead()) {
|
||||
throw new RuntimeException(file + ": file not readable");
|
||||
}
|
||||
|
||||
long longLength = file.length();
|
||||
int length = (int) longLength;
|
||||
if (length != longLength) {
|
||||
throw new RuntimeException(file + ": file too long");
|
||||
}
|
||||
|
||||
byte[] result = new byte[length];
|
||||
|
||||
try {
|
||||
FileInputStream in = new FileInputStream(file);
|
||||
int at = 0;
|
||||
while (length > 0) {
|
||||
int amt = in.read(result, at, length);
|
||||
if (amt == -1) {
|
||||
throw new RuntimeException(file + ": unexpected EOF");
|
||||
}
|
||||
at += amt;
|
||||
length -= amt;
|
||||
}
|
||||
in.close();
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(file + ": trouble reading", ex);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
315
dexlib/src/main/java/org/jf/dexlib/Util/Hex.java
Normal file
315
dexlib/src/main/java/org/jf/dexlib/Util/Hex.java
Normal file
@ -0,0 +1,315 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util;
|
||||
|
||||
/**
|
||||
* Utilities for formatting numbers as hexadecimal.
|
||||
*/
|
||||
public final class Hex {
|
||||
/**
|
||||
* This class is uninstantiable.
|
||||
*/
|
||||
private Hex() {
|
||||
// This space intentionally left blank.
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a <code>long</code> as an 8-byte unsigned hex value.
|
||||
*
|
||||
* @param v value to format
|
||||
* @return non-null; formatted form
|
||||
*/
|
||||
public static String u8(long v) {
|
||||
char[] result = new char[16];
|
||||
for (int i = 0; i < 16; i++) {
|
||||
result[15 - i] = Character.forDigit((int) v & 0x0f, 16);
|
||||
v >>= 4;
|
||||
}
|
||||
|
||||
return new String(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an <code>int</code> as a 4-byte unsigned hex value.
|
||||
*
|
||||
* @param v value to format
|
||||
* @return non-null; formatted form
|
||||
*/
|
||||
public static String u4(int v) {
|
||||
char[] result = new char[8];
|
||||
for (int i = 0; i < 8; i++) {
|
||||
result[7 - i] = Character.forDigit(v & 0x0f, 16);
|
||||
v >>= 4;
|
||||
}
|
||||
|
||||
return new String(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an <code>int</code> as a 3-byte unsigned hex value.
|
||||
*
|
||||
* @param v value to format
|
||||
* @return non-null; formatted form
|
||||
*/
|
||||
public static String u3(int v) {
|
||||
char[] result = new char[6];
|
||||
for (int i = 0; i < 6; i++) {
|
||||
result[5 - i] = Character.forDigit(v & 0x0f, 16);
|
||||
v >>= 4;
|
||||
}
|
||||
|
||||
return new String(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an <code>int</code> as a 2-byte unsigned hex value.
|
||||
*
|
||||
* @param v value to format
|
||||
* @return non-null; formatted form
|
||||
*/
|
||||
public static String u2(int v) {
|
||||
char[] result = new char[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result[3 - i] = Character.forDigit(v & 0x0f, 16);
|
||||
v >>= 4;
|
||||
}
|
||||
|
||||
return new String(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an <code>int</code> as either a 2-byte unsigned hex value
|
||||
* (if the value is small enough) or a 4-byte unsigned hex value (if
|
||||
* not).
|
||||
*
|
||||
* @param v value to format
|
||||
* @return non-null; formatted form
|
||||
*/
|
||||
public static String u2or4(int v) {
|
||||
if (v == (char) v) {
|
||||
return u2(v);
|
||||
} else {
|
||||
return u4(v);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an <code>int</code> as a 1-byte unsigned hex value.
|
||||
*
|
||||
* @param v value to format
|
||||
* @return non-null; formatted form
|
||||
*/
|
||||
public static String u1(int v) {
|
||||
char[] result = new char[2];
|
||||
for (int i = 0; i < 2; i++) {
|
||||
result[1 - i] = Character.forDigit(v & 0x0f, 16);
|
||||
v >>= 4;
|
||||
}
|
||||
|
||||
return new String(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an <code>int</code> as a 4-bit unsigned hex nibble.
|
||||
*
|
||||
* @param v value to format
|
||||
* @return non-null; formatted form
|
||||
*/
|
||||
public static String uNibble(int v) {
|
||||
char[] result = new char[1];
|
||||
|
||||
result[0] = Character.forDigit(v & 0x0f, 16);
|
||||
return new String(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a <code>long</code> as an 8-byte signed hex value.
|
||||
*
|
||||
* @param v value to format
|
||||
* @return non-null; formatted form
|
||||
*/
|
||||
public static String s8(long v) {
|
||||
char[] result = new char[17];
|
||||
|
||||
if (v < 0) {
|
||||
result[0] = '-';
|
||||
v = -v;
|
||||
} else {
|
||||
result[0] = '+';
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
result[16 - i] = Character.forDigit((int) v & 0x0f, 16);
|
||||
v >>= 4;
|
||||
}
|
||||
|
||||
return new String(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an <code>int</code> as a 4-byte signed hex value.
|
||||
*
|
||||
* @param v value to format
|
||||
* @return non-null; formatted form
|
||||
*/
|
||||
public static String s4(int v) {
|
||||
char[] result = new char[9];
|
||||
|
||||
if (v < 0) {
|
||||
result[0] = '-';
|
||||
v = -v;
|
||||
} else {
|
||||
result[0] = '+';
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
result[8 - i] = Character.forDigit(v & 0x0f, 16);
|
||||
v >>= 4;
|
||||
}
|
||||
|
||||
return new String(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an <code>int</code> as a 2-byte signed hex value.
|
||||
*
|
||||
* @param v value to format
|
||||
* @return non-null; formatted form
|
||||
*/
|
||||
public static String s2(int v) {
|
||||
char[] result = new char[5];
|
||||
|
||||
if (v < 0) {
|
||||
result[0] = '-';
|
||||
v = -v;
|
||||
} else {
|
||||
result[0] = '+';
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result[4 - i] = Character.forDigit(v & 0x0f, 16);
|
||||
v >>= 4;
|
||||
}
|
||||
|
||||
return new String(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an <code>int</code> as a 1-byte signed hex value.
|
||||
*
|
||||
* @param v value to format
|
||||
* @return non-null; formatted form
|
||||
*/
|
||||
public static String s1(int v) {
|
||||
char[] result = new char[3];
|
||||
|
||||
if (v < 0) {
|
||||
result[0] = '-';
|
||||
v = -v;
|
||||
} else {
|
||||
result[0] = '+';
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
result[2 - i] = Character.forDigit(v & 0x0f, 16);
|
||||
v >>= 4;
|
||||
}
|
||||
|
||||
return new String(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a hex dump of a portion of a <code>byte[]</code>. The result
|
||||
* is always newline-terminated, unless the passed-in length was zero,
|
||||
* in which case the result is always the empty string (<code>""</code>).
|
||||
*
|
||||
* @param arr non-null; array to format
|
||||
* @param offset >= 0; offset to the part to dump
|
||||
* @param length >= 0; number of bytes to dump
|
||||
* @param outOffset >= 0; first output offset to print
|
||||
* @param bpl >= 0; number of bytes of output per line
|
||||
* @param addressLength {2,4,6,8}; number of characters for each address
|
||||
* header
|
||||
* @return non-null; a string of the dump
|
||||
*/
|
||||
public static String dump(byte[] arr, int offset, int length,
|
||||
int outOffset, int bpl, int addressLength) {
|
||||
int end = offset + length;
|
||||
|
||||
// twos-complement math trick: ((x < 0) || (y < 0)) <=> ((x|y) < 0)
|
||||
if (((offset | length | end) < 0) || (end > arr.length)) {
|
||||
throw new IndexOutOfBoundsException("arr.length " +
|
||||
arr.length + "; " +
|
||||
offset + "..!" + end);
|
||||
}
|
||||
|
||||
if (outOffset < 0) {
|
||||
throw new IllegalArgumentException("outOffset < 0");
|
||||
}
|
||||
|
||||
if (length == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuffer sb = new StringBuffer(length * 4 + 6);
|
||||
boolean bol = true;
|
||||
int col = 0;
|
||||
|
||||
while (length > 0) {
|
||||
if (col == 0) {
|
||||
String astr;
|
||||
switch (addressLength) {
|
||||
case 2: astr = Hex.u1(outOffset); break;
|
||||
case 4: astr = Hex.u2(outOffset); break;
|
||||
case 6: astr = Hex.u3(outOffset); break;
|
||||
default: astr = Hex.u4(outOffset); break;
|
||||
}
|
||||
sb.append(astr);
|
||||
sb.append(": ");
|
||||
} else if ((col & 1) == 0) {
|
||||
sb.append(' ');
|
||||
}
|
||||
sb.append(Hex.u1(arr[offset]));
|
||||
outOffset++;
|
||||
offset++;
|
||||
col++;
|
||||
if (col == bpl) {
|
||||
sb.append('\n');
|
||||
col = 0;
|
||||
}
|
||||
length--;
|
||||
}
|
||||
|
||||
if (col != 0) {
|
||||
sb.append('\n');
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
181
dexlib/src/main/java/org/jf/dexlib/Util/IndentingWriter.java
Normal file
181
dexlib/src/main/java/org/jf/dexlib/Util/IndentingWriter.java
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util;
|
||||
|
||||
import java.io.FilterWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
/**
|
||||
* Writer that wraps another writer and passes width-limited and
|
||||
* optionally-prefixed output to its subordinate. When lines are
|
||||
* wrapped they are automatically indented based on the start of the
|
||||
* line.
|
||||
*/
|
||||
public final class IndentingWriter extends FilterWriter {
|
||||
/** null-ok; optional prefix for every line */
|
||||
private final String prefix;
|
||||
|
||||
/** > 0; the maximum output width */
|
||||
private final int width;
|
||||
|
||||
/** > 0; the maximum indent */
|
||||
private final int maxIndent;
|
||||
|
||||
/** >= 0; current output column (zero-based) */
|
||||
private int column;
|
||||
|
||||
/** whether indent spaces are currently being collected */
|
||||
private boolean collectingIndent;
|
||||
|
||||
/** >= 0; current indent amount */
|
||||
private int indent;
|
||||
|
||||
/**
|
||||
* Constructs an instance.
|
||||
*
|
||||
* @param out non-null; writer to send final output to
|
||||
* @param width >= 0; the maximum output width (not including
|
||||
* <code>prefix</code>), or <code>0</code> for no maximum
|
||||
* @param prefix non-null; the prefix for each line
|
||||
*/
|
||||
public IndentingWriter(Writer out, int width, String prefix) {
|
||||
super(out);
|
||||
|
||||
if (out == null) {
|
||||
throw new NullPointerException("out == null");
|
||||
}
|
||||
|
||||
if (width < 0) {
|
||||
throw new IllegalArgumentException("width < 0");
|
||||
}
|
||||
|
||||
if (prefix == null) {
|
||||
throw new NullPointerException("prefix == null");
|
||||
}
|
||||
|
||||
this.width = (width != 0) ? width : Integer.MAX_VALUE;
|
||||
this.maxIndent = width >> 1;
|
||||
this.prefix = (prefix.length() == 0) ? null : prefix;
|
||||
|
||||
bol();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a no-prefix instance.
|
||||
*
|
||||
* @param out non-null; writer to send final output to
|
||||
* @param width >= 0; the maximum output width (not including
|
||||
* <code>prefix</code>), or <code>0</code> for no maximum
|
||||
*/
|
||||
public IndentingWriter(Writer out, int width) {
|
||||
this(out, width, "");
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void write(int c) throws IOException {
|
||||
synchronized (lock) {
|
||||
if (collectingIndent) {
|
||||
if (c == ' ') {
|
||||
indent++;
|
||||
if (indent >= maxIndent) {
|
||||
indent = maxIndent;
|
||||
collectingIndent = false;
|
||||
}
|
||||
} else {
|
||||
collectingIndent = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((column == width) && (c != '\n')) {
|
||||
out.write('\n');
|
||||
column = 0;
|
||||
/*
|
||||
* Note: No else, so this should fall through to the next
|
||||
* if statement.
|
||||
*/
|
||||
}
|
||||
|
||||
if (column == 0) {
|
||||
if (prefix != null) {
|
||||
out.write(prefix);
|
||||
}
|
||||
|
||||
if (!collectingIndent) {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
out.write(' ');
|
||||
}
|
||||
column = indent;
|
||||
}
|
||||
}
|
||||
|
||||
out.write(c);
|
||||
|
||||
if (c == '\n') {
|
||||
bol();
|
||||
} else {
|
||||
column++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void write(char[] cbuf, int off, int len) throws IOException {
|
||||
synchronized (lock) {
|
||||
while (len > 0) {
|
||||
write(cbuf[off]);
|
||||
off++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void write(String str, int off, int len) throws IOException {
|
||||
synchronized (lock) {
|
||||
while (len > 0) {
|
||||
write(str.charAt(off));
|
||||
off++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that output is at the beginning of a line.
|
||||
*/
|
||||
private void bol() {
|
||||
column = 0;
|
||||
collectingIndent = (maxIndent != 0);
|
||||
indent = 0;
|
||||
}
|
||||
}
|
156
dexlib/src/main/java/org/jf/dexlib/Util/Input.java
Normal file
156
dexlib/src/main/java/org/jf/dexlib/Util/Input.java
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util;
|
||||
|
||||
/**
|
||||
* Interface for a source for binary input. This is similar to
|
||||
* <code>java.util.DataInput</code>, but no <code>IOExceptions</code>
|
||||
* are declared, and multibyte input is defined to be little-endian.
|
||||
*/
|
||||
public interface Input {
|
||||
/**
|
||||
* Gets the current cursor position. This is the same as the number of
|
||||
* bytes read from this instance.
|
||||
*
|
||||
* @return >= 0; the cursor position
|
||||
*/
|
||||
public int getCursor();
|
||||
|
||||
/**
|
||||
* Sets the current cursor position.
|
||||
*
|
||||
* @return >= 0; the cursor position
|
||||
*/
|
||||
public void setCursor(int cursor);
|
||||
|
||||
/**
|
||||
* Asserts that the cursor is the given value.
|
||||
*
|
||||
* @param expectedCursor the expected cursor value
|
||||
* @throws RuntimeException thrown if <code>getCursor() !=
|
||||
* expectedCursor</code>
|
||||
*/
|
||||
public void assertCursor(int expectedCursor);
|
||||
|
||||
/**
|
||||
* Reads a <code>byte</code> from this instance.
|
||||
*
|
||||
* @return the byte value that was read
|
||||
*/
|
||||
public byte readByte();
|
||||
|
||||
/**
|
||||
* Reads a <code>short</code> from this instance.
|
||||
*
|
||||
* @return the short value that was read, as an int
|
||||
*/
|
||||
public int readShort();
|
||||
|
||||
/**
|
||||
* Reads an <code>int</code> from this instance.
|
||||
*
|
||||
* @return the unsigned int value that was read
|
||||
*/
|
||||
public int readInt();
|
||||
|
||||
/**
|
||||
* Reads a <code>long</code> from this instance.
|
||||
*
|
||||
* @return the long value that was read
|
||||
*/
|
||||
public long readLong();
|
||||
|
||||
|
||||
/**
|
||||
* Reads a DWARFv3-style signed LEB128 integer. For details,
|
||||
* see the "Dalvik Executable Format" document or DWARF v3 section
|
||||
* 7.6.
|
||||
*
|
||||
* @return the integer value that was read
|
||||
*/
|
||||
public int readSignedLeb128();
|
||||
|
||||
/**
|
||||
* Reads a DWARFv3-style unsigned LEB128 integer. For details,
|
||||
* see the "Dalvik Executable Format" document or DWARF v3 section
|
||||
* 7.6.
|
||||
*
|
||||
* @return the integer value that was read
|
||||
*/
|
||||
public int readUnsignedLeb128();
|
||||
|
||||
/**
|
||||
* reads a <code>byte[]</code> from this instance.
|
||||
*
|
||||
* @param bytes non-null; the buffer to read the data into
|
||||
* @param offset >= 0; offset into <code>bytes</code> for the first
|
||||
* byte to write
|
||||
* @param length >= 0; number of bytes to read
|
||||
*/
|
||||
public void read(byte[] bytes, int offset, int length);
|
||||
|
||||
/**
|
||||
* reads a <code>byte[]</code> from this instance. This is just
|
||||
* a convenient shorthand for <code>read(bytes, 0, bytes.length)</code>.
|
||||
*
|
||||
* @param bytes non-null; the buffer to read the data into
|
||||
*/
|
||||
public void read(byte[] bytes);
|
||||
|
||||
|
||||
/**
|
||||
* reads a <code>byte[]</code> from this instance
|
||||
*
|
||||
* @param length >= 0; number of bytes to read
|
||||
* @return a byte array containing <code>length</code> bytes
|
||||
*/
|
||||
public byte[] readBytes(int length);
|
||||
|
||||
/**
|
||||
* reads a <code>byte[]</code> from this instance, from the current cursor up to but not including
|
||||
* the next null (0) byte. The terminating null byte is read and discarded, so that after the read,
|
||||
* the cursor is positioned at the byte immediately after the terminating null
|
||||
*/
|
||||
public byte[] readNullTerminatedBytes();
|
||||
|
||||
/**
|
||||
* Skips the given number of bytes.
|
||||
*
|
||||
* @param count >= 0; the number of bytes to skip
|
||||
*/
|
||||
public void skipBytes(int count);
|
||||
|
||||
/**
|
||||
* Skip extra bytes if necessary to force alignment of the output
|
||||
* cursor as given.
|
||||
*
|
||||
* @param alignment > 0; the alignment; must be a power of two
|
||||
*/
|
||||
public void alignTo(int alignment);
|
||||
}
|
78
dexlib/src/main/java/org/jf/dexlib/Util/Leb128Utils.java
Normal file
78
dexlib/src/main/java/org/jf/dexlib/Util/Leb128Utils.java
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jf.dexlib.Util;
|
||||
|
||||
/**
|
||||
* LEB128 (little-endian base 128) utilities.
|
||||
*/
|
||||
public final class Leb128Utils {
|
||||
/**
|
||||
* This class is uninstantiable.
|
||||
*/
|
||||
private Leb128Utils() {
|
||||
// This space intentionally left blank.
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of bytes in the unsigned LEB128 encoding of the
|
||||
* given value.
|
||||
*
|
||||
* @param value the value in question
|
||||
* @return its write size, in bytes
|
||||
*/
|
||||
public static int unsignedLeb128Size(int value) {
|
||||
// TODO: This could be much cleverer.
|
||||
|
||||
int remaining = value >> 7;
|
||||
int count = 0;
|
||||
|
||||
while (remaining != 0) {
|
||||
value = remaining;
|
||||
remaining >>= 7;
|
||||
count++;
|
||||
}
|
||||
|
||||
return count + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of bytes in the signed LEB128 encoding of the
|
||||
* given value.
|
||||
*
|
||||
* @param value the value in question
|
||||
* @return its write size, in bytes
|
||||
*/
|
||||
public static int signedLeb128Size(int value) {
|
||||
// TODO: This could be much cleverer.
|
||||
|
||||
int remaining = value >> 7;
|
||||
int count = 0;
|
||||
boolean hasMore = true;
|
||||
int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1;
|
||||
|
||||
while (hasMore) {
|
||||
hasMore = (remaining != end)
|
||||
|| ((remaining & 1) != ((value >> 6) & 1));
|
||||
|
||||
value = remaining;
|
||||
remaining >>= 7;
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
200
dexlib/src/main/java/org/jf/dexlib/Util/NumberUtils.java
Normal file
200
dexlib/src/main/java/org/jf/dexlib/Util/NumberUtils.java
Normal file
@ -0,0 +1,200 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util;
|
||||
|
||||
public class NumberUtils {
|
||||
|
||||
/**
|
||||
* Decodes the high signed 4-bit nibble from the given byte
|
||||
* @param b the byte to decode
|
||||
* @return the decoded signed nibble
|
||||
*/
|
||||
public static byte decodeHighSignedNibble(byte b) {
|
||||
return (byte)(b >> 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the low signed 4-bit nibble from the given byte
|
||||
* @param b the byte to decode
|
||||
* @return the decoded signed nibble
|
||||
*/
|
||||
public static byte decodeLowSignedNibble(byte b) {
|
||||
return (byte)(((byte)(b << 4)) >> 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the high unsigned 4-bit nibble from the given byte
|
||||
* @param b the byte to decode
|
||||
* @return the decoded unsigned nibble
|
||||
*/
|
||||
public static byte decodeHighUnsignedNibble(byte b) {
|
||||
return (byte)((b & 0xFF) >>> 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the low unsigned 4-bit nibble from the given byte
|
||||
* @param b the byte to decode
|
||||
* @return the decoded unsigned nibble
|
||||
*/
|
||||
public static byte decodeLowUnsignedNibble(byte b) {
|
||||
return (byte)(b & 0x0F);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes an unsigned byte from a signed byte
|
||||
* @param b the signed byte to decode
|
||||
* @return the decoded unsigned byte as a short
|
||||
*/
|
||||
public static short decodeUnsignedByte(byte b) {
|
||||
return (short)(b & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a signed short value from 2 individual bytes
|
||||
* The parameters are in order from least significant byte to most significant byte
|
||||
* @param lsb the least significant byte
|
||||
* @param msb the most significant byte
|
||||
* @return the decoded signed short value
|
||||
*/
|
||||
public static short decodeShort(byte lsb, byte msb) {
|
||||
return (short)
|
||||
( (lsb & 0xFF) |
|
||||
(msb << 8)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a signed short value in little endian format from the given byte array at the given index.
|
||||
* @param bytes the byte array
|
||||
* @param index the index of the first byte of the signed short value to decode
|
||||
* @return the decoded signed short value
|
||||
*/
|
||||
public static short decodeShort(byte[] bytes, int index) {
|
||||
return (short)
|
||||
( (bytes[index++] & 0xFF) |
|
||||
(bytes[index] << 8)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes an unsigned short value from 2 individual bytes
|
||||
* The parameters are in order from least significant byte to most significant byte
|
||||
* @param lsb the least significant byte
|
||||
* @param msb the most significant byte
|
||||
* @return the decoded unsigned short value as an int
|
||||
*/
|
||||
public static int decodeUnsignedShort(byte lsb, byte msb) {
|
||||
return ( (lsb & 0xFF) |
|
||||
((msb & 0xFF) << 8)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes an unsigned short value in little endian format from the given byte array at the given index.
|
||||
* @param bytes the byte array
|
||||
* @param index the index of the first byte of the unsigned short value to decode
|
||||
* @return the decoded unsigned short value as an int
|
||||
*/
|
||||
public static int decodeUnsignedShort(byte[] bytes, int index) {
|
||||
return ( (bytes[index++] & 0xFF) |
|
||||
((bytes[index] & 0xFF) << 8)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a signed integer value from 4 individual bytes
|
||||
* The parameters are in order from least significant byte to most significant byte
|
||||
* @param lsb the least significant byte
|
||||
* @param mlsb the middle least significant byte
|
||||
* @param mmsb the middle most significant byte
|
||||
* @param msb the most significant byte
|
||||
* @return the decoded signed integer value
|
||||
*/
|
||||
public static int decodeInt(byte lsb, byte mlsb, byte mmsb, byte msb) {
|
||||
return (lsb & 0xFF) |
|
||||
((mlsb & 0xFF) << 8) |
|
||||
((mmsb & 0xFF) << 16) |
|
||||
(msb << 24);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a signed integer value in little endian format from the given byte array at the given index.
|
||||
* @param bytes the byte array
|
||||
* @param index the index of the first byte of the signed integer value to decode
|
||||
* @return the decoded signed integer value
|
||||
*/
|
||||
public static int decodeInt(byte[] bytes, int index) {
|
||||
return (bytes[index++] & 0xFF) |
|
||||
((bytes[index++] & 0xFF) << 8) |
|
||||
((bytes[index++] & 0xFF) << 16) |
|
||||
(bytes[index] << 24);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a signed long value from 8 individual bytes
|
||||
* The parameters are in order from least significant byte to most significant byte
|
||||
* @param llsb the lower least significant byte
|
||||
* @param lmlsb the lower middle least significant byte
|
||||
* @param lmmsb the lower middle most significant byte
|
||||
* @param lgsb the lower greater significant byte
|
||||
* @param glsb the greater least significant byte
|
||||
* @param gmlsb the greater middle least significant byte
|
||||
* @param gmmsb the greater middle most significant byte
|
||||
* @param gmsb the greater most significant byte
|
||||
* @return the decoded signed long value
|
||||
*/
|
||||
public static long decodeLong(byte llsb, byte lmlsb, byte lmmsb, byte lgsb, byte glsb, byte gmlsb, byte gmmsb,
|
||||
byte gmsb) {
|
||||
return (llsb & 0xFFL) |
|
||||
((lmlsb & 0xFFL) << 8) |
|
||||
((lmmsb & 0xFFL) << 16) |
|
||||
((lgsb & 0xFFL) << 24) |
|
||||
((glsb & 0xFFL) << 32) |
|
||||
((gmlsb & 0xFFL) << 40) |
|
||||
((gmmsb & 0xFFL) << 48) |
|
||||
(((long)gmsb) << 56);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a signed long value in little endian format from the given byte array at the given index.
|
||||
* @param bytes the byte array
|
||||
* @param index the index of the first byte of the signed long value to decode
|
||||
* @return the decoded signed long value
|
||||
*/
|
||||
public static long decodeLong(byte[] bytes, int index) {
|
||||
return (bytes[index++] & 0xFFL) |
|
||||
((bytes[index++] & 0xFFL) << 8) |
|
||||
((bytes[index++] & 0xFFL) << 16) |
|
||||
((bytes[index++] & 0xFFL) << 24) |
|
||||
((bytes[index++] & 0xFFL) << 32) |
|
||||
((bytes[index++] & 0xFFL) << 40) |
|
||||
((bytes[index++] & 0xFFL) << 48) |
|
||||
(((long)bytes[index]) << 56);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user