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:
JesusFreke@JesusFreke.com 2009-08-05 03:23:36 +00:00
parent 02017677b7
commit 83b80f81d3
104 changed files with 15999 additions and 0 deletions

View 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);
}
}

View 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);
}
}

View 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);
}
}

View 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);
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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);
}
}
}
}

View File

@ -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);
}
}
}

View 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;
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View 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.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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View 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.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);
}
}
}

View 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.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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View 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;
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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View 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.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);
}
}
}

View File

@ -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);
}
}
}

View 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;
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);
}
}
}

View 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;
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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View 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);
}
}

View 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);
}
}

View File

@ -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);
}
}

View File

@ -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");
}
}
}
}

View File

@ -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);
}
});
}
}

View 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;
}
}

View 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;
}
}

View 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);
}
}
}
}

View File

@ -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;
}
}
}

View 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;
}
}

View 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;
}
}

View 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);
}
}

View 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);
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View 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.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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View 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.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;
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View 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);
}
}

View 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;
}
}

View 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);
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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";
}
}

View 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);
}
}

View 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);
}
}

View 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);
}
}

View 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];
}
}

View 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);
}
}

View 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());
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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 &gt;= 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 &gt;= 1; the maximum width
*/
public int getAnnotationWidth();
public void setIndentAmount(int indentAmount);
public void indent();
public void deindent();
}

View 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;
}
}
}

View 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>&gt;= 0</code>; start index of the slice (inclusive) */
private final int start;
/** <code>&gt;= 0, &lt;= 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>&gt;= 0</code>; start index of the slice (inclusive)
* @param end <code>&gt;= start, &lt;= 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 &gt;= 0; the size
*/
public int size() {
return size;
}
/**
* Returns a slice (that is, a sub-array) of this instance.
*
* @param start <code>&gt;= 0</code>; start index of the slice (inclusive)
* @param end <code>&gt;= start, &lt;= 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>&gt;= 0, &lt; 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>&gt;= 0, &lt; (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>&gt;= 0, &lt; (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>&gt;= 0, &lt; (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>&gt;= 0, &lt; 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>&gt;= 0, &lt; (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;
}
}

View File

@ -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;
/** &gt;= 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;
/** &gt;= 40 (if used); the desired maximum annotation width */
private int annotationWidth;
/**
* &gt;= 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 &gt;= 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 &gt;= 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 {
/** &gt;= 0; start of annotated range (inclusive) */
private final int start;
/**
* &gt;= 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 &gt;= 0; start of annotated range
* @param end &gt;= 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 &gt;= 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 &gt;= start; the end
*/
public void setEndIfUnset(int end) {
if (this.end == Integer.MAX_VALUE) {
this.end = end;
}
}
/**
* Sets the end as given.
*
* @param end &gt;= 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;
}
}
}

View 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;
/** &gt;= 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");
}
}

View 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;
/** &gt;= 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;
/** &gt;= 40 (if used); the desired maximum annotation width */
private int annotationWidth;
/**
* &gt;= 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 &gt;= 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 &gt;= 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 {
/** &gt;= 0; start of annotated range (inclusive) */
private final int start;
/**
* &gt;= 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 &gt;= 0; start of annotated range
* @param end &gt;= 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 &gt;= 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 &gt;= start; the end
*/
public void setEndIfUnset(int end) {
if (this.end == Integer.MAX_VALUE) {
this.end = end;
}
}
/**
* Sets the end as given.
*
* @param end &gt;= 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;
}
}
}

View 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;
}
}

View File

@ -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);
}
}

View 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;
}
}

View 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 &gt;= 0; offset to the part to dump
* @param length &gt;= 0; number of bytes to dump
* @param outOffset &gt;= 0; first output offset to print
* @param bpl &gt;= 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();
}
}

View 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;
/** &gt; 0; the maximum output width */
private final int width;
/** &gt; 0; the maximum indent */
private final int maxIndent;
/** &gt;= 0; current output column (zero-based) */
private int column;
/** whether indent spaces are currently being collected */
private boolean collectingIndent;
/** &gt;= 0; current indent amount */
private int indent;
/**
* Constructs an instance.
*
* @param out non-null; writer to send final output to
* @param width &gt;= 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 &gt;= 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;
}
}

View 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 &gt;= 0; the cursor position
*/
public int getCursor();
/**
* Sets the current cursor position.
*
* @return &gt;= 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 &gt;= 0; offset into <code>bytes</code> for the first
* byte to write
* @param length &gt;= 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 &gt;= 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 &gt;= 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 &gt; 0; the alignment; must be a power of two
*/
public void alignTo(int alignment);
}

View 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;
}
}

View 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