com.tencent.tinker.android.dx.util.IndexMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aosp-dexutils Show documentation
Show all versions of aosp-dexutils Show documentation
Tinker is a hot-fix solution library for Android, it supports dex, library and resources update without reinstalling apk.
/*
* 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 com.tencent.tinker.android.dx.util;
import com.tencent.tinker.android.dex.Annotation;
import com.tencent.tinker.android.dex.AnnotationSet;
import com.tencent.tinker.android.dex.AnnotationSetRefList;
import com.tencent.tinker.android.dex.AnnotationsDirectory;
import com.tencent.tinker.android.dex.ClassData;
import com.tencent.tinker.android.dex.ClassDef;
import com.tencent.tinker.android.dex.Code;
import com.tencent.tinker.android.dex.DebugInfoItem;
import com.tencent.tinker.android.dex.DexException;
import com.tencent.tinker.android.dex.EncodedValue;
import com.tencent.tinker.android.dex.EncodedValueCodec;
import com.tencent.tinker.android.dex.EncodedValueReader;
import com.tencent.tinker.android.dex.FieldId;
import com.tencent.tinker.android.dex.Leb128;
import com.tencent.tinker.android.dex.MethodId;
import com.tencent.tinker.android.dex.ProtoId;
import com.tencent.tinker.android.dex.TypeList;
import com.tencent.tinker.android.dex.util.ByteInput;
import com.tencent.tinker.android.dex.util.ByteOutput;
import com.tencent.tinker.android.utils.SparseIntArray;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.BitSet;
/**
* Created by tangyinsheng on 2016/6/29.
*/
public class IndexMap {
private final SparseIntArray stringIdsMap = new SparseIntArray();
private final SparseIntArray typeIdsMap = new SparseIntArray();
private final SparseIntArray protoIdsMap = new SparseIntArray();
private final SparseIntArray fieldIdsMap = new SparseIntArray();
private final SparseIntArray methodIdsMap = new SparseIntArray();
private final SparseIntArray typeListOffsetsMap = new SparseIntArray();
private final SparseIntArray annotationOffsetsMap = new SparseIntArray();
private final SparseIntArray annotationSetOffsetsMap = new SparseIntArray();
private final SparseIntArray annotationSetRefListOffsetsMap = new SparseIntArray();
private final SparseIntArray annotationsDirectoryOffsetsMap = new SparseIntArray();
private final SparseIntArray staticValuesOffsetsMap = new SparseIntArray();
private final SparseIntArray classDataOffsetsMap = new SparseIntArray();
private final SparseIntArray debugInfoItemOffsetsMap = new SparseIntArray();
private final SparseIntArray codeOffsetsMap = new SparseIntArray();
private final BitSet deletedStringIds = new BitSet();
private final BitSet deletedTypeIds = new BitSet();
private final BitSet deletedProtoIds = new BitSet();
private final BitSet deletedFieldIds = new BitSet();
private final BitSet deletedMethodIds = new BitSet();
private final BitSet deletedTypeListOffsets = new BitSet();
private final BitSet deletedAnnotationOffsets = new BitSet();
private final BitSet deletedAnnotationSetOffsets = new BitSet();
private final BitSet deletedAnnotationSetRefListOffsets = new BitSet();
private final BitSet deletedAnnotationsDirectoryOffsets = new BitSet();
private final BitSet deletedStaticValuesOffsets = new BitSet();
private final BitSet deletedClassDataOffsets = new BitSet();
private final BitSet deletedDebugInfoItemOffsets = new BitSet();
private final BitSet deletedCodeOffsets = new BitSet();
public void mapStringIds(int oldIndex, int newIndex) {
stringIdsMap.put(oldIndex, newIndex);
}
public void markStringIdDeleted(int index) {
if (index < 0) return;
deletedStringIds.set(index);
}
public void mapTypeIds(int oldIndex, int newIndex) {
typeIdsMap.put(oldIndex, newIndex);
}
public void markTypeIdDeleted(int index) {
if (index < 0) return;
deletedTypeIds.set(index);
}
public void mapProtoIds(int oldIndex, int newIndex) {
protoIdsMap.put(oldIndex, newIndex);
}
public void markProtoIdDeleted(int index) {
if (index < 0) return;
deletedProtoIds.set(index);
}
public void mapFieldIds(int oldIndex, int newIndex) {
fieldIdsMap.put(oldIndex, newIndex);
}
public void markFieldIdDeleted(int index) {
if (index < 0) return;
deletedFieldIds.set(index);
}
public void mapMethodIds(int oldIndex, int newIndex) {
methodIdsMap.put(oldIndex, newIndex);
}
public void markMethodIdDeleted(int index) {
if (index < 0) return;
deletedMethodIds.set(index);
}
public void mapTypeListOffset(int oldOffset, int newOffset) {
typeListOffsetsMap.put(oldOffset, newOffset);
}
public void markTypeListDeleted(int offset) {
if (offset < 0) return;
deletedTypeListOffsets.set(offset);
}
public void mapAnnotationOffset(int oldOffset, int newOffset) {
annotationOffsetsMap.put(oldOffset, newOffset);
}
public void markAnnotationDeleted(int offset) {
if (offset < 0) return;
deletedAnnotationOffsets.set(offset);
}
public void mapAnnotationSetOffset(int oldOffset, int newOffset) {
annotationSetOffsetsMap.put(oldOffset, newOffset);
}
public void markAnnotationSetDeleted(int offset) {
if (offset < 0) return;
deletedAnnotationSetOffsets.set(offset);
}
public void mapAnnotationSetRefListOffset(int oldOffset, int newOffset) {
annotationSetRefListOffsetsMap.put(oldOffset, newOffset);
}
public void markAnnotationSetRefListDeleted(int offset) {
if (offset < 0) return;
deletedAnnotationSetRefListOffsets.set(offset);
}
public void mapAnnotationsDirectoryOffset(int oldOffset, int newOffset) {
annotationsDirectoryOffsetsMap.put(oldOffset, newOffset);
}
public void markAnnotationsDirectoryDeleted(int offset) {
if (offset < 0) return;
deletedAnnotationsDirectoryOffsets.set(offset);
}
public void mapStaticValuesOffset(int oldOffset, int newOffset) {
staticValuesOffsetsMap.put(oldOffset, newOffset);
}
public void markStaticValuesDeleted(int offset) {
if (offset < 0) return;
deletedStaticValuesOffsets.set(offset);
}
public void mapClassDataOffset(int oldOffset, int newOffset) {
classDataOffsetsMap.put(oldOffset, newOffset);
}
public void markClassDataDeleted(int offset) {
if (offset < 0) return;
deletedClassDataOffsets.set(offset);
}
public void mapDebugInfoItemOffset(int oldOffset, int newOffset) {
debugInfoItemOffsetsMap.put(oldOffset, newOffset);
}
public void markDebugInfoItemDeleted(int offset) {
if (offset < 0) return;
deletedDebugInfoItemOffsets.set(offset);
}
public void mapCodeOffset(int oldOffset, int newOffset) {
codeOffsetsMap.put(oldOffset, newOffset);
}
public void markCodeDeleted(int offset) {
if (offset < 0) return;
deletedCodeOffsets.set(offset);
}
public int adjustStringIndex(int stringIndex) {
int index = stringIdsMap.indexOfKey(stringIndex);
if (index < 0) {
return (stringIndex >= 0 && deletedStringIds.get(stringIndex) ? -1 : stringIndex);
} else {
return stringIdsMap.valueAt(index);
}
}
public int adjustTypeIdIndex(int typeIdIndex) {
int index = typeIdsMap.indexOfKey(typeIdIndex);
if (index < 0) {
return (typeIdIndex >= 0 && deletedTypeIds.get(typeIdIndex) ? -1 : typeIdIndex);
} else {
return typeIdsMap.valueAt(index);
}
}
public int adjustProtoIdIndex(int protoIndex) {
int index = protoIdsMap.indexOfKey(protoIndex);
if (index < 0) {
return (protoIndex >= 0 && deletedProtoIds.get(protoIndex) ? -1 : protoIndex);
} else {
return protoIdsMap.valueAt(index);
}
}
public int adjustFieldIdIndex(int fieldIndex) {
int index = fieldIdsMap.indexOfKey(fieldIndex);
if (index < 0) {
return (fieldIndex >= 0 && deletedFieldIds.get(fieldIndex) ? -1 : fieldIndex);
} else {
return fieldIdsMap.valueAt(index);
}
}
public int adjustMethodIdIndex(int methodIndex) {
int index = methodIdsMap.indexOfKey(methodIndex);
if (index < 0) {
return (methodIndex >= 0 && deletedMethodIds.get(methodIndex) ? -1 : methodIndex);
} else {
return methodIdsMap.valueAt(index);
}
}
public int adjustTypeListOffset(int typeListOffset) {
int index = typeListOffsetsMap.indexOfKey(typeListOffset);
if (index < 0) {
return (typeListOffset >= 0 && deletedTypeListOffsets.get(typeListOffset) ? -1 : typeListOffset);
} else {
return typeListOffsetsMap.valueAt(index);
}
}
public int adjustAnnotationOffset(int annotationOffset) {
int index = annotationOffsetsMap.indexOfKey(annotationOffset);
if (index < 0) {
return (annotationOffset >= 0 && deletedAnnotationOffsets.get(annotationOffset) ? -1 : annotationOffset);
} else {
return annotationOffsetsMap.valueAt(index);
}
}
public int adjustAnnotationSetOffset(int annotationSetOffset) {
int index = annotationSetOffsetsMap.indexOfKey(annotationSetOffset);
if (index < 0) {
return (annotationSetOffset >= 0 && deletedAnnotationSetOffsets.get(annotationSetOffset) ? -1 : annotationSetOffset);
} else {
return annotationSetOffsetsMap.valueAt(index);
}
}
public int adjustAnnotationSetRefListOffset(int annotationSetRefListOffset) {
int index = annotationSetRefListOffsetsMap.indexOfKey(annotationSetRefListOffset);
if (index < 0) {
return (annotationSetRefListOffset >= 0 && deletedAnnotationSetRefListOffsets.get(annotationSetRefListOffset) ? -1 : annotationSetRefListOffset);
} else {
return annotationSetRefListOffsetsMap.valueAt(index);
}
}
public int adjustAnnotationsDirectoryOffset(int annotationsDirectoryOffset) {
int index = annotationsDirectoryOffsetsMap.indexOfKey(annotationsDirectoryOffset);
if (index < 0) {
return (annotationsDirectoryOffset >= 0 && deletedAnnotationsDirectoryOffsets.get(annotationsDirectoryOffset) ? -1 : annotationsDirectoryOffset);
} else {
return annotationsDirectoryOffsetsMap.valueAt(index);
}
}
public int adjustStaticValuesOffset(int staticValuesOffset) {
int index = staticValuesOffsetsMap.indexOfKey(staticValuesOffset);
if (index < 0) {
return (staticValuesOffset >= 0 && deletedStaticValuesOffsets.get(staticValuesOffset) ? -1 : staticValuesOffset);
} else {
return staticValuesOffsetsMap.valueAt(index);
}
}
public int adjustClassDataOffset(int classDataOffset) {
int index = classDataOffsetsMap.indexOfKey(classDataOffset);
if (index < 0) {
return (classDataOffset >= 0 && deletedClassDataOffsets.get(classDataOffset) ? -1 : classDataOffset);
} else {
return classDataOffsetsMap.valueAt(index);
}
}
public int adjustDebugInfoItemOffset(int debugInfoItemOffset) {
int index = debugInfoItemOffsetsMap.indexOfKey(debugInfoItemOffset);
if (index < 0) {
return (debugInfoItemOffset >= 0 && deletedDebugInfoItemOffsets.get(debugInfoItemOffset) ? -1 : debugInfoItemOffset);
} else {
return debugInfoItemOffsetsMap.valueAt(index);
}
}
public int adjustCodeOffset(int codeOffset) {
int index = codeOffsetsMap.indexOfKey(codeOffset);
if (index < 0) {
return (codeOffset >= 0 && deletedCodeOffsets.get(codeOffset) ? -1 : codeOffset);
} else {
return codeOffsetsMap.valueAt(index);
}
}
public TypeList adjust(TypeList typeList) {
if (typeList == TypeList.EMPTY) {
return typeList;
}
short[] types = new short[typeList.types.length];
for (int i = 0; i < types.length; ++i) {
types[i] = (short) adjustTypeIdIndex(typeList.types[i]);
}
return new TypeList(typeList.off, types);
}
public MethodId adjust(MethodId methodId) {
int adjustedDeclaringClassIndex = adjustTypeIdIndex(methodId.declaringClassIndex);
int adjustedProtoIndex = adjustProtoIdIndex(methodId.protoIndex);
int adjustedNameIndex = adjustStringIndex(methodId.nameIndex);
return new MethodId(
methodId.off, adjustedDeclaringClassIndex, adjustedProtoIndex, adjustedNameIndex
);
}
public FieldId adjust(FieldId fieldId) {
int adjustedDeclaringClassIndex = adjustTypeIdIndex(fieldId.declaringClassIndex);
int adjustedTypeIndex = adjustTypeIdIndex(fieldId.typeIndex);
int adjustedNameIndex = adjustStringIndex(fieldId.nameIndex);
return new FieldId(
fieldId.off, adjustedDeclaringClassIndex, adjustedTypeIndex, adjustedNameIndex
);
}
public ProtoId adjust(ProtoId protoId) {
int adjustedShortyIndex = adjustStringIndex(protoId.shortyIndex);
int adjustedReturnTypeIndex = adjustTypeIdIndex(protoId.returnTypeIndex);
int adjustedParametersOffset = adjustTypeListOffset(protoId.parametersOffset);
return new ProtoId(
protoId.off, adjustedShortyIndex, adjustedReturnTypeIndex, adjustedParametersOffset
);
}
public ClassDef adjust(ClassDef classDef) {
int adjustedTypeIndex = adjustTypeIdIndex(classDef.typeIndex);
int adjustedSupertypeIndex = adjustTypeIdIndex(classDef.supertypeIndex);
int adjustedInterfacesOffset = adjustTypeListOffset(classDef.interfacesOffset);
int adjustedSourceFileIndex = adjustStringIndex(classDef.sourceFileIndex);
int adjustedAnnotationsOffset = adjustAnnotationsDirectoryOffset(classDef.annotationsOffset);
int adjustedClassDataOffset = adjustClassDataOffset(classDef.classDataOffset);
int adjustedStaticValuesOffset = adjustStaticValuesOffset(classDef.staticValuesOffset);
return new ClassDef(
classDef.off, adjustedTypeIndex, classDef.accessFlags, adjustedSupertypeIndex,
adjustedInterfacesOffset, adjustedSourceFileIndex, adjustedAnnotationsOffset,
adjustedClassDataOffset, adjustedStaticValuesOffset
);
}
public ClassData adjust(ClassData classData) {
ClassData.Field[] adjustedStaticFields = adjustFields(classData.staticFields);
ClassData.Field[] adjustedInstanceFields = adjustFields(classData.instanceFields);
ClassData.Method[] adjustedDirectMethods = adjustMethods(classData.directMethods);
ClassData.Method[] adjustedVirtualMethods = adjustMethods(classData.virtualMethods);
return new ClassData(
classData.off, adjustedStaticFields, adjustedInstanceFields,
adjustedDirectMethods, adjustedVirtualMethods
);
}
public Code adjust(Code code) {
int adjustedDebugInfoOffset = adjustDebugInfoItemOffset(code.debugInfoOffset);
short[] adjustedInstructions = adjustInstructions(code.instructions);
Code.CatchHandler[] adjustedCatchHandlers = adjustCatchHandlers(code.catchHandlers);
return new Code(
code.off, code.registersSize, code.insSize, code.outsSize,
adjustedDebugInfoOffset, adjustedInstructions, code.tries, adjustedCatchHandlers
);
}
private short[] adjustInstructions(short[] instructions) {
if (instructions == null || instructions.length == 0) {
return instructions;
}
InstructionTransformer insTrans = new InstructionTransformer(this);
return insTrans.transform(instructions);
}
private Code.CatchHandler[] adjustCatchHandlers(Code.CatchHandler[] catchHandlers) {
if (catchHandlers == null || catchHandlers.length == 0) {
return catchHandlers;
}
Code.CatchHandler[] adjustedCatchHandlers = new Code.CatchHandler[catchHandlers.length];
for (int i = 0; i < catchHandlers.length; ++i) {
Code.CatchHandler catchHandler = catchHandlers[i];
int typeIndexesCount = catchHandler.typeIndexes.length;
int[] adjustedTypeIndexes = new int[typeIndexesCount];
for (int j = 0; j < typeIndexesCount; ++j) {
adjustedTypeIndexes[j] = adjustTypeIdIndex(catchHandler.typeIndexes[j]);
}
adjustedCatchHandlers[i] = new Code.CatchHandler(
adjustedTypeIndexes, catchHandler.addresses,
catchHandler.catchAllAddress, catchHandler.offset
);
}
return adjustedCatchHandlers;
}
private ClassData.Field[] adjustFields(ClassData.Field[] fields) {
ClassData.Field[] adjustedFields = new ClassData.Field[fields.length];
for (int i = 0; i < fields.length; ++i) {
ClassData.Field field = fields[i];
int adjustedFieldIndex = adjustFieldIdIndex(field.fieldIndex);
adjustedFields[i] = new ClassData.Field(adjustedFieldIndex, field.accessFlags);
}
return adjustedFields;
}
private ClassData.Method[] adjustMethods(ClassData.Method[] methods) {
ClassData.Method[] adjustedMethods = new ClassData.Method[methods.length];
for (int i = 0; i < methods.length; ++i) {
ClassData.Method method = methods[i];
int adjustedMethodIndex = adjustMethodIdIndex(method.methodIndex);
int adjustedCodeOffset = adjustCodeOffset(method.codeOffset);
adjustedMethods[i] = new ClassData.Method(
adjustedMethodIndex, method.accessFlags, adjustedCodeOffset
);
}
return adjustedMethods;
}
public DebugInfoItem adjust(DebugInfoItem debugInfoItem) {
int[] parameterNames = adjustParameterNames(debugInfoItem.parameterNames);
byte[] infoSTM = adjustDebugInfoItemSTM(debugInfoItem.infoSTM);
return new DebugInfoItem(
debugInfoItem.off, debugInfoItem.lineStart, parameterNames, infoSTM
);
}
private int[] adjustParameterNames(int[] parameterNames) {
int size = parameterNames.length;
int[] adjustedParameterNames = new int[size];
for (int i = 0; i < size; ++i) {
adjustedParameterNames[i] = adjustStringIndex(parameterNames[i]);
}
return adjustedParameterNames;
}
private byte[] adjustDebugInfoItemSTM(byte[] infoSTM) {
ByteArrayInputStream bais = new ByteArrayInputStream(infoSTM);
final ByteArrayInputStream baisRef = bais;
ByteInput inAdapter = new ByteInput() {
@Override
public byte readByte() {
return (byte) (baisRef.read() & 0xFF);
}
};
ByteArrayOutputStream baos = new ByteArrayOutputStream(infoSTM.length + 512);
final ByteArrayOutputStream baosRef = baos;
ByteOutput outAdapter = new ByteOutput() {
@Override
public void writeByte(int i) {
baosRef.write(i);
}
};
outside_whileloop:
while (true) {
int opcode = bais.read() & 0xFF;
baos.write(opcode);
switch (opcode) {
case DebugInfoItem.DBG_END_SEQUENCE: {
break outside_whileloop;
}
case DebugInfoItem.DBG_ADVANCE_PC: {
int addrDiff = Leb128.readUnsignedLeb128(inAdapter);
Leb128.writeUnsignedLeb128(outAdapter, addrDiff);
break;
}
case DebugInfoItem.DBG_ADVANCE_LINE: {
int lineDiff = Leb128.readSignedLeb128(inAdapter);
Leb128.writeSignedLeb128(outAdapter, lineDiff);
break;
}
case DebugInfoItem.DBG_START_LOCAL:
case DebugInfoItem.DBG_START_LOCAL_EXTENDED: {
int registerNum = Leb128.readUnsignedLeb128(inAdapter);
Leb128.writeUnsignedLeb128(outAdapter, registerNum);
int nameIndex = adjustStringIndex(Leb128.readUnsignedLeb128p1(inAdapter));
Leb128.writeUnsignedLeb128p1(outAdapter, nameIndex);
int typeIndex = adjustTypeIdIndex(Leb128.readUnsignedLeb128p1(inAdapter));
Leb128.writeUnsignedLeb128p1(outAdapter, typeIndex);
if (opcode == DebugInfoItem.DBG_START_LOCAL_EXTENDED) {
int sigIndex = adjustStringIndex(Leb128.readUnsignedLeb128p1(inAdapter));
Leb128.writeUnsignedLeb128p1(outAdapter, sigIndex);
}
break;
}
case DebugInfoItem.DBG_END_LOCAL:
case DebugInfoItem.DBG_RESTART_LOCAL: {
int registerNum = Leb128.readUnsignedLeb128(inAdapter);
Leb128.writeUnsignedLeb128(outAdapter, registerNum);
break;
}
case DebugInfoItem.DBG_SET_FILE: {
int nameIndex = adjustStringIndex(Leb128.readUnsignedLeb128p1(inAdapter));
Leb128.writeUnsignedLeb128p1(outAdapter, nameIndex);
break;
}
case DebugInfoItem.DBG_SET_PROLOGUE_END:
case DebugInfoItem.DBG_SET_EPILOGUE_BEGIN:
default: {
break;
}
}
}
return baos.toByteArray();
}
public EncodedValue adjust(EncodedValue encodedArray) {
final ByteArrayOutputStream baos = new ByteArrayOutputStream(encodedArray.data.length);
new EncodedValueTransformer(
new ByteOutput() {
@Override
public void writeByte(int i) {
baos.write(i);
}
}
).transformArray(
new EncodedValueReader(encodedArray, EncodedValueReader.ENCODED_ARRAY)
);
return new EncodedValue(encodedArray.off, baos.toByteArray());
}
public Annotation adjust(Annotation annotation) {
final ByteArrayOutputStream baos = new ByteArrayOutputStream(annotation.encodedAnnotation.data.length);
new EncodedValueTransformer(
new ByteOutput() {
@Override
public void writeByte(int i) {
baos.write(i);
}
}
).transformAnnotation(annotation.getReader());
return new Annotation(
annotation.off,
annotation.visibility,
new EncodedValue(annotation.encodedAnnotation.off, baos.toByteArray())
);
}
public AnnotationSet adjust(AnnotationSet annotationSet) {
int size = annotationSet.annotationOffsets.length;
int[] adjustedAnnotationOffsets = new int[size];
for (int i = 0; i < size; ++i) {
adjustedAnnotationOffsets[i]
= adjustAnnotationOffset(annotationSet.annotationOffsets[i]);
}
return new AnnotationSet(annotationSet.off, adjustedAnnotationOffsets);
}
public AnnotationSetRefList adjust(AnnotationSetRefList annotationSetRefList) {
int size = annotationSetRefList.annotationSetRefItems.length;
int[] adjustedAnnotationSetRefItems = new int[size];
for (int i = 0; i < size; ++i) {
adjustedAnnotationSetRefItems[i]
= adjustAnnotationSetOffset(annotationSetRefList.annotationSetRefItems[i]);
}
return new AnnotationSetRefList(annotationSetRefList.off, adjustedAnnotationSetRefItems);
}
public AnnotationsDirectory adjust(AnnotationsDirectory annotationsDirectory) {
int adjustedClassAnnotationsOffset
= adjustAnnotationSetOffset(annotationsDirectory.classAnnotationsOffset);
int[][] adjustedFieldAnnotations
= new int[annotationsDirectory.fieldAnnotations.length][2];
for (int i = 0; i < adjustedFieldAnnotations.length; ++i) {
adjustedFieldAnnotations[i][0]
= adjustFieldIdIndex(annotationsDirectory.fieldAnnotations[i][0]);
adjustedFieldAnnotations[i][1]
= adjustAnnotationSetOffset(annotationsDirectory.fieldAnnotations[i][1]);
}
int[][] adjustedMethodAnnotations
= new int[annotationsDirectory.methodAnnotations.length][2];
for (int i = 0; i < adjustedMethodAnnotations.length; ++i) {
adjustedMethodAnnotations[i][0]
= adjustMethodIdIndex(annotationsDirectory.methodAnnotations[i][0]);
adjustedMethodAnnotations[i][1]
= adjustAnnotationSetOffset(annotationsDirectory.methodAnnotations[i][1]);
}
int[][] adjustedParameterAnnotations
= new int[annotationsDirectory.parameterAnnotations.length][2];
for (int i = 0; i < adjustedParameterAnnotations.length; ++i) {
adjustedParameterAnnotations[i][0]
= adjustMethodIdIndex(annotationsDirectory.parameterAnnotations[i][0]);
adjustedParameterAnnotations[i][1]
= adjustAnnotationSetRefListOffset(
annotationsDirectory.parameterAnnotations[i][1]
);
}
return new AnnotationsDirectory(
annotationsDirectory.off, adjustedClassAnnotationsOffset,
adjustedFieldAnnotations, adjustedMethodAnnotations, adjustedParameterAnnotations
);
}
/**
* Adjust an encoded value or array.
*/
private final class EncodedValueTransformer {
private final ByteOutput out;
EncodedValueTransformer(ByteOutput out) {
this.out = out;
}
public void transform(EncodedValueReader reader) {
switch (reader.peek()) {
case EncodedValueReader.ENCODED_BYTE:
EncodedValueCodec.writeSignedIntegralValue(out, EncodedValueReader.ENCODED_BYTE, reader.readByte());
break;
case EncodedValueReader.ENCODED_SHORT:
EncodedValueCodec.writeSignedIntegralValue(out, EncodedValueReader.ENCODED_SHORT, reader.readShort());
break;
case EncodedValueReader.ENCODED_INT:
EncodedValueCodec.writeSignedIntegralValue(out, EncodedValueReader.ENCODED_INT, reader.readInt());
break;
case EncodedValueReader.ENCODED_LONG:
EncodedValueCodec.writeSignedIntegralValue(out, EncodedValueReader.ENCODED_LONG, reader.readLong());
break;
case EncodedValueReader.ENCODED_CHAR:
EncodedValueCodec.writeUnsignedIntegralValue(out, EncodedValueReader.ENCODED_CHAR, reader.readChar());
break;
case EncodedValueReader.ENCODED_FLOAT:
// Shift value left 32 so that right-zero-extension works.
long longBits = ((long) Float.floatToIntBits(reader.readFloat())) << 32;
EncodedValueCodec.writeRightZeroExtendedValue(out, EncodedValueReader.ENCODED_FLOAT, longBits);
break;
case EncodedValueReader.ENCODED_DOUBLE:
EncodedValueCodec.writeRightZeroExtendedValue(
out, EncodedValueReader.ENCODED_DOUBLE, Double.doubleToLongBits(reader.readDouble()));
break;
case EncodedValueReader.ENCODED_STRING:
EncodedValueCodec.writeUnsignedIntegralValue(
out, EncodedValueReader.ENCODED_STRING, adjustStringIndex(reader.readString()));
break;
case EncodedValueReader.ENCODED_TYPE:
EncodedValueCodec.writeUnsignedIntegralValue(
out, EncodedValueReader.ENCODED_TYPE, adjustTypeIdIndex(reader.readType()));
break;
case EncodedValueReader.ENCODED_FIELD:
EncodedValueCodec.writeUnsignedIntegralValue(
out, EncodedValueReader.ENCODED_FIELD, adjustFieldIdIndex(reader.readField()));
break;
case EncodedValueReader.ENCODED_ENUM:
EncodedValueCodec.writeUnsignedIntegralValue(
out, EncodedValueReader.ENCODED_ENUM, adjustFieldIdIndex(reader.readEnum()));
break;
case EncodedValueReader.ENCODED_METHOD:
EncodedValueCodec.writeUnsignedIntegralValue(
out, EncodedValueReader.ENCODED_METHOD, adjustMethodIdIndex(reader.readMethod()));
break;
case EncodedValueReader.ENCODED_ARRAY:
writeTypeAndArg(EncodedValueReader.ENCODED_ARRAY, 0);
transformArray(reader);
break;
case EncodedValueReader.ENCODED_ANNOTATION:
writeTypeAndArg(EncodedValueReader.ENCODED_ANNOTATION, 0);
transformAnnotation(reader);
break;
case EncodedValueReader.ENCODED_NULL:
reader.readNull();
writeTypeAndArg(EncodedValueReader.ENCODED_NULL, 0);
break;
case EncodedValueReader.ENCODED_BOOLEAN:
boolean value = reader.readBoolean();
writeTypeAndArg(EncodedValueReader.ENCODED_BOOLEAN, value ? 1 : 0);
break;
default:
throw new DexException("Unexpected type: " + Integer.toHexString(reader.peek()));
}
}
private void transformAnnotation(EncodedValueReader reader) {
int fieldCount = reader.readAnnotation();
Leb128.writeUnsignedLeb128(out, adjustTypeIdIndex(reader.getAnnotationType()));
Leb128.writeUnsignedLeb128(out, fieldCount);
for (int i = 0; i < fieldCount; i++) {
Leb128.writeUnsignedLeb128(out, adjustStringIndex(reader.readAnnotationName()));
transform(reader);
}
}
private void transformArray(EncodedValueReader reader) {
int size = reader.readArray();
Leb128.writeUnsignedLeb128(out, size);
for (int i = 0; i < size; i++) {
transform(reader);
}
}
private void writeTypeAndArg(int type, int arg) {
out.writeByte((arg << 5) | type);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy