Implementation of new generificationified writer functionality

This commit is contained in:
Ben Gruver 2013-04-27 22:23:30 -07:00
parent afc0a7d325
commit 1bf6f23245
78 changed files with 5297 additions and 3354 deletions

View File

@ -419,7 +419,7 @@ public class MethodDefinition {
}
private void addTries(List<MethodItem> methodItems) {
List<? extends TryBlock> tryBlocks = methodImpl.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = methodImpl.getTryBlocks();
if (tryBlocks.size() == 0) {
return;
}
@ -427,7 +427,7 @@ public class MethodDefinition {
int lastInstructionAddress = instructionOffsetMap.getInstructionCodeOffset(instructions.size() - 1);
int codeSize = lastInstructionAddress + instructions.get(instructions.size() - 1).getCodeUnits();
for (TryBlock tryBlock: tryBlocks) {
for (TryBlock<? extends ExceptionHandler> tryBlock: tryBlocks) {
int startAddress = tryBlock.getStartCodeAddress();
int endAddress = startAddress + tryBlock.getCodeUnitCount();

View File

@ -111,7 +111,7 @@ public final class DexFileFactory {
}
public static void writeDexFile(String path, DexFile dexFile) throws IOException {
org.jf.dexlib2.writer.DexFile.writeTo(path, dexFile);
org.jf.dexlib2.writer.pool.DexPool.writeTo(path, dexFile);
}
private DexFileFactory() {}

View File

@ -1035,7 +1035,7 @@ public class MethodAnalyzer {
RegisterType exceptionType = RegisterType.UNKNOWN_TYPE;
for (TryBlock tryBlock: methodImpl.getTryBlocks()) {
for (TryBlock<? extends ExceptionHandler> tryBlock: methodImpl.getTryBlocks()) {
for (ExceptionHandler handler: tryBlock.getExceptionHandlers()) {
if (handler.getHandlerCodeAddress() == instructionAddress) {

View File

@ -65,7 +65,7 @@ public abstract class BaseAnnotation implements Annotation {
return CollectionUtils.compareAsSet(getElements(), o.getElements());
}
public static final Comparator<Annotation> BY_TYPE = new Comparator<Annotation>() {
public static final Comparator<? super Annotation> BY_TYPE = new Comparator<Annotation>() {
@Override
public int compare(Annotation annotation1, Annotation annotation2) {
return annotation1.getType().compareTo(annotation2.getType());

View File

@ -31,9 +31,10 @@
package org.jf.dexlib2.base;
import org.jf.dexlib2.iface.ExceptionHandler;
import org.jf.dexlib2.iface.TryBlock;
public abstract class BaseTryBlock implements TryBlock {
public abstract class BaseTryBlock<EH extends ExceptionHandler> implements TryBlock<EH> {
@Override public boolean equals(Object o) {
if (o instanceof TryBlock) {
TryBlock other = (TryBlock)o;

View File

@ -37,7 +37,7 @@ import org.jf.dexlib2.iface.ExceptionHandler;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class DexBackedCatchAllExceptionHandler extends BaseExceptionHandler implements ExceptionHandler {
public class DexBackedCatchAllExceptionHandler extends DexBackedExceptionHandler {
private final int handlerCodeAddress;
public DexBackedCatchAllExceptionHandler(@Nonnull DexReader reader) {

View File

@ -32,22 +32,6 @@
package org.jf.dexlib2.dexbacked;
import org.jf.dexlib2.base.BaseExceptionHandler;
import org.jf.dexlib2.iface.ExceptionHandler;
import javax.annotation.Nonnull;
public class DexBackedExceptionHandler extends BaseExceptionHandler implements ExceptionHandler {
@Nonnull private final DexBackedDexFile dexFile;
private final int typeId;
private final int handlerCodeAddress;
public DexBackedExceptionHandler(@Nonnull DexReader reader) {
// TODO: verify dalvik doesn't accept an exception handler that points in the middle of an instruction
this.dexFile = reader.dexBuf;
this.typeId = reader.readSmallUleb128();
this.handlerCodeAddress = reader.readSmallUleb128();
}
@Nonnull @Override public String getExceptionType() { return dexFile.getType(typeId); }
@Override public int getHandlerCodeAddress() { return handlerCodeAddress; }
public abstract class DexBackedExceptionHandler extends BaseExceptionHandler {
}

View File

@ -38,7 +38,6 @@ import org.jf.dexlib2.dexbacked.util.DebugInfo;
import org.jf.dexlib2.dexbacked.util.FixedSizeList;
import org.jf.dexlib2.dexbacked.util.VariableSizeLookaheadIterator;
import org.jf.dexlib2.iface.MethodImplementation;
import org.jf.dexlib2.iface.TryBlock;
import org.jf.dexlib2.iface.debug.DebugItem;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.util.AlignmentUtils;
@ -87,7 +86,7 @@ public class DexBackedMethodImplementation implements MethodImplementation {
@Nonnull
@Override
public List<? extends TryBlock> getTryBlocks() {
public List<? extends DexBackedTryBlock> getTryBlocks() {
// TODO: provide utility to put try blocks into a "canonical", easy to use format, which more closely matches java's try blocks
final int triesSize = dexFile.readUshort(codeOffset + CodeItem.TRIES_SIZE_OFFSET);
if (triesSize > 0) {
@ -96,10 +95,10 @@ public class DexBackedMethodImplementation implements MethodImplementation {
codeOffset + CodeItem.INSTRUCTION_START_OFFSET + (instructionsSize*2), 4);
final int handlersStartOffset = triesStartOffset + triesSize*CodeItem.TryItem.ITEM_SIZE;
return new FixedSizeList<TryBlock>() {
return new FixedSizeList<DexBackedTryBlock>() {
@Nonnull
@Override
public TryBlock readItem(int index) {
public DexBackedTryBlock readItem(int index) {
return new DexBackedTryBlock(dexFile,
triesStartOffset + index*CodeItem.TryItem.ITEM_SIZE,
handlersStartOffset);

View File

@ -34,19 +34,15 @@ package org.jf.dexlib2.dexbacked;
import org.jf.dexlib2.base.BaseTryBlock;
import org.jf.dexlib2.dexbacked.raw.CodeItem;
import org.jf.dexlib2.dexbacked.util.VariableSizeList;
import org.jf.dexlib2.iface.ExceptionHandler;
import org.jf.dexlib2.iface.TryBlock;
import javax.annotation.Nonnull;
import java.util.List;
public class DexBackedTryBlock extends BaseTryBlock implements TryBlock {
public class DexBackedTryBlock extends BaseTryBlock<DexBackedExceptionHandler> {
@Nonnull public final DexBackedDexFile dexFile;
private final int tryItemOffset;
private final int handlersStartOffset;
public DexBackedTryBlock(@Nonnull DexBackedDexFile dexFile,
int tryItemOffset,
int handlersStartOffset) {
@ -65,31 +61,31 @@ public class DexBackedTryBlock extends BaseTryBlock implements TryBlock {
@Nonnull
@Override
public List<? extends ExceptionHandler> getExceptionHandlers() {
public List<? extends DexBackedExceptionHandler> getExceptionHandlers() {
DexReader reader = dexFile.readerAt(
handlersStartOffset + dexFile.readUshort(tryItemOffset + CodeItem.TryItem.HANDLER_OFFSET));
final int encodedSize = reader.readSleb128();
if (encodedSize > 0) {
//no catch-all
return new VariableSizeList<ExceptionHandler>(dexFile, reader.getOffset(), encodedSize) {
return new VariableSizeList<DexBackedTypedExceptionHandler>(dexFile, reader.getOffset(), encodedSize) {
@Nonnull
@Override
protected ExceptionHandler readNextItem(@Nonnull DexReader reader, int index) {
return new DexBackedExceptionHandler(reader);
protected DexBackedTypedExceptionHandler readNextItem(@Nonnull DexReader reader, int index) {
return new DexBackedTypedExceptionHandler(reader);
}
};
} else {
//with catch-all
final int sizeWithCatchAll = (-1 * encodedSize) + 1;
return new VariableSizeList<ExceptionHandler>(dexFile, reader.getOffset(), sizeWithCatchAll) {
return new VariableSizeList<DexBackedExceptionHandler>(dexFile, reader.getOffset(), sizeWithCatchAll) {
@Nonnull
@Override
protected ExceptionHandler readNextItem(@Nonnull DexReader dexReader, int index) {
protected DexBackedExceptionHandler readNextItem(@Nonnull DexReader dexReader, int index) {
if (index == sizeWithCatchAll-1) {
return new DexBackedCatchAllExceptionHandler(dexReader);
} else {
return new DexBackedExceptionHandler(dexReader);
return new DexBackedTypedExceptionHandler(dexReader);
}
}
};

View File

@ -0,0 +1,53 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.dexbacked;
import org.jf.dexlib2.base.BaseExceptionHandler;
import org.jf.dexlib2.iface.ExceptionHandler;
import javax.annotation.Nonnull;
public class DexBackedTypedExceptionHandler extends DexBackedExceptionHandler {
@Nonnull private final DexBackedDexFile dexFile;
private final int typeId;
private final int handlerCodeAddress;
public DexBackedTypedExceptionHandler(@Nonnull DexReader reader) {
// TODO: verify dalvik doesn't accept an exception handler that points in the middle of an instruction
this.dexFile = reader.dexBuf;
this.typeId = reader.readSmallUleb128();
this.handlerCodeAddress = reader.readSmallUleb128();
}
@Nonnull @Override public String getExceptionType() { return dexFile.getType(typeId); }
@Override public int getHandlerCodeAddress() { return handlerCodeAddress; }
}

View File

@ -70,7 +70,7 @@ public interface MethodImplementation {
*
* @return A list of the TryBlock items
*/
@Nonnull List<? extends TryBlock> getTryBlocks();
@Nonnull List<? extends TryBlock<? extends ExceptionHandler>> getTryBlocks();
/**
* Get a list of debug items for this method.

View File

@ -38,7 +38,7 @@ import java.util.List;
/**
* This class represents an individual try block and associated set of handlers.
*/
public interface TryBlock {
public interface TryBlock<EH extends ExceptionHandler> {
/**
* Gets the code offset of the start of this try block.
*
@ -67,7 +67,7 @@ public interface TryBlock {
*
* @return A list of ExceptionHandler objects
*/
@Nonnull List<? extends ExceptionHandler> getExceptionHandlers();
@Nonnull List<? extends EH> getExceptionHandlers();
/**
* Compares this TryBlock to another TryBlock for equality.

View File

@ -32,6 +32,7 @@
package org.jf.dexlib2.immutable;
import com.google.common.collect.ImmutableList;
import org.jf.dexlib2.iface.ExceptionHandler;
import org.jf.dexlib2.iface.MethodImplementation;
import org.jf.dexlib2.iface.TryBlock;
import org.jf.dexlib2.iface.debug.DebugItem;
@ -52,7 +53,7 @@ public class ImmutableMethodImplementation implements MethodImplementation {
public ImmutableMethodImplementation(int registerCount,
@Nullable Iterable<? extends Instruction> instructions,
@Nullable List<? extends TryBlock> tryBlocks,
@Nullable List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks,
@Nullable Iterable<? extends DebugItem> debugItems) {
this.registerCount = registerCount;
this.instructions = ImmutableInstruction.immutableListOf(instructions);

View File

@ -42,7 +42,7 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
public class ImmutableTryBlock extends BaseTryBlock implements TryBlock {
public class ImmutableTryBlock extends BaseTryBlock<ImmutableExceptionHandler> {
protected final int startCodeAddress;
protected final int codeUnitCount;
@Nonnull protected final ImmutableList<? extends ImmutableExceptionHandler> exceptionHandlers;
@ -63,7 +63,7 @@ public class ImmutableTryBlock extends BaseTryBlock implements TryBlock {
this.exceptionHandlers = ImmutableUtils.nullToEmptyList(exceptionHandlers);
}
public static ImmutableTryBlock of(TryBlock tryBlock) {
public static ImmutableTryBlock of(TryBlock<? extends ExceptionHandler> tryBlock) {
if (tryBlock instanceof ImmutableTryBlock) {
return (ImmutableTryBlock)tryBlock;
}
@ -81,12 +81,13 @@ public class ImmutableTryBlock extends BaseTryBlock implements TryBlock {
}
@Nonnull
public static ImmutableList<ImmutableTryBlock> immutableListOf(@Nullable List<? extends TryBlock> list) {
public static ImmutableList<ImmutableTryBlock> immutableListOf(
@Nullable List<? extends TryBlock<? extends ExceptionHandler>> list) {
return CONVERTER.toList(list);
}
private static final ImmutableConverter<ImmutableTryBlock, TryBlock> CONVERTER =
new ImmutableConverter<ImmutableTryBlock, TryBlock>() {
private static final ImmutableConverter<ImmutableTryBlock, TryBlock<? extends ExceptionHandler>> CONVERTER =
new ImmutableConverter<ImmutableTryBlock, TryBlock<? extends ExceptionHandler>>() {
@Override
protected boolean isImmutable(@Nonnull TryBlock item) {
return item instanceof ImmutableTryBlock;
@ -94,7 +95,7 @@ public class ImmutableTryBlock extends BaseTryBlock implements TryBlock {
@Nonnull
@Override
protected ImmutableTryBlock makeImmutable(@Nonnull TryBlock item) {
protected ImmutableTryBlock makeImmutable(@Nonnull TryBlock<? extends ExceptionHandler> item) {
return ImmutableTryBlock.of(item);
}
};

View File

@ -0,0 +1,223 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.immutable.instruction;
import org.jf.dexlib2.Opcode;
import org.jf.dexlib2.iface.instruction.SwitchElement;
import org.jf.dexlib2.iface.reference.Reference;
import org.jf.dexlib2.writer.InstructionFactory;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
public class ImmutableInstructionFactory implements InstructionFactory<ImmutableInstruction> {
public static final ImmutableInstructionFactory INSTANCE = new ImmutableInstructionFactory();
private ImmutableInstructionFactory() {
}
public ImmutableInstruction10t makeInstruction10t(@Nonnull Opcode opcode,
int codeOffset) {
return new ImmutableInstruction10t(opcode, codeOffset);
}
public ImmutableInstruction10x makeInstruction10x(@Nonnull Opcode opcode) {
return new ImmutableInstruction10x(opcode);
}
public ImmutableInstruction11n makeInstruction11n(@Nonnull Opcode opcode,
int registerA,
int literal) {
return new ImmutableInstruction11n(opcode, registerA, literal);
}
public ImmutableInstruction11x makeInstruction11x(@Nonnull Opcode opcode,
int registerA) {
return new ImmutableInstruction11x(opcode, registerA);
}
public ImmutableInstruction12x makeInstruction12x(@Nonnull Opcode opcode,
int registerA,
int registerB) {
return new ImmutableInstruction12x(opcode, registerA, registerB);
}
public ImmutableInstruction20bc makeInstruction20bc(@Nonnull Opcode opcode,
int verificationError,
@Nonnull Reference reference) {
return new ImmutableInstruction20bc(opcode, verificationError, reference);
}
public ImmutableInstruction20t makeInstruction20t(@Nonnull Opcode opcode,
int codeOffset) {
return new ImmutableInstruction20t(opcode, codeOffset);
}
public ImmutableInstruction21c makeInstruction21c(@Nonnull Opcode opcode,
int registerA,
@Nonnull Reference reference) {
return new ImmutableInstruction21c(opcode, registerA, reference);
}
public ImmutableInstruction21ih makeInstruction21ih(@Nonnull Opcode opcode,
int registerA,
int literal) {
return new ImmutableInstruction21ih(opcode, registerA, literal);
}
public ImmutableInstruction21lh makeInstruction21lh(@Nonnull Opcode opcode,
int registerA,
long literal) {
return new ImmutableInstruction21lh(opcode, registerA, literal);
}
public ImmutableInstruction21s makeInstruction21s(@Nonnull Opcode opcode,
int registerA,
int literal) {
return new ImmutableInstruction21s(opcode, registerA, literal);
}
public ImmutableInstruction21t makeInstruction21t(@Nonnull Opcode opcode,
int registerA,
int codeOffset) {
return new ImmutableInstruction21t(opcode, registerA, codeOffset);
}
public ImmutableInstruction22b makeInstruction22b(@Nonnull Opcode opcode,
int registerA,
int registerB,
int literal) {
return new ImmutableInstruction22b(opcode, registerA, registerB, literal);
}
public ImmutableInstruction22c makeInstruction22c(@Nonnull Opcode opcode,
int registerA,
int registerB,
@Nonnull Reference reference) {
return new ImmutableInstruction22c(opcode, registerA, registerB, reference);
}
public ImmutableInstruction22s makeInstruction22s(@Nonnull Opcode opcode,
int registerA,
int registerB,
int literal) {
return new ImmutableInstruction22s(opcode, registerA, registerB, literal);
}
public ImmutableInstruction22t makeInstruction22t(@Nonnull Opcode opcode,
int registerA,
int registerB,
int codeOffset) {
return new ImmutableInstruction22t(opcode, registerA, registerB, codeOffset);
}
public ImmutableInstruction22x makeInstruction22x(@Nonnull Opcode opcode,
int registerA,
int registerB) {
return new ImmutableInstruction22x(opcode, registerA, registerB);
}
public ImmutableInstruction23x makeInstruction23x(@Nonnull Opcode opcode,
int registerA,
int registerB,
int registerC) {
return new ImmutableInstruction23x(opcode, registerA, registerB, registerC);
}
public ImmutableInstruction30t makeInstruction30t(@Nonnull Opcode opcode,
int codeOffset) {
return new ImmutableInstruction30t(opcode, codeOffset);
}
public ImmutableInstruction31c makeInstruction31c(@Nonnull Opcode opcode,
int registerA,
@Nonnull Reference reference) {
return new ImmutableInstruction31c(opcode, registerA, reference);
}
public ImmutableInstruction31i makeInstruction31i(@Nonnull Opcode opcode,
int registerA,
int literal) {
return new ImmutableInstruction31i(opcode, registerA, literal);
}
public ImmutableInstruction31t makeInstruction31t(@Nonnull Opcode opcode,
int registerA,
int codeOffset) {
return new ImmutableInstruction31t(opcode, registerA, codeOffset);
}
public ImmutableInstruction32x makeInstruction32x(@Nonnull Opcode opcode,
int registerA,
int registerB) {
return new ImmutableInstruction32x(opcode, registerA, registerB);
}
public ImmutableInstruction35c makeInstruction35c(@Nonnull Opcode opcode,
int registerCount,
int registerC,
int registerD,
int registerE,
int registerF,
int registerG,
@Nonnull Reference reference) {
return new ImmutableInstruction35c(opcode, registerCount, registerC, registerD, registerE, registerF, registerG,
reference);
}
public ImmutableInstruction3rc makeInstruction3rc(@Nonnull Opcode opcode,
int startRegister,
int registerCount,
@Nonnull Reference reference) {
return new ImmutableInstruction3rc(opcode, startRegister, registerCount, reference);
}
public ImmutableInstruction51l makeInstruction51l(@Nonnull Opcode opcode,
int registerA,
long literal) {
return new ImmutableInstruction51l(opcode, registerA, literal);
}
public ImmutableSparseSwitchPayload makeSparseSwitchPayload(@Nullable List<? extends SwitchElement> switchElements) {
return new ImmutableSparseSwitchPayload(switchElements);
}
public ImmutablePackedSwitchPayload makePackedSwitchPayload(@Nullable List<? extends SwitchElement> switchElements) {
return new ImmutablePackedSwitchPayload(switchElements);
}
public ImmutableArrayPayload makeArrayPayload(int elementWidth,
@Nullable List<Number> arrayElements) {
return new ImmutableArrayPayload(elementWidth, arrayElements);
}
}

View File

@ -38,7 +38,7 @@ import org.jf.dexlib2.iface.reference.MethodReference;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Collection;
public final class MethodUtil {
private static int directMask = AccessFlags.STATIC.getValue() | AccessFlags.PRIVATE.getValue() |
@ -76,7 +76,8 @@ public final class MethodUtil {
return getParameterRegisterCount(methodRef.getParameterTypes(), isStatic);
}
public static int getParameterRegisterCount(@Nonnull List<? extends CharSequence> parameterTypes, boolean isStatic) {
public static int getParameterRegisterCount(@Nonnull Collection<? extends CharSequence> parameterTypes,
boolean isStatic) {
int regCount = 0;
for (CharSequence paramType: parameterTypes) {
int firstChar = paramType.charAt(0);

View File

@ -1,262 +0,0 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.*;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.Field;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.MethodParameter;
import org.jf.util.CollectionUtils;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class AnnotationDirectoryPool {
@Nonnull private final Map<Key, Integer> internedAnnotationDirectoryItems = Maps.newHashMap();
@Nonnull private final Map<String, Integer> nonInternedAnnotationDirectoryOffsetMap = Maps.newHashMap();
@Nonnull private final List<Key> nonInternedAnnotationDirectoryItems = Lists.newArrayList();
@Nonnull private final DexFile dexFile;
private int sectionOffset = -1;
public AnnotationDirectoryPool(@Nonnull DexFile dexFile) {
this.dexFile = dexFile;
}
public void intern(@Nonnull ClassDef classDef) {
Key key = new Key(classDef);
if (key.hasNonClassAnnotations()) {
nonInternedAnnotationDirectoryItems.add(key);
} else if (key.hasClassAnnotations()) {
Integer prev = internedAnnotationDirectoryItems.put(key, 0);
if (prev != null) {
// we don't need to re-intern the contents
return;
}
} else {
// it's empty. nothing to do.
return;
}
dexFile.annotationSetPool.intern(classDef.getAnnotations());
for (Field field: Iterables.filter(classDef.getFields(), FIELD_HAS_ANNOTATION)) {
dexFile.annotationSetPool.intern(field.getAnnotations());
}
for (Method method: classDef.getMethods()) {
if (METHOD_HAS_ANNOTATION.apply(method)) {
dexFile.annotationSetPool.intern(method.getAnnotations());
}
if (METHOD_HAS_PARAMETER_ANNOTATION.apply(method)) {
dexFile.annotationSetRefPool.intern(method);
}
}
}
public int getOffset(@Nonnull ClassDef classDef) {
Integer offset = nonInternedAnnotationDirectoryOffsetMap.get(classDef.getType());
if (offset == null) {
Key key = new Key(classDef);
if (!key.hasNonClassAnnotations()) {
offset = internedAnnotationDirectoryItems.get(key);
}
if (offset == null) {
if (key.hasClassAnnotations() || key.hasNonClassAnnotations()) {
throw new ExceptionWithContext("Annotation directory not found for class %s.", classDef.getType());
}
offset = 0;
}
}
return offset;
}
public int getNumItems() {
return internedAnnotationDirectoryItems.size() + nonInternedAnnotationDirectoryItems.size();
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
// we'll write out the interned items first
List<Key> directoryItems = Lists.newArrayList(internedAnnotationDirectoryItems.keySet());
Collections.sort(directoryItems);
writer.align();
sectionOffset = writer.getPosition();
for (Key key: directoryItems) {
writer.align();
internedAnnotationDirectoryItems.put(key, writer.getPosition());
writer.writeInt(dexFile.annotationSetPool.getOffset(key.classDef.getAnnotations()));
writer.writeInt(0);
writer.writeInt(0);
writer.writeInt(0);
}
// now, write out the non-internable items
directoryItems = nonInternedAnnotationDirectoryItems;
Collections.sort(directoryItems);
for (Key key: directoryItems) {
writer.align();
nonInternedAnnotationDirectoryOffsetMap.put(key.classDef.getType(), writer.getPosition());
writer.writeInt(dexFile.annotationSetPool.getOffset(key.classDef.getAnnotations()));
writer.writeInt(key.fieldAnnotationCount);
writer.writeInt(key.methodAnnotationCount);
writer.writeInt(key.parameterAnnotationCount);
List<? extends Field> sortedFieldsWithAnnotations = Ordering.natural().immutableSortedCopy(
Iterables.filter(key.classDef.getFields(), FIELD_HAS_ANNOTATION));
for (Field field: sortedFieldsWithAnnotations) {
writer.writeInt(dexFile.fieldPool.getIndex(field));
writer.writeInt(dexFile.annotationSetPool.getOffset(field.getAnnotations()));
}
List<? extends Method> sortedMethods = Ordering.natural().immutableSortedCopy(
Iterables.filter(
key.classDef.getMethods(),
Predicates.or(METHOD_HAS_ANNOTATION, METHOD_HAS_PARAMETER_ANNOTATION)));
// It's safe to assume that we don't have any duplicate methods here. We would have already caught that and
// thrown an exception
for (Method method: sortedMethods) {
if (METHOD_HAS_ANNOTATION.apply(method)) {
writer.writeInt(dexFile.methodPool.getIndex(method));
writer.writeInt(dexFile.annotationSetPool.getOffset(method.getAnnotations()));
}
}
for (Method method: sortedMethods) {
if (METHOD_HAS_PARAMETER_ANNOTATION.apply(method)) {
writer.writeInt(dexFile.methodPool.getIndex(method));
writer.writeInt(dexFile.annotationSetRefPool.getOffset(method));
}
}
}
}
private static final Predicate<Field> FIELD_HAS_ANNOTATION = new Predicate<Field>() {
@Override
public boolean apply(Field input) { return input.getAnnotations().size() > 0; }
};
private static final Predicate<Method> METHOD_HAS_ANNOTATION = new Predicate<Method>() {
@Override
public boolean apply(Method input) { return input.getAnnotations().size() > 0; }
};
private static final Predicate<Method> METHOD_HAS_PARAMETER_ANNOTATION = new Predicate<Method>() {
@Override
public boolean apply(Method input) {
for (MethodParameter parameter: input.getParameters()) {
if (parameter.getAnnotations().size() > 0) {
return true;
}
}
return false;
}
};
private static class Key implements Comparable<Key> {
@Nonnull private final ClassDef classDef;
private final int fieldAnnotationCount;
private final int methodAnnotationCount;
private final int parameterAnnotationCount;
public Key(@Nonnull ClassDef classDef) {
this.classDef = classDef;
this.fieldAnnotationCount = Iterables.size(Iterables.filter(classDef.getFields(), FIELD_HAS_ANNOTATION));
int methodAnnotationCount = 0;
int parameterAnnotationCount = 0;
for (Method method: classDef.getMethods()) {
if (METHOD_HAS_ANNOTATION.apply(method)) {
methodAnnotationCount++;
}
if (METHOD_HAS_PARAMETER_ANNOTATION.apply(method)) {
parameterAnnotationCount++;
}
}
this.methodAnnotationCount = methodAnnotationCount;
this.parameterAnnotationCount = parameterAnnotationCount;
}
public boolean hasClassAnnotations() {
return classDef.getAnnotations().size() > 0;
}
public boolean hasNonClassAnnotations() {
return fieldAnnotationCount > 0 ||
methodAnnotationCount > 0 ||
parameterAnnotationCount > 0;
}
@Override
public int hashCode() {
// hashCode is only used for internable items - those that only have class annotations.
return classDef.getAnnotations().hashCode();
}
@Override
public boolean equals(Object o) {
// equals is only used for internable items - those that only have class annotations
if (o instanceof Key) {
Key other = (Key)o;
if (classDef.getAnnotations().size() != other.classDef.getAnnotations().size()) {
return false;
}
return Iterables.elementsEqual(classDef.getAnnotations(), other.classDef.getAnnotations());
}
return false;
}
@Override
public int compareTo(Key o) {
// compareTo will only be called on keys of the same internability. An internable key will not be compared
// with a non-internable one.
if (hasNonClassAnnotations()) {
return classDef.getType().compareTo(o.classDef.getType());
}
return CollectionUtils.compareAsSet(classDef.getAnnotations(), o.classDef.getAnnotations());
}
}
}

View File

@ -1,107 +0,0 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.jf.dexlib2.base.BaseAnnotationElement;
import org.jf.dexlib2.iface.Annotation;
import org.jf.dexlib2.iface.AnnotationElement;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
public class AnnotationPool {
@Nonnull private final Map<Annotation, Integer> internedAnnotations = Maps.newHashMap();
@Nonnull private final DexFile dexFile;
private int sectionOffset = -1;
public AnnotationPool(@Nonnull DexFile dexFile) {
this.dexFile = dexFile;
}
public void intern(@Nonnull Annotation annotation) {
Integer prev = internedAnnotations.put(annotation, 0);
if (prev == null) {
dexFile.typePool.intern(annotation.getType());
for (AnnotationElement element: annotation.getElements()) {
dexFile.stringPool.intern(element.getName());
dexFile.internEncodedValue(element.getValue());
}
}
}
public int getOffset(@Nonnull Annotation annotation) {
Integer offset = internedAnnotations.get(annotation);
if (offset == null) {
throw new ExceptionWithContext("Annotation not found.");
}
return offset;
}
public int getNumItems() {
return internedAnnotations.size();
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
List<Annotation> annotations = Lists.newArrayList(internedAnnotations.keySet());
Collections.sort(annotations);
sectionOffset = writer.getPosition();
for (Annotation annotation: annotations) {
internedAnnotations.put(annotation, writer.getPosition());
writer.writeUbyte(annotation.getVisibility());
writer.writeUleb128(dexFile.typePool.getIndex(annotation.getType()));
writer.writeUleb128(annotation.getElements().size());
SortedSet<? extends AnnotationElement> sortedElements =
ImmutableSortedSet.copyOf(BaseAnnotationElement.BY_NAME, annotation.getElements());
for (AnnotationElement element: sortedElements) {
writer.writeUleb128(dexFile.stringPool.getIndex(element.getName()));
dexFile.writeEncodedValue(writer, element.getValue());
}
}
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import javax.annotation.Nonnull;
import java.util.Collection;
public interface AnnotationSection<StringKey, TypeKey, AnnotationKey, AnnotationElement, EncodedValue>
extends OffsetSection<AnnotationKey> {
int getVisibility(@Nonnull AnnotationKey key);
@Nonnull TypeKey getType(@Nonnull AnnotationKey key);
@Nonnull Collection<? extends AnnotationElement> getElements(@Nonnull AnnotationKey key);
@Nonnull StringKey getElementName(@Nonnull AnnotationElement element);
@Nonnull EncodedValue getElementValue(@Nonnull AnnotationElement element);
}

View File

@ -1,107 +0,0 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import org.jf.dexlib2.base.BaseAnnotation;
import org.jf.dexlib2.iface.Annotation;
import org.jf.util.CollectionUtils;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.*;
public class AnnotationSetPool {
@Nonnull private final Map<Set<? extends Annotation>, Integer> internedAnnotationSetItems = Maps.newHashMap();
@Nonnull private final DexFile dexFile;
private int sectionOffset = -1;
public AnnotationSetPool(@Nonnull DexFile dexFile) {
this.dexFile = dexFile;
}
public void intern(@Nonnull Set<? extends Annotation> annotationSet) {
if (annotationSet.size() > 0) {
Integer prev = internedAnnotationSetItems.put(annotationSet, 0);
if (prev == null) {
for (Annotation annotation: annotationSet) {
dexFile.annotationPool.intern(annotation);
}
}
}
}
public int getOffset(@Nonnull Set<? extends Annotation> annotationSet) {
if (annotationSet.size() == 0) {
return 0;
}
Integer offset = internedAnnotationSetItems.get(annotationSet);
if (offset == null) {
throw new ExceptionWithContext("Annotation set not found.");
}
return offset;
}
public int getNumItems() {
return internedAnnotationSetItems.size();
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
List<Set<? extends Annotation>> annotationSets =
Lists.newArrayList(internedAnnotationSetItems.keySet());
Collections.sort(annotationSets, CollectionUtils.listComparator(Ordering.natural()));
writer.align();
sectionOffset = writer.getPosition();
for (Set<? extends Annotation> annotationSet: annotationSets) {
SortedSet<? extends Annotation> sortedAnnotationSet = ImmutableSortedSet.copyOf(BaseAnnotation.BY_TYPE,
annotationSet);
writer.align();
internedAnnotationSetItems.put(annotationSet, writer.getPosition());
writer.writeInt(annotationSet.size());
for (Annotation annotation: sortedAnnotationSet) {
writer.writeInt(dexFile.annotationPool.getOffset(annotation));
}
}
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import javax.annotation.Nonnull;
import java.util.Collection;
public interface AnnotationSetRefSection<AnnotationSetKey, AnnotationSetRefKey>
extends NullableOffsetSection<AnnotationSetRefKey> {
@Nonnull Collection<AnnotationSetKey> getAnnotationSets(@Nonnull AnnotationSetRefKey key);
}

View File

@ -0,0 +1,42 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import org.jf.dexlib2.iface.Annotation;
import javax.annotation.Nonnull;
import java.util.Collection;
public interface AnnotationSetSection<AnnotationKey extends Annotation, AnnotationSetKey>
extends NullableOffsetSection<AnnotationSetKey> {
@Nonnull Collection<? extends AnnotationKey> getAnnotations(@Nonnull AnnotationSetKey key);
}

View File

@ -1,302 +0,0 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import com.google.common.collect.*;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.Field;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.util.ReferenceUtil;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
public class ClassDefPool {
public final static int CLASS_DEF_ITEM_SIZE = 0x20;
@Nonnull private final Map<ClassDef, Boolean> internedClassDefItems = Maps.newHashMap();
@Nonnull private final Map<String, ClassDef> nameToClassDef = Maps.newHashMap();
@Nonnull private final DexFile dexFile;
private int indexSectionOffset = -1;
private int dataSectionOffset = -1;
private int classDataCount = 0;
public ClassDefPool(@Nonnull DexFile dexFile) {
this.dexFile = dexFile;
}
public void intern(@Nonnull ClassDef classDef) {
Boolean prev = internedClassDefItems.put(classDef, false);
if (prev != null) {
// item is already interned, no need to do it again
// TODO: add additional handling for the case of interning a modified class
return;
}
dexFile.typePool.intern(classDef.getType());
dexFile.typePool.internNullable(classDef.getSuperclass());
dexFile.typeListPool.intern(ImmutableSortedSet.copyOf(classDef.getInterfaces()));
dexFile.stringPool.internNullable(classDef.getSourceFile());
dexFile.encodedArrayPool.intern(classDef);
boolean hasClassData = false;
HashSet<String> fields = new HashSet<String>();
for (Field field: classDef.getFields()) {
hasClassData = true;
String fieldDescriptor = ReferenceUtil.getShortFieldDescriptor(field);
if (!fields.add(fieldDescriptor)) {
throw new ExceptionWithContext("Multiple definitions for field %s->%s",
classDef.getType(), fieldDescriptor);
}
dexFile.fieldPool.intern(field);
}
HashSet<String> methods = new HashSet<String>();
for (Method method: classDef.getMethods()) {
hasClassData = true;
String methodDescriptor = ReferenceUtil.getShortMethodDescriptor(method);
if (!methods.add(methodDescriptor)) {
throw new ExceptionWithContext("Multiple definitions for method %s->%s",
classDef.getType(), methodDescriptor);
}
dexFile.methodPool.intern(method);
dexFile.codeItemPool.intern(method);
}
dexFile.annotationDirectoryPool.intern(classDef);
if (hasClassData) {
classDataCount++;
}
nameToClassDef.put(classDef.getType(), classDef);
}
public int getIndexedSectionSize() {
return internedClassDefItems.size() * CLASS_DEF_ITEM_SIZE;
}
public int getNumClassDefItems() {
return internedClassDefItems.size();
}
public int getNumClassDataItems() {
return classDataCount;
}
public int getIndexSectionOffset() {
if (indexSectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return indexSectionOffset;
}
public int getDataSectionOffset() {
if (dataSectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return dataSectionOffset;
}
public void write(@Nonnull DexWriter indexWriter, @Nonnull DexWriter offsetWriter) throws IOException {
List<ClassDef> classDefs = Lists.newArrayList(internedClassDefItems.keySet());
indexSectionOffset = indexWriter.getPosition();
dataSectionOffset = offsetWriter.getPosition();
for (ClassDef classDef: classDefs) {
writeClass(indexWriter, offsetWriter, classDef);
}
}
private void writeClass(DexWriter indexWriter, DexWriter offsetWriter, ClassDef classDef) throws IOException {
if (classDef == null) {
// class does not exist in this dex file, cannot write it
return;
}
Boolean alreadyWritten = internedClassDefItems.put(classDef, true);
if (alreadyWritten != null && alreadyWritten) {
// class has already been written, no need to write it
return;
}
// first, try to write a superclass
ClassDef superClassDef = nameToClassDef.get(classDef.getSuperclass());
writeClass(indexWriter, offsetWriter, superClassDef);
// then, try to write interfaces
for (String iface: classDef.getInterfaces()) {
ClassDef interfaceClassDef = nameToClassDef.get(iface);
writeClass(indexWriter, offsetWriter, interfaceClassDef);
}
// and finally, write the class itself
writeSelf(indexWriter, offsetWriter, classDef);
}
private void writeSelf(DexWriter indexWriter, DexWriter offsetWriter, ClassDef classDef) throws IOException {
indexWriter.writeInt(dexFile.typePool.getIndex(classDef));
indexWriter.writeInt(classDef.getAccessFlags());
indexWriter.writeInt(dexFile.typePool.getIndexNullable(classDef.getSuperclass()));
indexWriter.writeInt(dexFile.typeListPool.getOffset(ImmutableSortedSet.copyOf(classDef.getInterfaces())));
if (classDef.getSourceFile() != null) {
indexWriter.writeInt(dexFile.stringPool.getIndexNullable(classDef.getSourceFile()));
} else {
indexWriter.writeInt(-1); // TODO: this should be replaced by NO_INDEX
}
indexWriter.writeInt(dexFile.annotationDirectoryPool.getOffset(classDef));
ClassDataItem classDataItem = new ClassDataItem(classDef);
if (classDataItem.hasData()) {
indexWriter.writeInt(offsetWriter.getPosition());
classDataItem.write(offsetWriter);
} else {
indexWriter.writeInt(0);
}
if (classDataItem.hasStaticFields()) {
indexWriter.writeInt(dexFile.encodedArrayPool.getOffset(classDef));
} else {
indexWriter.writeInt(0);
}
}
private class ClassDataItem {
ClassDef classDef;
int numStaticFields = 0;
int numInstanceFields = 0;
int numDirectMethods = 0;
int numVirtualMethods = 0;
private ClassDataItem(ClassDef classDef) {
this.classDef = classDef;
numStaticFields = Iterables.size(classDef.getStaticFields());
numInstanceFields = Iterables.size(classDef.getInstanceFields());
numDirectMethods = Iterables.size(classDef.getDirectMethods());
numVirtualMethods = Iterables.size(classDef.getVirtualMethods());
}
private boolean hasData() {
return (numStaticFields > 0 || numInstanceFields > 0 || numDirectMethods > 0 || numVirtualMethods > 0);
}
private boolean hasStaticFields() {
return numStaticFields > 0;
}
private void writeStaticFields(DexWriter writer) throws IOException {
int lastIdx = 0;
Iterable<? extends Field> sortedStaticFields =
Ordering.natural().immutableSortedCopy(classDef.getStaticFields());
for (Field field: sortedStaticFields) {
int idx = dexFile.fieldPool.getIndex(field);
writer.writeUleb128(idx - lastIdx);
lastIdx = idx;
writer.writeUleb128(field.getAccessFlags());
}
}
private void writeInstanceFields(DexWriter writer) throws IOException {
int lastIdx = 0;
Iterable<? extends Field> sortedInstanceFields =
Ordering.natural().immutableSortedCopy(classDef.getInstanceFields());
for (Field field: sortedInstanceFields) {
int idx = dexFile.fieldPool.getIndex(field);
writer.writeUleb128(idx - lastIdx);
lastIdx = idx;
writer.writeUleb128(field.getAccessFlags());
}
}
private void writeDirectMethods(DexWriter writer) throws IOException {
int lastIdx = 0;
Iterable<? extends Method> sortedDirectMethods =
Ordering.natural().immutableSortedCopy(classDef.getDirectMethods());
for (Method method: sortedDirectMethods) {
int idx = dexFile.methodPool.getIndex(method);
writer.writeUleb128(idx - lastIdx);
lastIdx = idx;
writer.writeUleb128(method.getAccessFlags());
writer.writeUleb128(dexFile.codeItemPool.getOffset(method));
}
}
private void writeVirtualMethods(DexWriter writer) throws IOException {
int lastIdx = 0;
Iterable<? extends Method> sortedVirtualMethods =
Ordering.natural().immutableSortedCopy(classDef.getVirtualMethods());
for (Method method: sortedVirtualMethods) {
int idx = dexFile.methodPool.getIndex(method);
writer.writeUleb128(idx - lastIdx);
lastIdx = idx;
writer.writeUleb128(method.getAccessFlags());
writer.writeUleb128(dexFile.codeItemPool.getOffset(method));
}
}
private void write(DexWriter writer) throws IOException {
writer.writeUleb128(numStaticFields);
writer.writeUleb128(numInstanceFields);
writer.writeUleb128(numDirectMethods);
writer.writeUleb128(numVirtualMethods);
writeStaticFields(writer);
writeInstanceFields(writer);
writeDirectMethods(writer);
writeVirtualMethods(writer);
}
}
}

View File

@ -0,0 +1,89 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import org.jf.dexlib2.iface.TryBlock;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
public interface ClassSection<StringKey extends CharSequence, TypeKey extends CharSequence, TypeListKey, ClassKey,
FieldKey, MethodKey, AnnotationSetKey,
AnnotationSetRefKey, EncodedArrayKey, DebugItem, Insn,
ExceptionHandler extends org.jf.dexlib2.iface.ExceptionHandler> extends IndexSection<ClassKey> {
@Nonnull Collection<? extends ClassKey> getSortedClasses();
@Nullable Map.Entry<? extends ClassKey, Integer> getClassEntryByType(@Nullable TypeKey key);
@Nonnull TypeKey getType(@Nonnull ClassKey key);
int getAccessFlags(@Nonnull ClassKey key);
@Nullable TypeKey getSuperclass(@Nonnull ClassKey key);
@Nullable TypeListKey getSortedInterfaces(@Nonnull ClassKey key);
@Nullable StringKey getSourceFile(@Nonnull ClassKey key);
@Nullable EncodedArrayKey getStaticInitializers(@Nonnull ClassKey key);
@Nonnull Collection<? extends FieldKey> getSortedStaticFields(@Nonnull ClassKey key);
@Nonnull Collection<? extends FieldKey> getSortedInstanceFields(@Nonnull ClassKey key);
@Nonnull Collection<? extends MethodKey> getSortedDirectMethods(@Nonnull ClassKey key);
@Nonnull Collection<? extends MethodKey> getSortedVirtualMethods(@Nonnull ClassKey key);
int getFieldAccessFlags(@Nonnull FieldKey key);
int getMethodAccessFlags(@Nonnull MethodKey key);
@Nullable AnnotationSetKey getClassAnnotations(@Nonnull ClassKey key);
@Nullable AnnotationSetKey getFieldAnnotations(@Nonnull FieldKey key);
@Nullable AnnotationSetKey getMethodAnnotations(@Nonnull MethodKey key);
@Nullable AnnotationSetRefKey getParameterAnnotations(@Nonnull MethodKey key);
@Nullable Iterable<? extends DebugItem> getDebugItems(@Nonnull MethodKey key);
@Nullable Iterable<? extends StringKey> getParameterNames(@Nonnull MethodKey key);
int getRegisterCount(@Nonnull MethodKey key);
@Nullable Iterable<? extends Insn> getInstructions(@Nonnull MethodKey key);
@Nonnull List<? extends TryBlock<? extends ExceptionHandler>> getTryBlocks(@Nonnull MethodKey key);
@Nullable TypeKey getExceptionType(@Nonnull ExceptionHandler handler);
void setAnnotationDirectoryOffset(@Nonnull ClassKey key, int offset);
int getAnnotationDirectoryOffset(@Nonnull ClassKey key);
void setCodeItemOffset(@Nonnull MethodKey key, int offset);
int getCodeItemOffset(@Nonnull MethodKey key);
void setDebugItemOffset(@Nonnull MethodKey key, int offset);
int getDebugItemOffset(@Nonnull MethodKey key);
void writeDebugItem(@Nonnull DebugWriter<StringKey, TypeKey> writer, DebugItem debugItem) throws IOException;
}

View File

@ -1,555 +0,0 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.jf.dexlib2.ReferenceType;
import org.jf.dexlib2.iface.ExceptionHandler;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.MethodImplementation;
import org.jf.dexlib2.iface.TryBlock;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
import org.jf.dexlib2.iface.instruction.SwitchElement;
import org.jf.dexlib2.iface.instruction.formats.*;
import org.jf.dexlib2.iface.reference.*;
import org.jf.dexlib2.util.MethodUtil;
import org.jf.dexlib2.util.ReferenceUtil;
import org.jf.dexlib2.writer.util.InstructionWriteUtil;
import org.jf.dexlib2.writer.util.TryListBuilder;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class CodeItemPool {
@Nonnull private final Map<Method, Integer> codeItemOffsetMap = Maps.newHashMap();
@Nonnull private final DexFile dexFile;
private int sectionOffset = -1;
public CodeItemPool(@Nonnull DexFile dexFile) {
this.dexFile = dexFile;
}
public void intern(@Nonnull Method method) {
// TODO: can we have parameter names (in the debug_info_item), without having any other sort of method implementation
// this also handles parameter names, which aren't directly tied to the MethodImplementation, even though the debug items are
boolean hasDebugInfo = dexFile.debugInfoPool.intern(method);
boolean hasInstruction = false;
MethodImplementation methodImpl = method.getImplementation();
if (methodImpl != null) {
for (Instruction instruction: methodImpl.getInstructions()) {
hasInstruction = true;
if (instruction instanceof ReferenceInstruction) {
Reference reference = ((ReferenceInstruction)instruction).getReference();
switch (instruction.getOpcode().referenceType) {
case ReferenceType.STRING:
dexFile.stringPool.intern((StringReference) reference);
break;
case ReferenceType.TYPE:
dexFile.typePool.intern((TypeReference)reference);
break;
case ReferenceType.FIELD:
dexFile.fieldPool.intern((FieldReference) reference);
break;
case ReferenceType.METHOD:
dexFile.methodPool.intern((MethodReference)reference);
break;
default:
throw new ExceptionWithContext("Unrecognized reference type: %d",
instruction.getOpcode().referenceType);
}
}
}
List<? extends TryBlock> tryBlocks = methodImpl.getTryBlocks();
if (!hasInstruction && tryBlocks.size() > 0) {
throw new ExceptionWithContext("Method %s has no instructions, but has try blocks.",
ReferenceUtil.getMethodDescriptor(method));
}
for (TryBlock tryBlock: methodImpl.getTryBlocks()) {
for (ExceptionHandler handler: tryBlock.getExceptionHandlers()) {
dexFile.typePool.internNullable(handler.getExceptionType());
}
}
}
if (hasDebugInfo || hasInstruction) {
codeItemOffsetMap.put(method, 0);
}
}
public int getOffset(@Nonnull Method method) {
Integer offset = codeItemOffsetMap.get(method);
if (offset == null) {
return 0;
}
return offset;
}
public int getNumItems() {
return codeItemOffsetMap.size();
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
ByteArrayOutputStream ehBuf = new ByteArrayOutputStream();
writer.align();
sectionOffset = writer.getPosition();
List<Method> methods = Lists.newArrayList(codeItemOffsetMap.keySet());
Collections.sort(methods);
for (Method method: methods) {
writer.align();
codeItemOffsetMap.put(method, writer.getPosition());
MethodImplementation methodImpl = method.getImplementation();
if (methodImpl != null) {
writer.writeUshort(methodImpl.getRegisterCount());
writer.writeUshort(MethodUtil.getParameterRegisterCount(method, MethodUtil.isStatic(method)));
InstructionWriteUtil instrWriteUtil = new InstructionWriteUtil(methodImpl, dexFile.stringPool);
writer.writeUshort(instrWriteUtil.getOutParamCount());
List<? extends TryBlock> tryBlocks = TryListBuilder.massageTryBlocks(methodImpl.getTryBlocks());
writer.writeUshort(tryBlocks.size());
writer.writeInt(dexFile.debugInfoPool.getOffset(method));
writer.writeInt(instrWriteUtil.getCodeUnitCount());
for (Instruction instruction: instrWriteUtil.getInstructions()) {
switch (instruction.getOpcode().format) {
case Format10t:
writeFormat10t(writer, (Instruction10t)instruction);
break;
case Format10x:
writeFormat10x(writer, (Instruction10x)instruction);
break;
case Format11n:
writeFormat11n(writer, (Instruction11n)instruction);
break;
case Format11x:
writeFormat11x(writer, (Instruction11x)instruction);
break;
case Format12x:
writeFormat12x(writer, (Instruction12x)instruction);
break;
case Format20t:
writeFormat20t(writer, (Instruction20t)instruction);
break;
case Format21c:
writeFormat21c(writer, (Instruction21c)instruction);
break;
case Format21ih:
writeFormat21ih(writer, (Instruction21ih)instruction);
break;
case Format21lh:
writeFormat21lh(writer, (Instruction21lh)instruction);
break;
case Format21s:
writeFormat21s(writer, (Instruction21s)instruction);
break;
case Format21t:
writeFormat21t(writer, (Instruction21t)instruction);
break;
case Format22b:
writeFormat22b(writer, (Instruction22b)instruction);
break;
case Format22c:
writeFormat22c(writer, (Instruction22c)instruction);
break;
case Format22s:
writeFormat22s(writer, (Instruction22s)instruction);
break;
case Format22t:
writeFormat22t(writer, (Instruction22t)instruction);
break;
case Format22x:
writeFormat22x(writer, (Instruction22x)instruction);
break;
case Format23x:
writeFormat23x(writer, (Instruction23x)instruction);
break;
case Format30t:
writeFormat30t(writer, (Instruction30t)instruction);
break;
case Format31c:
writeFormat31c(writer, (Instruction31c)instruction);
break;
case Format31i:
writeFormat31i(writer, (Instruction31i)instruction);
break;
case Format31t:
writeFormat31t(writer, (Instruction31t)instruction);
break;
case Format32x:
writeFormat32x(writer, (Instruction32x)instruction);
break;
case Format35c:
writeFormat35c(writer, (Instruction35c)instruction);
break;
case Format3rc:
writeFormat3rc(writer, (Instruction3rc)instruction);
break;
case Format51l:
writeFormat51l(writer, (Instruction51l)instruction);
break;
case ArrayPayload:
writeArrayPayload(writer, (ArrayPayload)instruction);
break;
case SparseSwitchPayload:
writeSparseSwitchPayload(writer, (SparseSwitchPayload)instruction);
break;
case PackedSwitchPayload:
writePackedSwitchPayload(writer, (PackedSwitchPayload)instruction);
break;
default:
throw new ExceptionWithContext("Unexpected format: %s", instruction.getOpcode().format);
}
}
if (tryBlocks.size() > 0) {
writer.align();
// filter out unique lists of exception handlers
Map<List<? extends ExceptionHandler>, Integer> exceptionHandlerOffsetMap = Maps.newHashMap();
for (TryBlock tryBlock: tryBlocks) {
exceptionHandlerOffsetMap.put(tryBlock.getExceptionHandlers(), 0);
}
DexWriter.writeUleb128(ehBuf, exceptionHandlerOffsetMap.size());
for (TryBlock tryBlock: tryBlocks) {
int startAddress = tryBlock.getStartCodeAddress();
int endAddress = startAddress + tryBlock.getCodeUnitCount();
startAddress += instrWriteUtil.codeOffsetShift(startAddress);
endAddress += instrWriteUtil.codeOffsetShift(endAddress);
int tbCodeUnitCount = endAddress - startAddress;
writer.writeInt(startAddress);
writer.writeUshort(tbCodeUnitCount);
if (tryBlock.getExceptionHandlers().size() == 0) {
throw new ExceptionWithContext("No exception handlers for the try block!");
}
Integer offset = exceptionHandlerOffsetMap.get(tryBlock.getExceptionHandlers());
if (offset != 0) {
// exception handler has already been written out, just use it
writer.writeUshort(offset);
} else {
// if offset has not been set yet, we are about to write out a new exception handler
offset = ehBuf.size();
writer.writeUshort(offset);
exceptionHandlerOffsetMap.put(tryBlock.getExceptionHandlers(), offset);
// check if the last exception handler is a catch-all and adjust the size accordingly
int ehSize = tryBlock.getExceptionHandlers().size();
ExceptionHandler ehLast = tryBlock.getExceptionHandlers().get(ehSize-1);
if (ehLast.getExceptionType() == null) {
ehSize = ehSize * (-1) + 1;
}
// now let's layout the exception handlers, assuming that catch-all is always last
DexWriter.writeSleb128(ehBuf, ehSize);
for (ExceptionHandler eh : tryBlock.getExceptionHandlers()) {
String exceptionType = eh.getExceptionType();
int codeAddress = eh.getHandlerCodeAddress();
codeAddress += instrWriteUtil.codeOffsetShift(codeAddress);
if (exceptionType != null) {
//regular exception handling
DexWriter.writeUleb128(ehBuf, dexFile.typePool.getIndex(exceptionType));
DexWriter.writeUleb128(ehBuf, codeAddress);
} else {
//catch-all
DexWriter.writeUleb128(ehBuf, codeAddress);
}
}
}
}
if (ehBuf.size() > 0) {
ehBuf.writeTo(writer);
ehBuf.reset();
}
}
}
}
}
private static int packNibbles(int a, int b) {
return (b << 4) | a;
}
private int getReferenceIndex(ReferenceInstruction referenceInstruction) {
switch (referenceInstruction.getOpcode().referenceType) {
case ReferenceType.FIELD:
return dexFile.fieldPool.getIndex((FieldReference)referenceInstruction.getReference());
case ReferenceType.METHOD:
return dexFile.methodPool.getIndex((MethodReference)referenceInstruction.getReference());
case ReferenceType.STRING:
return dexFile.stringPool.getIndex((StringReference)referenceInstruction.getReference());
case ReferenceType.TYPE:
return dexFile.typePool.getIndex((TypeReference)referenceInstruction.getReference());
default:
throw new ExceptionWithContext("Unknown reference type: %d",
referenceInstruction.getOpcode().referenceType);
}
}
public void writeFormat10t(@Nonnull DexWriter writer, @Nonnull Instruction10t instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getCodeOffset());
}
public void writeFormat10x(@Nonnull DexWriter writer, @Nonnull Instruction10x instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(0);
}
public void writeFormat11n(@Nonnull DexWriter writer, @Nonnull Instruction11n instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(packNibbles(instruction.getRegisterA(), instruction.getNarrowLiteral()));
}
public void writeFormat11x(@Nonnull DexWriter writer, @Nonnull Instruction11x instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
}
public void writeFormat12x(@Nonnull DexWriter writer, @Nonnull Instruction12x instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
}
public void writeFormat20t(@Nonnull DexWriter writer, @Nonnull Instruction20t instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(0);
writer.writeShort(instruction.getCodeOffset());
}
public void writeFormat21c(@Nonnull DexWriter writer, @Nonnull Instruction21c instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeUshort(getReferenceIndex(instruction));
}
public void writeFormat21ih(@Nonnull DexWriter writer, @Nonnull Instruction21ih instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeShort(instruction.getHatLiteral());
}
public void writeFormat21lh(@Nonnull DexWriter writer, @Nonnull Instruction21lh instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeShort(instruction.getHatLiteral());
}
public void writeFormat21s(@Nonnull DexWriter writer, @Nonnull Instruction21s instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeShort(instruction.getNarrowLiteral());
}
public void writeFormat21t(@Nonnull DexWriter writer, @Nonnull Instruction21t instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeShort(instruction.getCodeOffset());
}
public void writeFormat22b(@Nonnull DexWriter writer, @Nonnull Instruction22b instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.write(instruction.getRegisterB());
writer.write(instruction.getNarrowLiteral());
}
public void writeFormat22c(@Nonnull DexWriter writer, @Nonnull Instruction22c instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
writer.writeUshort(getReferenceIndex(instruction));
}
public void writeFormat22s(@Nonnull DexWriter writer, @Nonnull Instruction22s instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
writer.writeShort(instruction.getNarrowLiteral());
}
public void writeFormat22t(@Nonnull DexWriter writer, @Nonnull Instruction22t instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
writer.writeShort(instruction.getCodeOffset());
}
public void writeFormat22x(@Nonnull DexWriter writer, @Nonnull Instruction22x instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeUshort(instruction.getRegisterB());
}
public void writeFormat23x(@Nonnull DexWriter writer, @Nonnull Instruction23x instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.write(instruction.getRegisterB());
writer.write(instruction.getRegisterC());
}
public void writeFormat30t(@Nonnull DexWriter writer, @Nonnull Instruction30t instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(0);
writer.writeInt(instruction.getCodeOffset());
}
public void writeFormat31c(@Nonnull DexWriter writer, @Nonnull Instruction31c instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeInt(getReferenceIndex(instruction));
}
public void writeFormat31i(@Nonnull DexWriter writer, @Nonnull Instruction31i instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeInt(instruction.getNarrowLiteral());
}
public void writeFormat31t(@Nonnull DexWriter writer, @Nonnull Instruction31t instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeInt(instruction.getCodeOffset());
}
public void writeFormat32x(@Nonnull DexWriter writer, @Nonnull Instruction32x instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(0);
writer.writeUshort(instruction.getRegisterA());
writer.writeUshort(instruction.getRegisterB());
}
public void writeFormat35c(@Nonnull DexWriter writer, @Nonnull Instruction35c instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(packNibbles(instruction.getRegisterG(), instruction.getRegisterCount()));
writer.writeUshort(getReferenceIndex(instruction));
writer.write(packNibbles(instruction.getRegisterC(), instruction.getRegisterD()));
writer.write(packNibbles(instruction.getRegisterE(), instruction.getRegisterF()));
}
public void writeFormat3rc(@Nonnull DexWriter writer, @Nonnull Instruction3rc instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterCount());
writer.writeUshort(getReferenceIndex(instruction));
writer.writeUshort(instruction.getStartRegister());
}
public void writeFormat51l(@Nonnull DexWriter writer, @Nonnull Instruction51l instruction) throws IOException {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeLong(instruction.getWideLiteral());
}
public void writeArrayPayload(@Nonnull DexWriter writer, @Nonnull ArrayPayload instruction) throws IOException {
writer.writeUshort(instruction.getOpcode().value);
writer.writeUshort(instruction.getElementWidth());
List<Number> elements = instruction.getArrayElements();
writer.writeInt(elements.size());
// TODO: validate that dalvik only allows these element widths
switch (instruction.getElementWidth()) {
case 1:
for (Number element: elements) {
writer.write(element.byteValue());
}
break;
case 2:
for (Number element: elements) {
writer.writeShort(element.shortValue());
}
break;
case 4:
for (Number element: elements) {
writer.writeInt(element.intValue());
}
break;
case 8:
for (Number element: elements) {
writer.writeLong(element.longValue());
}
break;
}
if ((writer.getPosition() & 1) != 0) {
writer.write(0);
}
}
public void writeSparseSwitchPayload(@Nonnull DexWriter writer, @Nonnull SparseSwitchPayload instruction)
throws IOException {
writer.writeUbyte(0);
writer.writeUbyte(instruction.getOpcode().value >> 8);
List<? extends SwitchElement> elements = instruction.getSwitchElements();
writer.writeUshort(elements.size());
for (SwitchElement element: elements) {
writer.writeInt(element.getKey());
}
for (SwitchElement element: elements) {
writer.writeInt(element.getOffset());
}
}
public void writePackedSwitchPayload(@Nonnull DexWriter writer, @Nonnull PackedSwitchPayload instruction)
throws IOException {
writer.writeUbyte(0);
writer.writeUbyte(instruction.getOpcode().value >> 8);
List<? extends SwitchElement> elements = instruction.getSwitchElements();
writer.writeUshort(elements.size());
if (elements.size() == 0) {
writer.writeInt(0);
} else {
writer.writeInt(elements.get(0).getKey());
for (SwitchElement element: elements) {
writer.writeInt(element.getOffset());
}
}
}
}

View File

@ -1,284 +0,0 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.jf.dexlib2.DebugItemType;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.MethodImplementation;
import org.jf.dexlib2.iface.MethodParameter;
import org.jf.dexlib2.iface.debug.*;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class DebugInfoPool {
@Nonnull private final Map<Method, Integer> debugInfoOffsetMap = Maps.newHashMap();
@Nonnull private final DexFile dexFile;
private int sectionOffset = -1;
public DebugInfoPool(@Nonnull DexFile dexFile) {
this.dexFile = dexFile;
}
public boolean intern(@Nonnull Method method) {
boolean hasDebugInfo = false;
for (MethodParameter param: method.getParameters()) {
String paramName = param.getName();
if (paramName != null) {
hasDebugInfo = true;
dexFile.stringPool.intern(paramName);
}
}
MethodImplementation methodImpl = method.getImplementation();
if (methodImpl != null) {
for (DebugItem debugItem: methodImpl.getDebugItems()) {
hasDebugInfo = true;
switch (debugItem.getDebugItemType()) {
case DebugItemType.START_LOCAL:
StartLocal startLocal = (StartLocal)debugItem;
dexFile.stringPool.internNullable(startLocal.getName());
dexFile.typePool.internNullable(startLocal.getType());
dexFile.stringPool.internNullable(startLocal.getSignature());
break;
case DebugItemType.SET_SOURCE_FILE:
dexFile.stringPool.internNullable(((SetSourceFile) debugItem).getSourceFile());
break;
}
}
}
if (hasDebugInfo) {
debugInfoOffsetMap.put(method, 0);
}
return hasDebugInfo;
}
public int getOffset(@Nonnull Method method) {
Integer offset = debugInfoOffsetMap.get(method);
if (offset == null) {
return 0;
}
return offset;
}
public int getNumItems() {
return debugInfoOffsetMap.size();
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
List<Method> methods = Lists.newArrayList(debugInfoOffsetMap.keySet());
Collections.sort(methods);
sectionOffset = writer.getPosition();
for (Method method: methods) {
debugInfoOffsetMap.put(method, writer.getPosition());
int startingLineNumber = 0;
MethodImplementation methodImpl = method.getImplementation();
List<DebugItem> debugItems = null;
if (methodImpl != null) {
debugItems = Lists.newArrayList(methodImpl.getDebugItems());
for (DebugItem item: debugItems) {
if (item.getDebugItemType() == DebugItemType.LINE_NUMBER) {
startingLineNumber = ((LineNumber)item).getLineNumber();
break;
}
}
}
writer.writeUleb128(startingLineNumber);
// TODO: do we need to write out all param names, even if the last n are null?
List<? extends MethodParameter> parameters = method.getParameters();
writer.writeUleb128(parameters.size());
for (MethodParameter parameter: parameters) {
writer.writeUleb128(dexFile.stringPool.getIndexNullable(parameter.getName())+1);
}
if (debugItems != null && debugItems.size() > 0) {
DebugWriter debugWriter = new DebugWriter(dexFile, writer, startingLineNumber);
for (DebugItem debugItem: debugItems) {
switch (debugItem.getDebugItemType()) {
case DebugItemType.START_LOCAL:
debugWriter.emitStartLocal((StartLocal)debugItem);
break;
case DebugItemType.END_LOCAL:
debugWriter.emitEndLocal((EndLocal)debugItem);
break;
case DebugItemType.RESTART_LOCAL:
debugWriter.emitRestartLocal((RestartLocal)debugItem);
break;
case DebugItemType.PROLOGUE_END:
debugWriter.emitPrologueEnd((PrologueEnd)debugItem);
break;
case DebugItemType.EPILOGUE_BEGIN:
debugWriter.emitEpilogueBegin((EpilogueBegin)debugItem);
break;
case DebugItemType.SET_SOURCE_FILE:
debugWriter.emitSetSourceFile((SetSourceFile)debugItem);
break;
case DebugItemType.LINE_NUMBER:
debugWriter.emitLineNumber((LineNumber)debugItem);
break;
default:
throw new ExceptionWithContext("Unexpected debug item type: %d",
debugItem.getDebugItemType());
}
}
}
// write an END_SEQUENCE opcode, to end the debug item
writer.write(0);
}
}
// TODO: add some validation here.
private static class DebugWriter {
@Nonnull private final DexFile dexFile;
@Nonnull private final DexWriter writer;
private int currentAddress = 0;
private int currentLine;
public DebugWriter(@Nonnull DexFile dexFile, @Nonnull DexWriter writer, int startLine) {
this.dexFile = dexFile;
this.writer = writer;
this.currentLine = startLine;
}
private void emitAdvancePC(int address) throws IOException {
int addressDelta = address-currentAddress;
if (addressDelta > 0) {
writer.write(1);
writer.writeUleb128(addressDelta);
currentAddress = address;
}
}
private void emitAdvanceLine(int line) throws IOException {
int lineDelta = line-currentLine;
if (lineDelta != 0) {
writer.write(2);
writer.writeSleb128(lineDelta);
currentLine = line;
}
}
public void emitLineNumber(@Nonnull LineNumber lineNumber) throws IOException {
int lineDelta = lineNumber.getLineNumber() - currentLine;
int addressDelta = lineNumber.getCodeAddress() - currentAddress;
if (lineDelta < -4 || lineDelta > 10) {
emitAdvanceLine(lineNumber.getLineNumber());
lineDelta = 0;
}
if ((lineDelta < 2 && addressDelta > 16) || (lineDelta > 1 && addressDelta > 15)) {
emitAdvancePC(lineNumber.getCodeAddress());
addressDelta = 0;
}
//TODO: need to handle the case when the line delta is larger than a signed int
emitSpecialOpcode(lineDelta, addressDelta);
}
public void emitStartLocal(@Nonnull StartLocal startLocal) throws IOException {
int nameIndex = dexFile.stringPool.getIndexNullable(startLocal.getName());
int typeIndex = dexFile.typePool.getIndexNullable(startLocal.getType());
int signatureIndex = dexFile.stringPool.getIndexNullable(startLocal.getSignature());
emitAdvancePC(startLocal.getCodeAddress());
if (signatureIndex == -1) {
writer.write(3);
writer.writeUleb128(startLocal.getRegister());
writer.writeUleb128(nameIndex+1);
writer.writeUleb128(typeIndex+1);
} else {
writer.write(4);
writer.writeUleb128(startLocal.getRegister());
writer.writeUleb128(nameIndex+1);
writer.writeUleb128(typeIndex+1);
writer.writeUleb128(signatureIndex+1);
}
}
public void emitEndLocal(@Nonnull EndLocal endLocal) throws IOException {
emitAdvancePC(endLocal.getCodeAddress());
writer.write(5);
writer.writeUleb128(endLocal.getRegister());
}
public void emitRestartLocal(@Nonnull RestartLocal restartLocal) throws IOException {
emitAdvancePC(restartLocal.getCodeAddress());
writer.write(6);
writer.writeUleb128(restartLocal.getRegister());
}
public void emitPrologueEnd(@Nonnull PrologueEnd prologueEnd) throws IOException {
emitAdvancePC(prologueEnd.getCodeAddress());
writer.write(7);
}
public void emitEpilogueBegin(@Nonnull EpilogueBegin epilogueBegin) throws IOException {
emitAdvancePC(epilogueBegin.getCodeAddress());
writer.write(8);
}
public void emitSetSourceFile(@Nonnull SetSourceFile setSourceFile) throws IOException {
emitAdvancePC(setSourceFile.getCodeAddress());
writer.write(9);
writer.writeUleb128(dexFile.stringPool.getIndexNullable(setSourceFile.getSourceFile()) + 1);
}
private static final int LINE_BASE = -4;
private static final int LINE_RANGE = 15;
private static final int FIRST_SPECIAL = 0x0a;
private void emitSpecialOpcode(int lineDelta, int addressDelta) throws IOException {
writer.write((byte)(FIRST_SPECIAL + (addressDelta * LINE_RANGE) + (lineDelta - LINE_BASE)));
currentLine += lineDelta;
currentAddress += addressDelta;
}
}
}

View File

@ -0,0 +1,163 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import org.jf.dexlib2.DebugItemType;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
public class DebugWriter<StringKey extends CharSequence, TypeKey extends CharSequence> {
@Nonnull private final StringSection<StringKey, ?> stringSection;
@Nonnull private final TypeSection<StringKey, TypeKey, ?> typeSection;
@Nonnull private final DexDataWriter writer;
private int currentAddress;
private int currentLine;
DebugWriter(@Nonnull StringSection<StringKey, ?> stringSection,
@Nonnull TypeSection<StringKey, TypeKey, ?> typeSection,
@Nonnull DexDataWriter writer) {
this.stringSection = stringSection;
this.typeSection = typeSection;
this.writer = writer;
}
void reset(int startLine) {
this.currentAddress = 0;
this.currentLine = startLine;
}
public void writeStartLocal(int codeAddress, int register,
@Nullable StringKey name,
@Nullable TypeKey type,
@Nullable StringKey signature) throws IOException {
int nameIndex = stringSection.getNullableItemIndex(name);
int typeIndex = typeSection.getNullableItemIndex(type);
int signatureIndex = stringSection.getNullableItemIndex(signature);
writeAdvancePC(codeAddress);
if (signatureIndex == DexWriter.NO_INDEX) {
writer.write(DebugItemType.START_LOCAL);
writer.writeUleb128(register);
writer.writeUleb128(nameIndex + 1);
writer.writeUleb128(typeIndex + 1);
} else {
writer.write(DebugItemType.START_LOCAL_EXTENDED);
writer.writeUleb128(register);
writer.writeUleb128(nameIndex + 1);
writer.writeUleb128(typeIndex + 1);
writer.writeUleb128(signatureIndex + 1);
}
}
public void writeEndLocal(int codeAddress, int register) throws IOException {
writeAdvancePC(codeAddress);
writer.write(DebugItemType.END_LOCAL);
writer.writeUleb128(register);
}
public void writeRestartLocal(int codeAddress, int register) throws IOException {
writeAdvancePC(codeAddress);
writer.write(DebugItemType.RESTART_LOCAL);
writer.writeUleb128(register);
}
public void writePrologueEnd(int codeAddress) throws IOException {
writeAdvancePC(codeAddress);
writer.write(DebugItemType.PROLOGUE_END);
}
public void writeEpilogueBegin(int codeAddress) throws IOException {
writeAdvancePC(codeAddress);
writer.write(DebugItemType.EPILOGUE_BEGIN);
}
public void writeLineNumber(int codeAddress, int lineNumber) throws IOException {
int lineDelta = lineNumber - currentLine;
int addressDelta = codeAddress - currentAddress;
if (addressDelta < 0) {
throw new ExceptionWithContext("debug info items must have non-decreasing code addresses");
}
if (lineDelta < -4 || lineDelta > 10) {
writeAdvanceLine(lineNumber);
lineDelta = 0;
} // no else is intentional here. we might need to advance the PC as well as the line
if ((lineDelta < 2 && addressDelta > 16) || (lineDelta > 1 && addressDelta > 15)) {
writeAdvancePC(codeAddress);
addressDelta = 0;
}
// we need to emit the special opcode even if both lineDelta and addressDelta are 0, otherwise a positions
// entry isn't generated
writeSpecialOpcode(lineDelta, addressDelta);
}
public void writeSetSourceFile(int codeAddress, @Nullable StringKey sourceFile) throws IOException {
writeAdvancePC(codeAddress);
writer.write(DebugItemType.SET_SOURCE_FILE);
writer.writeUleb128(stringSection.getNullableItemIndex(sourceFile) + 1);
}
private void writeAdvancePC(int address) throws IOException {
int addressDelta = address - currentAddress;
if (addressDelta > 0) {
writer.write(1);
writer.writeUleb128(addressDelta);
currentAddress = address;
} /*else if (addressDelta < 0) {
throw new ExceptionWithContext("debug info items must have non-decreasing code addresses");
}*/
}
private void writeAdvanceLine(int line) throws IOException {
int lineDelta = line - currentLine;
if (lineDelta != 0) {
writer.write(2);
writer.writeSleb128(lineDelta);
currentLine = line;
}
}
private static final int LINE_BASE = -4;
private static final int LINE_RANGE = 15;
private static final int FIRST_SPECIAL = 0x0a;
private void writeSpecialOpcode(int lineDelta, int addressDelta) throws IOException {
writer.write((byte)(FIRST_SPECIAL + (addressDelta * LINE_RANGE) + (lineDelta - LINE_BASE)));
currentLine += lineDelta;
currentAddress += addressDelta;
}
}

View File

@ -0,0 +1,282 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class DexDataWriter extends BufferedOutputStream {
/**
* The position within the file that we will write to next. This is only updated when the buffer is flushed to the
* outputStream.
*/
private int filePosition;
/**
* A temporary buffer that can be used for larger writes. Can be replaced with a larger buffer if needed.
* Must be at least 8 bytes
*/
private byte[] tempBuf = new byte[8];
/** A buffer of 0s to use for writing alignment values */
private byte[] zeroBuf = new byte[3];
/**
* Construct a new DexWriter instance that writes to output.
*
* @param output An OutputStream to write the data to.
* @param filePosition The position within the file that OutputStream will write to.
*/
public DexDataWriter(@Nonnull OutputStream output, int filePosition) {
this(output, filePosition, 256 * 1024);
}
public DexDataWriter(@Nonnull OutputStream output, int filePosition, int bufferSize) {
super(output, bufferSize);
this.filePosition = filePosition;
}
@Override
public void write(int b) throws IOException {
filePosition++;
super.write(b);
}
@Override
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
filePosition += len;
super.write(b, off, len);
}
public void writeLong(long value) throws IOException {
writeInt((int)value);
writeInt((int)(value >> 32));
}
public static void writeInt(OutputStream out, int value) throws IOException {
out.write(value);
out.write(value >> 8);
out.write(value >> 16);
out.write(value >> 24);
}
public void writeInt(int value) throws IOException {
writeInt(this, value);
}
public void writeShort(int value) throws IOException {
if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
throw new ExceptionWithContext("Short value out of range: %d", value);
}
write(value);
write(value >> 8);
}
public void writeUshort(int value) throws IOException {
if (value < 0 || value > 0xFFFF) {
throw new ExceptionWithContext("Unsigned short value out of range: %d", value);
}
write(value);
write(value >> 8);
}
public void writeUbyte(int value) throws IOException {
if (value < 0 || value > 0xFF) {
throw new ExceptionWithContext("Unsigned byte value out of range: %d", value);
}
write(value);
}
public static void writeUleb128(OutputStream out, int value) throws IOException {
while (value > 0x7f) {
out.write((value & 0x7f) | 0x80);
value >>>= 7;
}
out.write(value);
}
public void writeUleb128(int value) throws IOException {
writeUleb128(this, value);
}
public static void writeSleb128(OutputStream out, int value) throws IOException {
if (value >= 0) {
while (value > 0x3f) {
out.write((value & 0x7f) | 0x80);
value >>>= 7;
}
out.write(value & 0x7f);
} else {
while (value < -0x40) {
out.write((value & 0x7f) | 0x80);
value >>= 7;
}
out.write(value & 0x7f);
}
}
public void writeSleb128(int value) throws IOException {
writeSleb128(this, value);
}
public void writeEncodedValueHeader(int valueType, int valueArg) throws IOException {
write(valueType | (valueArg << 5));
}
public void writeEncodedInt(int valueType, int value) throws IOException {
int index = 0;
if (value >= 0) {
while (value > 0x7f) {
tempBuf[index++] = (byte)value;
value >>= 8;
}
} else {
while (value < -0x80) {
tempBuf[index++] = (byte)value;
value >>= 8;
}
}
tempBuf[index++] = (byte)value;
writeEncodedValueHeader(valueType, index-1);
write(tempBuf, 0, index);
}
public void writeEncodedLong(int valueType, long value) throws IOException {
int index = 0;
if (value >= 0) {
while (value > 0x7f) {
tempBuf[index++] = (byte)value;
value >>= 8;
}
} else {
while (value < -0x80) {
tempBuf[index++] = (byte)value;
value >>= 8;
}
}
tempBuf[index++] = (byte)value;
writeEncodedValueHeader(valueType, index-1);
write(tempBuf, 0, index);
}
public void writeEncodedUint(int valueType, int value) throws IOException {
int index = 0;
do {
tempBuf[index++] = (byte)value;
value >>>= 8;
} while (value != 0);
writeEncodedValueHeader(valueType, index-1);
write(tempBuf, 0, index);
}
public void writeEncodedFloat(int valueType, float value) throws IOException {
writeRightZeroExtendedInt(valueType, Float.floatToRawIntBits(value));
}
protected void writeRightZeroExtendedInt(int valueType, int value) throws IOException {
int index = 3;
do {
tempBuf[index--] = (byte)((value & 0xFF000000) >>> 24);
value <<= 8;
} while (value != 0);
int firstElement = index+1;
int encodedLength = 4-firstElement;
writeEncodedValueHeader(valueType, encodedLength - 1);
write(tempBuf, firstElement, encodedLength);
}
public void writeEncodedDouble(int valueType, double value) throws IOException {
writeRightZeroExtendedLong(valueType, Double.doubleToRawLongBits(value));
}
protected void writeRightZeroExtendedLong(int valueType, long value) throws IOException {
int index = 7;
do {
tempBuf[index--] = (byte)((value & 0xFF00000000000000L) >>> 56);
value <<= 8;
} while (value != 0);
int firstElement = index+1;
int encodedLength = 8-firstElement;
writeEncodedValueHeader(valueType, encodedLength - 1);
write(tempBuf, firstElement, encodedLength);
}
public void writeString(String string) throws IOException {
int len = string.length();
// make sure we have enough room in the temporary buffer
if (tempBuf.length <= string.length()*3) {
tempBuf = new byte[string.length()*3];
}
final byte[] buf = tempBuf;
int bufPos = 0;
for (int i = 0; i < len; i++) {
char c = string.charAt(i);
if ((c != 0) && (c < 0x80)) {
buf[bufPos++] = (byte)c;
} else if (c < 0x800) {
buf[bufPos++] = (byte)(((c >> 6) & 0x1f) | 0xc0);
buf[bufPos++] = (byte)((c & 0x3f) | 0x80);
} else {
buf[bufPos++] = (byte)(((c >> 12) & 0x0f) | 0xe0);
buf[bufPos++] = (byte)(((c >> 6) & 0x3f) | 0x80);
buf[bufPos++] = (byte)((c & 0x3f) | 0x80);
}
}
write(buf, 0, bufPos);
}
public void align() throws IOException {
int zeros = (-getPosition()) & 3;
if (zeros > 0) {
write(zeroBuf, 0, zeros);
}
}
public int getPosition() {
return filePosition;
}
}

View File

@ -1,242 +0,0 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import org.jf.dexlib2.ValueType;
import org.jf.dexlib2.iface.AnnotationElement;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.value.*;
import org.jf.util.ExceptionWithContext;
import org.jf.util.RandomAccessFileOutputStream;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.util.Collection;
import java.util.Set;
public class DexFile {
// package-private access for these
@Nonnull final StringPool stringPool = new StringPool();
@Nonnull final TypePool typePool = new TypePool(this);
@Nonnull final FieldPool fieldPool = new FieldPool(this);
@Nonnull final ProtoPool protoPool = new ProtoPool(this);
@Nonnull final MethodPool methodPool = new MethodPool(this);
@Nonnull final TypeListPool typeListPool = new TypeListPool(this);
@Nonnull final EncodedArrayPool encodedArrayPool = new EncodedArrayPool(this);
@Nonnull final AnnotationPool annotationPool = new AnnotationPool(this);
@Nonnull final AnnotationSetPool annotationSetPool = new AnnotationSetPool(this);
@Nonnull final AnnotationSetRefPool annotationSetRefPool = new AnnotationSetRefPool(this);
@Nonnull final AnnotationDirectoryPool annotationDirectoryPool = new AnnotationDirectoryPool(this);
@Nonnull final DebugInfoPool debugInfoPool = new DebugInfoPool(this);
@Nonnull final CodeItemPool codeItemPool = new CodeItemPool(this);
@Nonnull final ClassDefPool classDefPool = new ClassDefPool(this);
@Nonnull final MapItem mapItem = new MapItem(this);
@Nonnull final HeaderItem headerItem = new HeaderItem(this);
private DexFile(Set<? extends ClassDef> classes) {
for (ClassDef classDef: classes) {
classDefPool.intern(classDef);
}
}
public void writeEncodedValue(@Nonnull DexWriter writer, @Nonnull EncodedValue encodedValue) throws IOException {
int valueType = encodedValue.getValueType();
switch (valueType) {
case ValueType.ANNOTATION:
AnnotationEncodedValue annotationEncodedValue = (AnnotationEncodedValue)encodedValue;
Collection<? extends AnnotationElement> annotationElements = annotationEncodedValue.getElements();
writer.writeEncodedValueHeader(valueType, 0);
writer.writeUleb128(typePool.getIndex(annotationEncodedValue.getType()));
writer.writeUleb128(annotationElements.size());
for (AnnotationElement element: annotationElements) {
writer.writeUleb128(stringPool.getIndex(element.getName()));
writeEncodedValue(writer, element.getValue());
}
break;
case ValueType.ARRAY:
ArrayEncodedValue arrayEncodedValue = (ArrayEncodedValue)encodedValue;
Collection<? extends EncodedValue> elements = arrayEncodedValue.getValue();
writer.writeEncodedValueHeader(valueType, 0);
writer.writeUleb128(elements.size());
for (EncodedValue element: elements) {
writeEncodedValue(writer, element);
}
break;
case ValueType.BOOLEAN:
writer.writeEncodedValueHeader(valueType, (((BooleanEncodedValue)encodedValue).getValue()?1:0));
break;
case ValueType.BYTE:
writer.writeEncodedInt(valueType, ((ByteEncodedValue)encodedValue).getValue());
break;
case ValueType.CHAR:
writer.writeEncodedUint(valueType, ((CharEncodedValue)encodedValue).getValue());
break;
case ValueType.DOUBLE:
writer.writeEncodedDouble(valueType, ((DoubleEncodedValue)encodedValue).getValue());
break;
case ValueType.ENUM:
writer.writeEncodedUint(valueType, fieldPool.getIndex(((EnumEncodedValue)encodedValue).getValue()));
break;
case ValueType.FIELD:
writer.writeEncodedUint(valueType, fieldPool.getIndex(((FieldEncodedValue)encodedValue).getValue()));
break;
case ValueType.FLOAT:
writer.writeEncodedFloat(valueType, ((FloatEncodedValue)encodedValue).getValue());
break;
case ValueType.INT:
writer.writeEncodedInt(valueType, ((IntEncodedValue)encodedValue).getValue());
break;
case ValueType.LONG:
writer.writeEncodedLong(valueType, ((LongEncodedValue)encodedValue).getValue());
break;
case ValueType.METHOD:
writer.writeEncodedUint(valueType, methodPool.getIndex(((MethodEncodedValue)encodedValue).getValue()));
break;
case ValueType.NULL:
writer.write(valueType);
break;
case ValueType.SHORT:
writer.writeEncodedInt(valueType, ((ShortEncodedValue)encodedValue).getValue());
break;
case ValueType.STRING:
writer.writeEncodedUint(valueType, stringPool.getIndex(((StringEncodedValue)encodedValue).getValue()));
break;
case ValueType.TYPE:
writer.writeEncodedUint(valueType, typePool.getIndex(((TypeEncodedValue)encodedValue).getValue()));
break;
default:
throw new ExceptionWithContext("Unrecognized value type: %d", encodedValue.getValueType());
}
}
public void internEncodedValue(@Nonnull EncodedValue encodedValue) {
switch (encodedValue.getValueType()) {
case ValueType.ARRAY:
ArrayEncodedValue arrayEncodedValue = (ArrayEncodedValue)encodedValue;
for (EncodedValue value: arrayEncodedValue.getValue()) {
internEncodedValue(value);
}
return;
case ValueType.ANNOTATION:
AnnotationEncodedValue annotationEncodedValue = (AnnotationEncodedValue)encodedValue;
typePool.intern(annotationEncodedValue.getType());
for(AnnotationElement annotationElement: annotationEncodedValue.getElements()) {
stringPool.intern(annotationElement.getName());
internEncodedValue(annotationElement.getValue());
}
return;
case ValueType.STRING:
StringEncodedValue stringEncodedValue = (StringEncodedValue)encodedValue;
stringPool.intern(stringEncodedValue.getValue());
return;
case ValueType.TYPE:
TypeEncodedValue typeEncodedValue = (TypeEncodedValue)encodedValue;
typePool.intern(typeEncodedValue.getValue());
return;
case ValueType.ENUM:
EnumEncodedValue enumEncodedValue = (EnumEncodedValue)encodedValue;
fieldPool.intern(enumEncodedValue.getValue());
return;
case ValueType.FIELD:
FieldEncodedValue fieldEncodedValue = (FieldEncodedValue)encodedValue;
fieldPool.intern(fieldEncodedValue.getValue());
return;
case ValueType.METHOD:
MethodEncodedValue methodEncodedValue = (MethodEncodedValue)encodedValue;
methodPool.intern(methodEncodedValue.getValue());
return;
default:
// nothing to do
break;
}
}
private int getDataSectionOffset() {
return HeaderItem.HEADER_ITEM_SIZE +
stringPool.getIndexedSectionSize() +
typePool.getIndexedSectionSize() +
protoPool.getIndexedSectionSize() +
fieldPool.getIndexedSectionSize() +
methodPool.getIndexedSectionSize() +
classDefPool.getIndexedSectionSize();
}
private void writeTo(@Nonnull String path) throws IOException {
RandomAccessFile raf = new RandomAccessFile(path, "rw");
raf.setLength(0);
try {
int dataSectionOffset = getDataSectionOffset();
DexWriter headerWriter = outputAt(raf, 0);
DexWriter indexWriter = outputAt(raf, HeaderItem.HEADER_ITEM_SIZE);
DexWriter offsetWriter = outputAt(raf, dataSectionOffset);
try {
stringPool.write(indexWriter, offsetWriter);
typePool.write(indexWriter);
typeListPool.write(offsetWriter);
protoPool.write(indexWriter);
fieldPool.write(indexWriter);
methodPool.write(indexWriter);
encodedArrayPool.write(offsetWriter);
annotationPool.write(offsetWriter);
annotationSetPool.write(offsetWriter);
annotationSetRefPool.write(offsetWriter);
annotationDirectoryPool.write(offsetWriter);
debugInfoPool.write(offsetWriter);
codeItemPool.write(offsetWriter);
classDefPool.write(indexWriter, offsetWriter);
mapItem.write(offsetWriter);
headerItem.write(headerWriter, dataSectionOffset, offsetWriter.getPosition());
} finally {
headerWriter.close();
indexWriter.close();
offsetWriter.close();
}
FileChannel fileChannel = raf.getChannel();
headerItem.updateSignature(fileChannel);
headerItem.updateChecksum(fileChannel);
} finally {
raf.close();
}
}
private static DexWriter outputAt(RandomAccessFile raf, int filePosition) throws IOException {
return new DexWriter(new RandomAccessFileOutputStream(raf, filePosition), filePosition);
}
public static void writeTo(@Nonnull String path, @Nonnull org.jf.dexlib2.iface.DexFile input) throws IOException {
DexFile dexFile = new DexFile(input.getClasses());
dexFile.writeTo(path);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,41 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import javax.annotation.Nonnull;
import java.util.Collection;
public interface EncodedArraySection<EncodedArrayKey, EncodedValue> extends NullableOffsetSection<EncodedArrayKey> {
@Nonnull Collection<EncodedValue> getElements(@Nonnull EncodedArrayKey key);
}

View File

@ -0,0 +1,142 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import org.jf.dexlib2.ValueType;
import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.MethodReference;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.Collection;
public abstract class EncodedValueWriter<StringKey, TypeKey, FieldRefKey extends FieldReference,
MethodRefKey extends MethodReference, AnnotationElement, EncodedValue> {
@Nonnull private final DexDataWriter writer;
@Nonnull private final StringSection<StringKey, ?> stringSection;
@Nonnull private final TypeSection<?, TypeKey, ?> typeSection;
@Nonnull private final FieldSection<?, ?, FieldRefKey> fieldSection;
@Nonnull private final MethodSection<?, ?, ?, MethodRefKey> methodSection;
@Nonnull private final AnnotationSection<StringKey, TypeKey, ?, AnnotationElement, EncodedValue> annotationSection;
public EncodedValueWriter(
@Nonnull DexDataWriter writer,
@Nonnull StringSection<StringKey, ?> stringSection,
@Nonnull TypeSection<?, TypeKey, ?> typeSection,
@Nonnull FieldSection<?, ?, FieldRefKey> fieldSection,
@Nonnull MethodSection<?, ?, ?, MethodRefKey> methodSection,
@Nonnull AnnotationSection<StringKey, TypeKey, ?, AnnotationElement, EncodedValue> annotationSection) {
this.writer = writer;
this.stringSection = stringSection;
this.typeSection = typeSection;
this.fieldSection = fieldSection;
this.methodSection = methodSection;
this.annotationSection = annotationSection;
}
protected abstract void writeEncodedValue(@Nonnull EncodedValue encodedValue) throws IOException;
public void writeAnnotation(TypeKey annotationType,
Collection<? extends AnnotationElement> elements) throws IOException {
writer.writeEncodedValueHeader(ValueType.ANNOTATION, 0);
writer.writeUleb128(typeSection.getItemIndex(annotationType));
writer.writeUleb128(elements.size());
for (AnnotationElement element: elements) {
writer.writeUleb128(stringSection.getItemIndex(annotationSection.getElementName(element)));
writeEncodedValue(annotationSection.getElementValue(element));
}
}
public void writeArray(Collection<? extends EncodedValue> elements) throws IOException {
writer.writeEncodedValueHeader(ValueType.ARRAY, 0);
writer.writeUleb128(elements.size());
for (EncodedValue element: elements) {
writeEncodedValue(element);
}
}
public void writeBoolean(boolean value) throws IOException {
writer.writeEncodedValueHeader(ValueType.BOOLEAN, value ? 1 : 0);
}
public void writeByte(byte value) throws IOException {
writer.writeEncodedInt(ValueType.BYTE, value);
}
public void writeChar(char value) throws IOException {
writer.writeEncodedUint(ValueType.CHAR, value);
}
public void writeDouble(double value) throws IOException {
writer.writeEncodedDouble(ValueType.DOUBLE, value);
}
public void writeEnum(@Nonnull FieldRefKey value) throws IOException {
writer.writeEncodedUint(ValueType.ENUM, fieldSection.getItemIndex(value));
}
public void writeField(@Nonnull FieldRefKey value) throws IOException {
writer.writeEncodedUint(ValueType.FIELD, fieldSection.getItemIndex(value));
}
public void writeFloat(float value) throws IOException {
writer.writeEncodedFloat(ValueType.FLOAT, value);
}
public void writeInt(int value) throws IOException {
writer.writeEncodedInt(ValueType.INT, value);
}
public void writeLong(long value) throws IOException {
writer.writeEncodedLong(ValueType.LONG, value);
}
public void writeMethod(@Nonnull MethodRefKey value) throws IOException {
writer.writeEncodedUint(ValueType.METHOD, methodSection.getItemIndex(value));
}
public void writeNull() throws IOException {
writer.write(ValueType.NULL);
}
public void writeShort(int value) throws IOException {
writer.writeEncodedInt(ValueType.SHORT, value);
}
public void writeString(@Nonnull StringKey value) throws IOException {
writer.writeEncodedUint(ValueType.STRING, stringSection.getItemIndex(value));
}
public void writeType(@Nonnull TypeKey value) throws IOException {
writer.writeEncodedUint(ValueType.TYPE, typeSection.getItemIndex(value));
}
}

View File

@ -1,102 +0,0 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.util.ReferenceUtil;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class FieldPool {
public final static int FIELD_ID_ITEM_SIZE = 0x08;
@Nonnull private final Map<FieldReference, Integer> internedFieldIdItems = Maps.newHashMap();
@Nonnull private final DexFile dexFile;
private int sectionOffset = -1;
public FieldPool(@Nonnull DexFile dexFile) {
this.dexFile = dexFile;
}
public void intern(@Nonnull FieldReference field) {
Integer prev = internedFieldIdItems.put(field, 0);
if (prev == null) {
dexFile.typePool.intern(field.getDefiningClass());
dexFile.stringPool.intern(field.getName());
dexFile.typePool.intern(field.getType());
}
}
public int getIndex(@Nonnull FieldReference fieldReference) {
Integer index = internedFieldIdItems.get(fieldReference);
if (index == null) {
throw new ExceptionWithContext("Field not found.: %s", ReferenceUtil.getFieldDescriptor(fieldReference));
}
return index;
}
public int getIndexedSectionSize() {
return internedFieldIdItems.size() * FIELD_ID_ITEM_SIZE;
}
public int getNumItems() {
return internedFieldIdItems.size();
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
List<FieldReference> fields = Lists.newArrayList(internedFieldIdItems.keySet());
Collections.sort(fields);
sectionOffset = writer.getPosition();
int index = 0;
for (FieldReference field: fields) {
internedFieldIdItems.put(field, index++);
writer.writeUshort(dexFile.typePool.getIndex(field.getDefiningClass()));
writer.writeUshort(dexFile.typePool.getIndex(field.getType()));
writer.writeInt(dexFile.stringPool.getIndex(field.getName()));
}
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import org.jf.dexlib2.iface.reference.FieldReference;
import javax.annotation.Nonnull;
public interface FieldSection<StringKey, TypeKey, FieldRefKey extends FieldReference>
extends IndexSection<FieldRefKey> {
@Nonnull TypeKey getDefiningClass(@Nonnull FieldRefKey key);
@Nonnull TypeKey getFieldType(@Nonnull FieldRefKey key);
@Nonnull StringKey getName(@Nonnull FieldRefKey key);
}

View File

@ -1,163 +0,0 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.zip.Adler32;
public class HeaderItem {
public final static int HEADER_ITEM_SIZE = 0x70;
private static byte[] DEX_FILE_MAGIC = new byte[] {0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x35, 0x00 };
private static int LITTLE_ENDIAN = 0x12345678;
private static int CHECKSUM_SIZE = 4;
private static int SIGNATURE_SIZE = 20;
DexFile dexFile;
public HeaderItem(DexFile dexFile) {
this.dexFile = dexFile;
}
public int getSectionOffset() {
return 0;
}
public int getNumItems() {
return 1;
}
public int getSize() {
return HEADER_ITEM_SIZE;
}
public void write(DexWriter writer, int dataOffset, int fileSize) throws IOException {
writer.write(DEX_FILE_MAGIC);
// checksum placeholder
writer.writeInt(0);
// signature placeholder
writer.write(new byte[20]);
writer.writeInt(fileSize);
writer.writeInt(HEADER_ITEM_SIZE);
writer.writeInt(LITTLE_ENDIAN);
// link
writer.writeInt(0);
writer.writeInt(0);
// map
writer.writeInt(dexFile.mapItem.getSectionOffset());
// index sections
// TODO: double-check whether section offset for an empty section must be 0
writeSectionInfo(writer, dexFile.stringPool.getNumItems(), dexFile.stringPool.getIndexSectionOffset());
writeSectionInfo(writer, dexFile.typePool.getNumItems(), dexFile.typePool.getSectionOffset());
writeSectionInfo(writer, dexFile.protoPool.getNumItems(), dexFile.protoPool.getSectionOffset());
writeSectionInfo(writer, dexFile.fieldPool.getNumItems(), dexFile.fieldPool.getSectionOffset());
writeSectionInfo(writer, dexFile.methodPool.getNumItems(), dexFile.methodPool.getSectionOffset());
writeSectionInfo(writer, dexFile.classDefPool.getNumClassDefItems(), dexFile.classDefPool.getIndexSectionOffset());
// data section
writer.writeInt(fileSize - dataOffset);
writer.writeInt(dataOffset);
}
public void updateSignature(FileChannel fileChannel) throws IOException {
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-1");
} catch (NoSuchAlgorithmException ex) {
throw new RuntimeException(ex);
}
ByteBuffer buffer = ByteBuffer.allocate(128 * 1024);
fileChannel.position(DEX_FILE_MAGIC.length + CHECKSUM_SIZE + SIGNATURE_SIZE);
int bytesRead = fileChannel.read(buffer);
while (bytesRead >= 0) {
buffer.rewind();
md.update(buffer);
buffer.clear();
bytesRead = fileChannel.read(buffer);
}
byte[] signature = md.digest();
if (signature.length != SIGNATURE_SIZE) {
throw new RuntimeException("unexpected digest write: " + signature.length + " bytes");
}
// write signature
fileChannel.position(DEX_FILE_MAGIC.length + CHECKSUM_SIZE);
fileChannel.write(ByteBuffer.wrap(signature));
// flush
fileChannel.force(false);
}
public void updateChecksum(FileChannel fileChannel) throws IOException {
Adler32 a32 = new Adler32();
ByteBuffer buffer = ByteBuffer.allocate(128 * 1024);
fileChannel.position(DEX_FILE_MAGIC.length + CHECKSUM_SIZE);
int bytesRead = fileChannel.read(buffer);
while (bytesRead >= 0) {
a32.update(buffer.array(), 0, bytesRead);
buffer.clear();
bytesRead = fileChannel.read(buffer);
}
// write checksum, utilizing logic in DexWriter to write the integer value properly
fileChannel.position(DEX_FILE_MAGIC.length);
int checksum = (int) a32.getValue();
ByteArrayOutputStream checksumBuf = new ByteArrayOutputStream();
DexWriter.writeInt(checksumBuf, checksum);
fileChannel.write(ByteBuffer.wrap(checksumBuf.toByteArray()));
// flush
fileChannel.force(false);
}
private void writeSectionInfo(DexWriter writer, int numItems, int offset) throws IOException {
writer.writeInt(numItems);
if (numItems > 0) {
writer.writeInt(offset);
} else {
writer.writeInt(0);
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012, Google Inc.
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -32,9 +32,10 @@
package org.jf.dexlib2.writer;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.Map;
public class MockStringPool extends StringPool {
public void intern(@Nonnull CharSequence string, int index) {
internedStringIdItems.put(string.toString(), index);
}
public interface IndexSection<Key> {
int getItemIndex(@Nonnull Key key);
@Nonnull Collection<? extends Map.Entry<? extends Key, Integer>> getItems();
}

View File

@ -0,0 +1,76 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import org.jf.dexlib2.Opcode;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.instruction.SwitchElement;
import org.jf.dexlib2.iface.reference.Reference;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
public interface InstructionFactory<Insn extends Instruction> {
Insn makeInstruction10t(@Nonnull Opcode opcode, int codeOffset);
Insn makeInstruction10x(@Nonnull Opcode opcode);
Insn makeInstruction11n(@Nonnull Opcode opcode, int registerA, int literal);
Insn makeInstruction11x(@Nonnull Opcode opcode, int registerA);
Insn makeInstruction12x(@Nonnull Opcode opcode, int registerA, int registerB);
Insn makeInstruction20bc(@Nonnull Opcode opcode, int verificationError, @Nonnull Reference reference);
Insn makeInstruction20t(@Nonnull Opcode opcode, int codeOffset);
Insn makeInstruction21c(@Nonnull Opcode opcode, int registerA, @Nonnull Reference reference);
Insn makeInstruction21ih(@Nonnull Opcode opcode, int registerA, int literal);
Insn makeInstruction21lh(@Nonnull Opcode opcode, int registerA, long literal);
Insn makeInstruction21s(@Nonnull Opcode opcode, int registerA, int literal);
Insn makeInstruction21t(@Nonnull Opcode opcode, int registerA, int codeOffset);
Insn makeInstruction22b(@Nonnull Opcode opcode, int registerA, int registerB, int literal);
Insn makeInstruction22c(@Nonnull Opcode opcode, int registerA, int registerB, @Nonnull Reference reference);
Insn makeInstruction22s(@Nonnull Opcode opcode, int registerA, int registerB, int literal);
Insn makeInstruction22t(@Nonnull Opcode opcode, int registerA, int registerB, int codeOffset);
Insn makeInstruction22x(@Nonnull Opcode opcode, int registerA, int registerB);
Insn makeInstruction23x(@Nonnull Opcode opcode, int registerA, int registerB, int registerC);
Insn makeInstruction30t(@Nonnull Opcode opcode, int codeOffset);
Insn makeInstruction31c(@Nonnull Opcode opcode, int registerA, @Nonnull Reference reference);
Insn makeInstruction31i(@Nonnull Opcode opcode, int registerA, int literal);
Insn makeInstruction31t(@Nonnull Opcode opcode, int registerA, int codeOffset);
Insn makeInstruction32x(@Nonnull Opcode opcode, int registerA, int registerB);
Insn makeInstruction35c(@Nonnull Opcode opcode, int registerCount, int registerC, int registerD, int registerE,
int registerF, int registerG, @Nonnull Reference reference);
Insn makeInstruction3rc(@Nonnull Opcode opcode, int startRegister, int registerCount,
@Nonnull Reference reference);
Insn makeInstruction51l(@Nonnull Opcode opcode, int registerA, long literal);
Insn makeSparseSwitchPayload(@Nullable List<? extends SwitchElement> switchElements);
Insn makePackedSwitchPayload(@Nullable List<? extends SwitchElement> switchElements);
Insn makeArrayPayload(int elementWidth, @Nullable List<Number> arrayElements);
}

View File

@ -0,0 +1,432 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import org.jf.dexlib2.ReferenceType;
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
import org.jf.dexlib2.iface.instruction.SwitchElement;
import org.jf.dexlib2.iface.instruction.formats.*;
import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.iface.reference.StringReference;
import org.jf.dexlib2.iface.reference.TypeReference;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.List;
public class InstructionWriter<StringRef extends StringReference, TypeRef extends TypeReference,
FieldRefKey extends FieldReference, MethodRefKey extends MethodReference> {
@Nonnull private final DexDataWriter writer;
@Nonnull private final StringSection<?, StringRef> stringSection;
@Nonnull private final TypeSection<?, ?, TypeRef> typeSection;
@Nonnull private final FieldSection<?, ?, FieldRefKey> fieldSection;
@Nonnull private final MethodSection<?, ?, ?, MethodRefKey> methodSection;
@Nonnull static <StringRef extends StringReference, TypeRef extends TypeReference, FieldRefKey extends FieldReference, MethodRefKey extends MethodReference>
InstructionWriter<StringRef, TypeRef, FieldRefKey, MethodRefKey>
makeInstructionWriter(
@Nonnull DexDataWriter writer,
@Nonnull StringSection<?, StringRef> stringSection,
@Nonnull TypeSection<?, ?, TypeRef> typeSection,
@Nonnull FieldSection<?, ?, FieldRefKey> fieldSection,
@Nonnull MethodSection<?, ?, ?, MethodRefKey> methodSection) {
return new InstructionWriter<StringRef, TypeRef, FieldRefKey, MethodRefKey>(
writer, stringSection, typeSection, fieldSection, methodSection);
}
InstructionWriter(@Nonnull DexDataWriter writer,
@Nonnull StringSection<?, StringRef> stringSection,
@Nonnull TypeSection<?, ?, TypeRef> typeSection,
@Nonnull FieldSection<?, ?, FieldRefKey> fieldSection,
@Nonnull MethodSection<?, ?, ?, MethodRefKey> methodSection) {
this.writer = writer;
this.stringSection = stringSection;
this.typeSection = typeSection;
this.fieldSection = fieldSection;
this.methodSection = methodSection;
}
public void write(@Nonnull Instruction10t instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getCodeOffset());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction10x instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(0);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction11n instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(packNibbles(instruction.getRegisterA(), instruction.getNarrowLiteral()));
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction11x instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction12x instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction20bc instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getVerificationError());
writer.writeUshort(getReferenceIndex(instruction));
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction20t instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(0);
writer.writeShort(instruction.getCodeOffset());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction21c instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeUshort(getReferenceIndex(instruction));
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction21ih instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeShort(instruction.getHatLiteral());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction21lh instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeShort(instruction.getHatLiteral());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction21s instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeShort(instruction.getNarrowLiteral());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction21t instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeShort(instruction.getCodeOffset());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction22b instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.write(instruction.getRegisterB());
writer.write(instruction.getNarrowLiteral());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction22c instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
writer.writeUshort(getReferenceIndex(instruction));
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction22s instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
writer.writeShort(instruction.getNarrowLiteral());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction22t instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(packNibbles(instruction.getRegisterA(), instruction.getRegisterB()));
writer.writeShort(instruction.getCodeOffset());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction22x instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeUshort(instruction.getRegisterB());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction23x instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.write(instruction.getRegisterB());
writer.write(instruction.getRegisterC());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction30t instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(0);
writer.writeInt(instruction.getCodeOffset());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction31c instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeInt(getReferenceIndex(instruction));
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction31i instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeInt(instruction.getNarrowLiteral());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction31t instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeInt(instruction.getCodeOffset());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction32x instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(0);
writer.writeUshort(instruction.getRegisterA());
writer.writeUshort(instruction.getRegisterB());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction35c instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(packNibbles(instruction.getRegisterG(), instruction.getRegisterCount()));
writer.writeUshort(getReferenceIndex(instruction));
writer.write(packNibbles(instruction.getRegisterC(), instruction.getRegisterD()));
writer.write(packNibbles(instruction.getRegisterE(), instruction.getRegisterF()));
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction3rc instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterCount());
writer.writeUshort(getReferenceIndex(instruction));
writer.writeUshort(instruction.getStartRegister());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull Instruction51l instruction) {
try {
writer.write(instruction.getOpcode().value);
writer.write(instruction.getRegisterA());
writer.writeLong(instruction.getWideLiteral());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull ArrayPayload instruction) {
try {
writer.writeUshort(instruction.getOpcode().value);
writer.writeUshort(instruction.getElementWidth());
List<Number> elements = instruction.getArrayElements();
writer.writeInt(elements.size());
switch (instruction.getElementWidth()) {
case 1:
for (Number element: elements) {
writer.write(element.byteValue());
}
break;
case 2:
for (Number element: elements) {
writer.writeShort(element.shortValue());
}
break;
case 4:
for (Number element: elements) {
writer.writeInt(element.intValue());
}
break;
case 8:
for (Number element: elements) {
writer.writeLong(element.longValue());
}
break;
}
if ((writer.getPosition() & 1) != 0) {
writer.write(0);
}
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull SparseSwitchPayload instruction) {
try {
writer.writeUbyte(0);
writer.writeUbyte(instruction.getOpcode().value >> 8);
List<? extends SwitchElement> elements = instruction.getSwitchElements();
writer.writeUshort(elements.size());
for (SwitchElement element: elements) {
writer.writeInt(element.getKey());
}
for (SwitchElement element: elements) {
writer.writeInt(element.getOffset());
}
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void write(@Nonnull PackedSwitchPayload instruction) {
try {
writer.writeUbyte(0);
writer.writeUbyte(instruction.getOpcode().value >> 8);
List<? extends SwitchElement> elements = instruction.getSwitchElements();
writer.writeUshort(elements.size());
if (elements.size() == 0) {
writer.writeInt(0);
} else {
writer.writeInt(elements.get(0).getKey());
for (SwitchElement element: elements) {
writer.writeInt(element.getOffset());
}
}
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
private static int packNibbles(int a, int b) {
return (b << 4) | a;
}
private int getReferenceIndex(ReferenceInstruction referenceInstruction) {
switch (referenceInstruction.getOpcode().referenceType) {
case ReferenceType.FIELD:
return fieldSection.getItemIndex((FieldRefKey)referenceInstruction.getReference());
case ReferenceType.METHOD:
return methodSection.getItemIndex((MethodRefKey)referenceInstruction.getReference());
case ReferenceType.STRING:
return stringSection.getItemIndex((StringRef)referenceInstruction.getReference());
case ReferenceType.TYPE:
return typeSection.getItemIndex((TypeRef)referenceInstruction.getReference());
default:
throw new ExceptionWithContext("Unknown reference type: %d",
referenceInstruction.getOpcode().referenceType);
}
}
}

View File

@ -1,150 +0,0 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import org.jf.dexlib2.dexbacked.raw.ItemType;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import java.io.IOException;
public class MapItem {
DexFile dexFile;
private int sectionOffset = -1;
public MapItem(DexFile dexFile) {
this.dexFile = dexFile;
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
writer.align();
sectionOffset = writer.getPosition();
int numItems = calcNumItems();
writer.writeInt(numItems);
// index section
writeItem(writer, ItemType.HEADER_ITEM, 1, 0);
writeItem(writer, ItemType.STRING_ID_ITEM, dexFile.stringPool.getNumItems(), dexFile.stringPool.getIndexSectionOffset());
writeItem(writer, ItemType.TYPE_ID_ITEM, dexFile.typePool.getNumItems(), dexFile.typePool.getSectionOffset());
writeItem(writer, ItemType.PROTO_ID_ITEM, dexFile.protoPool.getNumItems(), dexFile.protoPool.getSectionOffset());
writeItem(writer, ItemType.FIELD_ID_ITEM, dexFile.fieldPool.getNumItems(), dexFile.fieldPool.getSectionOffset());
writeItem(writer, ItemType.METHOD_ID_ITEM, dexFile.methodPool.getNumItems(), dexFile.methodPool.getSectionOffset());
writeItem(writer, ItemType.CLASS_DEF_ITEM, dexFile.classDefPool.getNumClassDefItems(), dexFile.classDefPool.getIndexSectionOffset());
// data section
writeItem(writer, ItemType.STRING_DATA_ITEM, dexFile.stringPool.getNumItems(), dexFile.stringPool.getDataSectionOffset());
writeItem(writer, ItemType.TYPE_LIST, dexFile.typeListPool.getNumItems(), dexFile.typeListPool.getSectionOffset());
writeItem(writer, ItemType.ENCODED_ARRAY_ITEM, dexFile.encodedArrayPool.getNumItems(), dexFile.encodedArrayPool.getSectionOffset());
writeItem(writer, ItemType.ANNOTATION_ITEM, dexFile.annotationPool.getNumItems(), dexFile.annotationPool.getSectionOffset());
writeItem(writer, ItemType.ANNOTATION_SET_ITEM, dexFile.annotationSetPool.getNumItems(), dexFile.annotationSetPool.getSectionOffset());
writeItem(writer, ItemType.ANNOTATION_SET_REF_LIST, dexFile.annotationSetRefPool.getNumItems(), dexFile.annotationSetRefPool.getSectionOffset());
writeItem(writer, ItemType.ANNOTATION_DIRECTORY_ITEM, dexFile.annotationDirectoryPool.getNumItems(), dexFile.annotationDirectoryPool.getSectionOffset());
writeItem(writer, ItemType.DEBUG_INFO_ITEM, dexFile.debugInfoPool.getNumItems(), dexFile.debugInfoPool.getSectionOffset());
writeItem(writer, ItemType.CODE_ITEM, dexFile.codeItemPool.getNumItems(), dexFile.codeItemPool.getSectionOffset());
writeItem(writer, ItemType.CLASS_DATA_ITEM, dexFile.classDefPool.getNumClassDataItems(), dexFile.classDefPool.getDataSectionOffset());
writeItem(writer, ItemType.MAP_LIST, 1, sectionOffset);
}
private int calcNumItems() {
int numItems = 0;
// header item
numItems++;
if (dexFile.stringPool.getNumItems() > 0) {
numItems += 2; // index and data
}
if (dexFile.typePool.getNumItems() > 0) {
numItems++;
}
if (dexFile.protoPool.getNumItems() > 0) {
numItems++;
}
if (dexFile.fieldPool.getNumItems() > 0) {
numItems++;
}
if (dexFile.methodPool.getNumItems() > 0) {
numItems++;
}
if (dexFile.typeListPool.getNumItems() > 0) {
numItems++;
}
if (dexFile.encodedArrayPool.getNumItems() > 0) {
numItems++;
}
if (dexFile.annotationPool.getNumItems() > 0) {
numItems++;
}
if (dexFile.annotationSetPool.getNumItems() > 0) {
numItems++;
}
if (dexFile.annotationSetRefPool.getNumItems() > 0) {
numItems++;
}
if (dexFile.annotationDirectoryPool.getNumItems() > 0) {
numItems++;
}
if (dexFile.debugInfoPool.getNumItems() > 0) {
numItems++;
}
if (dexFile.codeItemPool.getNumItems() > 0) {
numItems++;
}
if (dexFile.classDefPool.getNumClassDefItems() > 0) {
numItems++;
}
if (dexFile.classDefPool.getNumClassDataItems() > 0) {
numItems++;
}
// map item itself
numItems++;
return numItems;
}
private void writeItem(DexWriter writer, int type, int size, int offset) throws IOException {
if (size > 0) {
writer.writeUshort(type);
writer.writeUshort(0);
writer.writeInt(size);
writer.writeInt(offset);
}
}
}

View File

@ -1,102 +0,0 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.util.ReferenceUtil;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class MethodPool {
public final static int METHOD_ID_ITEM_SIZE = 0x08;
@Nonnull private final Map<MethodReference, Integer> internedMethodIdItems = Maps.newHashMap();
@Nonnull private final DexFile dexFile;
private int sectionOffset = -1;
public MethodPool(@Nonnull DexFile dexFile) {
this.dexFile = dexFile;
}
public void intern(@Nonnull MethodReference method) {
Integer prev = internedMethodIdItems.put(method, 0);
if (prev == null) {
dexFile.typePool.intern(method.getDefiningClass());
dexFile.protoPool.intern(method);
dexFile.stringPool.intern(method.getName());
}
}
public int getIndex(@Nonnull MethodReference methodReference) {
Integer index = internedMethodIdItems.get(methodReference);
if (index == null) {
throw new ExceptionWithContext("Method not found.: %s", ReferenceUtil.getMethodDescriptor(methodReference));
}
return index;
}
public int getIndexedSectionSize() {
return internedMethodIdItems.size() * METHOD_ID_ITEM_SIZE;
}
public int getNumItems() {
return internedMethodIdItems.size();
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
List<MethodReference> methods = Lists.newArrayList(internedMethodIdItems.keySet());
Collections.sort(methods);
sectionOffset = writer.getPosition();
int index = 0;
for (MethodReference method: methods) {
internedMethodIdItems.put(method, index++);
writer.writeUshort(dexFile.typePool.getIndex(method.getDefiningClass()));
writer.writeUshort(dexFile.protoPool.getIndex(method));
writer.writeInt(dexFile.stringPool.getIndex(method.getName()));
}
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import org.jf.dexlib2.iface.reference.MethodReference;
import javax.annotation.Nonnull;
public interface MethodSection<StringKey, TypeKey, ProtoKey, MethodRefKey extends MethodReference>
extends IndexSection<MethodRefKey> {
@Nonnull TypeKey getDefiningClass(@Nonnull MethodRefKey key);
@Nonnull ProtoKey getPrototype(@Nonnull MethodRefKey key);
@Nonnull StringKey getName(@Nonnull MethodRefKey key);
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import javax.annotation.Nullable;
public interface NullableIndexSection<Key> extends IndexSection<Key> {
int getNullableItemIndex(@Nullable Key key);
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import javax.annotation.Nullable;
public interface NullableOffsetSection<Key> extends OffsetSection<Key> {
int getNullableItemOffset(@Nullable Key key);
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.Map;
public interface OffsetSection<Key> {
int getItemOffset(@Nonnull Key key);
@Nonnull Collection<? extends Map.Entry<? extends Key, Integer>> getItems();
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public interface ProtoSection<StringKey, TypeKey, ProtoKey, TypeListKey> extends IndexSection<ProtoKey> {
@Nonnull StringKey getShorty(@Nonnull ProtoKey key);
@Nonnull TypeKey getReturnType(@Nonnull ProtoKey key);
@Nullable TypeListKey getParameters(@Nonnull ProtoKey key);
}

View File

@ -1,111 +0,0 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.jf.util.ExceptionWithContext;
import org.jf.util.StringUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class StringPool {
public final static int STRING_ID_ITEM_SIZE = 0x04;
@Nonnull protected final Map<String, Integer> internedStringIdItems = Maps.newHashMap();
private int indexSectionOffset = -1;
private int dataSectionOffset = -1;
public void intern(@Nonnull CharSequence string) {
internedStringIdItems.put(string.toString(), 0);
}
public void internNullable(@Nullable CharSequence string) {
if (string != null) {
intern(string);
}
}
public int getIndex(@Nonnull CharSequence string) {
Integer index = internedStringIdItems.get(string.toString());
if (index == null) {
throw new ExceptionWithContext("String not found.: %s",
StringUtils.escapeString(string.toString()));
}
return index;
}
public int getIndexNullable(@Nullable CharSequence string) {
if (string == null) {
return -1;
}
return getIndex(string);
}
public int getIndexedSectionSize() {
return internedStringIdItems.size() * STRING_ID_ITEM_SIZE;
}
public int getNumItems() {
return internedStringIdItems.size();
}
public int getIndexSectionOffset() {
return indexSectionOffset;
}
public int getDataSectionOffset() {
return dataSectionOffset;
}
public void write(@Nonnull DexWriter indexWriter, @Nonnull DexWriter offsetWriter) throws IOException {
List<String> strings = Lists.newArrayList(internedStringIdItems.keySet());
Collections.sort(strings);
indexSectionOffset = indexWriter.getPosition();
dataSectionOffset = offsetWriter.getPosition();
int index = 0;
for (String string: strings) {
internedStringIdItems.put(string, index++);
indexWriter.writeInt(offsetWriter.getPosition());
offsetWriter.writeUleb128(string.length());
offsetWriter.writeString(string);
offsetWriter.write(0);
}
}
}

View File

@ -0,0 +1,39 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import org.jf.dexlib2.iface.reference.StringReference;
import org.jf.dexlib2.writer.util.InstructionWriteUtil;
public interface StringSection<StringKey, StringRef extends StringReference> extends NullableIndexSection<StringKey>,
InstructionWriteUtil.StringIndexProvider<StringRef> {
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collection;
public interface TypeListSection<TypeKey, TypeListKey> extends NullableOffsetSection<TypeListKey> {
int getNullableItemOffset(@Nullable TypeListKey index);
@Nonnull Collection<? extends TypeKey> getTypes(@Nullable TypeListKey key);
}

View File

@ -1,111 +0,0 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class TypePool {
public final static int TYPE_ID_ITEM_SIZE = 0x04;
@Nonnull private final Map<String, Integer> internedTypeIdItems = Maps.newHashMap();
@Nonnull private final DexFile dexFile;
private int sectionOffset = -1;
public TypePool(@Nonnull DexFile dexFile) {
this.dexFile = dexFile;
}
public void intern(@Nonnull CharSequence type) {
Integer prev = internedTypeIdItems.put(type.toString(), 0);
if (prev == null) {
dexFile.stringPool.intern(type);
}
}
public void internNullable(@Nullable CharSequence type) {
if (type != null) {
intern(type);
}
}
public int getIndex(@Nonnull CharSequence type) {
Integer index = internedTypeIdItems.get(type.toString());
if (index == null) {
throw new ExceptionWithContext("Type not found.: %s", type);
}
return index;
}
public int getIndexNullable(@Nullable CharSequence type) {
if (type == null) {
return -1;
}
return getIndex(type);
}
public int getIndexedSectionSize() {
return internedTypeIdItems.size() * TYPE_ID_ITEM_SIZE;
}
public int getNumItems() {
return internedTypeIdItems.size();
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
List<String> types = Lists.newArrayList(internedTypeIdItems.keySet());
Collections.sort(types);
sectionOffset = writer.getPosition();
int index = 0;
for (String type: types) {
internedTypeIdItems.put(type, index++);
int stringIndex = dexFile.stringPool.getIndex(type);
writer.writeInt(stringIndex);
}
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import org.jf.dexlib2.iface.reference.TypeReference;
import javax.annotation.Nonnull;
public interface TypeSection<StringKey, TypeKey, TypeRef extends TypeReference> extends NullableIndexSection<TypeKey> {
@Nonnull StringKey getString(@Nonnull TypeKey key);
int getItemIndex(@Nonnull TypeReference key);
}

View File

@ -0,0 +1,87 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer.pool;
import org.jf.dexlib2.iface.Annotation;
import org.jf.dexlib2.iface.AnnotationElement;
import org.jf.dexlib2.iface.value.EncodedValue;
import org.jf.dexlib2.writer.AnnotationSection;
import javax.annotation.Nonnull;
import java.util.Collection;
public class AnnotationPool extends BaseOffsetPool<Annotation>
implements AnnotationSection<CharSequence, CharSequence, Annotation, AnnotationElement, EncodedValue> {
@Nonnull StringPool stringPool;
@Nonnull TypePool typePool;
@Nonnull FieldPool fieldPool;
@Nonnull MethodPool methodPool;
public AnnotationPool(@Nonnull StringPool stringPool, @Nonnull TypePool typePool,
@Nonnull FieldPool fieldPool, @Nonnull MethodPool methodPool) {
this.stringPool = stringPool;
this.typePool = typePool;
this.fieldPool = fieldPool;
this.methodPool = methodPool;
}
public void intern(@Nonnull Annotation annotation) {
Integer prev = internedItems.put(annotation, 0);
if (prev == null) {
typePool.intern(annotation.getType());
for (AnnotationElement element: annotation.getElements()) {
stringPool.intern(element.getName());
DexPool.internEncodedValue(element.getValue(), stringPool, typePool, fieldPool, methodPool);
}
}
}
@Override public int getVisibility(@Nonnull Annotation annotation) {
return annotation.getVisibility();
}
@Nonnull @Override public CharSequence getType(@Nonnull Annotation annotation) {
return annotation.getType();
}
@Nonnull @Override public Collection<? extends AnnotationElement> getElements(@Nonnull Annotation annotation) {
return annotation.getElements();
}
@Nonnull @Override public CharSequence getElementName(@Nonnull AnnotationElement annotationElement) {
return annotationElement.getName();
}
@Nonnull @Override public EncodedValue getElementValue(@Nonnull AnnotationElement annotationElement) {
return annotationElement.getValue();
}
}

View File

@ -0,0 +1,64 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer.pool;
import org.jf.dexlib2.iface.Annotation;
import org.jf.dexlib2.writer.AnnotationSetSection;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.Set;
public class AnnotationSetPool extends BaseNullableOffsetPool<Set<? extends Annotation>>
implements AnnotationSetSection<Annotation, Set<? extends Annotation>> {
@Nonnull private final AnnotationPool annotationPool;
public AnnotationSetPool(@Nonnull AnnotationPool annotationPool) {
this.annotationPool = annotationPool;
}
public void intern(@Nonnull Set<? extends Annotation> annotationSet) {
if (annotationSet.size() > 0) {
Integer prev = internedItems.put(annotationSet, 0);
if (prev == null) {
for (Annotation annotation: annotationSet) {
annotationPool.intern(annotation);
}
}
}
}
@Nonnull @Override public Collection<? extends Annotation> getAnnotations(
@Nonnull Set<? extends Annotation> annotations) {
return annotations;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012, Google Inc.
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -29,82 +29,49 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
package org.jf.dexlib2.writer.pool;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import com.google.common.primitives.Ints;
import org.jf.dexlib2.iface.Annotation;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.MethodParameter;
import org.jf.dexlib2.writer.pool.AnnotationSetRefPool.Key;
import org.jf.dexlib2.writer.AnnotationSetRefSection;
import org.jf.util.CollectionUtils;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.*;
import java.util.AbstractCollection;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
public class AnnotationSetRefPool {
@Nonnull private final Map<Key, Integer> internedAnnotationSetRefItems = Maps.newHashMap();
@Nonnull private final DexFile dexFile;
private int sectionOffset = -1;
public class AnnotationSetRefPool extends BaseNullableOffsetPool<Key>
implements AnnotationSetRefSection<Set<? extends Annotation>, Key> {
@Nonnull private final AnnotationSetPool annotationSetPool;
public AnnotationSetRefPool(@Nonnull DexFile dexFile) {
this.dexFile = dexFile;
public AnnotationSetRefPool(@Nonnull AnnotationSetPool annotationSetPool) {
this.annotationSetPool = annotationSetPool;
}
public void intern(@Nonnull Method method) {
Key annotationSetRefKey = new Key(method);
Integer prev = internedAnnotationSetRefItems.put(annotationSetRefKey, 0);
Integer prev = internedItems.put(annotationSetRefKey, 0);
if (prev == null) {
for (Set<? extends Annotation> annotationSet: annotationSetRefKey.getAnnotationSets()) {
dexFile.annotationSetPool.intern(annotationSet);
annotationSetPool.intern(annotationSet);
}
}
}
public int getOffset(@Nonnull Method method) {
Key annotationSetRefKey = new Key(method);
Integer offset = internedAnnotationSetRefItems.get(annotationSetRefKey);
if (offset == null) {
throw new ExceptionWithContext("Annotation set ref not found.");
}
return offset;
@Nonnull @Override public Collection<Set<? extends Annotation>> getAnnotationSets(@Nonnull Key key) {
return key.getAnnotationSets();
}
public int getNumItems() {
return internedAnnotationSetRefItems.size();
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
List<Key> annotationSetRefs =
Lists.newArrayList(internedAnnotationSetRefItems.keySet());
Collections.sort(annotationSetRefs);
writer.align();
sectionOffset = writer.getPosition();
for (Key key: annotationSetRefs) {
writer.align();
internedAnnotationSetRefItems.put(key, writer.getPosition());
writer.writeInt(key.getAnnotationSetCount());
for (Set<? extends Annotation> annotationSet: key.getAnnotationSets()) {
writer.writeInt(dexFile.annotationSetPool.getOffset(annotationSet));
}
}
}
private static class Key implements Comparable<Key> {
public static class Key implements Comparable<Key> {
@Nonnull private final Method method;
private final int size;
@ -113,14 +80,18 @@ public class AnnotationSetRefPool {
this.size = CollectionUtils.lastIndexOf(method.getParameters(), HAS_ANNOTATIONS) + 1;
}
public int getAnnotationSetCount() {
return size;
}
public Collection<Set<? extends Annotation>> getAnnotationSets() {
return new AbstractCollection<Set<? extends Annotation>>() {
@Nonnull @Override public Iterator<Set<? extends Annotation>> iterator() {
return FluentIterable.from(method.getParameters())
.limit(size)
.transform(PARAMETER_ANNOTATIONS).iterator();
}
public Iterable<Set<? extends Annotation>> getAnnotationSets() {
return FluentIterable.from(method.getParameters())
.limit(size)
.transform(PARAMETER_ANNOTATIONS);
@Override public int size() {
return size;
}
};
}
@Override

View File

@ -0,0 +1,60 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer.pool;
import com.google.common.collect.Maps;
import org.jf.dexlib2.writer.IndexSection;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.Map;
public abstract class BaseIndexPool<Key> implements IndexSection<Key> {
@Nonnull protected final Map<Key, Integer> internedItems = Maps.newHashMap();
@Nonnull @Override public Collection<? extends Map.Entry<? extends Key, Integer>> getItems() {
return internedItems.entrySet();
}
@Override public int getItemIndex(@Nonnull Key key) {
Integer index = internedItems.get(key);
if (index == null) {
throw new ExceptionWithContext("Item not found.: %s", getItemString(key));
}
return index;
}
@Nonnull protected String getItemString(@Nonnull Key key) {
return key.toString();
}
}

View File

@ -0,0 +1,47 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer.pool;
import org.jf.dexlib2.writer.DexWriter;
import org.jf.dexlib2.writer.NullableOffsetSection;
import javax.annotation.Nullable;
public abstract class BaseNullableOffsetPool<Key> extends BaseOffsetPool<Key>
implements NullableOffsetSection<Key> {
@Override public int getNullableItemOffset(@Nullable Key key) {
if (key == null) {
return DexWriter.NO_OFFSET;
}
return getItemOffset(key);
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer.pool;
import com.google.common.collect.Maps;
import org.jf.dexlib2.writer.OffsetSection;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.Map;
public abstract class BaseOffsetPool<Key> implements OffsetSection<Key> {
@Nonnull protected final Map<Key, Integer> internedItems = Maps.newHashMap();
@Nonnull @Override public Collection<? extends Map.Entry<? extends Key, Integer>> getItems() {
return internedItems.entrySet();
}
@Override public int getItemOffset(@Nonnull Key key) {
Integer offset = internedItems.get(key);
if (offset == null) {
throw new ExceptionWithContext("Item not found.: %s", getItemString(key));
}
return offset;
}
@Nonnull protected String getItemString(@Nonnull Key key) {
return key.toString();
}
}

View File

@ -0,0 +1,480 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer.pool;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import org.jf.dexlib2.DebugItemType;
import org.jf.dexlib2.ReferenceType;
import org.jf.dexlib2.iface.*;
import org.jf.dexlib2.iface.debug.*;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
import org.jf.dexlib2.iface.reference.*;
import org.jf.dexlib2.util.ReferenceUtil;
import org.jf.dexlib2.writer.ClassSection;
import org.jf.dexlib2.writer.DebugWriter;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;
public class ClassPool implements ClassSection<CharSequence, CharSequence,
TypeListPool.Key<? extends Collection<? extends CharSequence>>, PoolClassDef, Field, PoolMethod,
Set<? extends Annotation>, AnnotationSetRefPool.Key, EncodedArrayPool.Key,
DebugItem, Instruction, ExceptionHandler> {
@Nonnull private HashMap<String, PoolClassDef> internedItems = Maps.newHashMap();
@Nonnull private final StringPool stringPool;
@Nonnull private final TypePool typePool;
@Nonnull private final FieldPool fieldPool;
@Nonnull private final MethodPool methodPool;
@Nonnull private final AnnotationSetPool annotationSetPool;
@Nonnull private final AnnotationSetRefPool annotationSetRefPool;
@Nonnull private final TypeListPool typeListPool;
@Nonnull private final EncodedArrayPool encodedArrayPool;
public ClassPool(@Nonnull StringPool stringPool,
@Nonnull TypePool typePool,
@Nonnull FieldPool fieldPool,
@Nonnull MethodPool methodPool,
@Nonnull AnnotationSetPool annotationSetPool,
@Nonnull AnnotationSetRefPool annotationSetRefPool,
@Nonnull TypeListPool typeListPool,
@Nonnull EncodedArrayPool encodedArrayPool) {
this.stringPool = stringPool;
this.typePool = typePool;
this.fieldPool = fieldPool;
this.methodPool = methodPool;
this.annotationSetPool = annotationSetPool;
this.annotationSetRefPool = annotationSetRefPool;
this.typeListPool = typeListPool;
this.encodedArrayPool = encodedArrayPool;
}
public void intern(@Nonnull ClassDef classDef) {
PoolClassDef poolClassDef = new PoolClassDef(classDef);
PoolClassDef prev = internedItems.put(poolClassDef.getType(), poolClassDef);
if (prev != null) {
throw new ExceptionWithContext("Class %s has already been interned", poolClassDef.getType());
}
typePool.intern(poolClassDef.getType());
typePool.internNullable(poolClassDef.getSuperclass());
typeListPool.intern(poolClassDef.getInterfaces());
stringPool.internNullable(poolClassDef.getSourceFile());
encodedArrayPool.intern(poolClassDef);
HashSet<String> fields = new HashSet<String>();
for (Field field: poolClassDef.getFields()) {
String fieldDescriptor = ReferenceUtil.getShortFieldDescriptor(field);
if (!fields.add(fieldDescriptor)) {
throw new ExceptionWithContext("Multiple definitions for field %s->%s",
poolClassDef.getType(), fieldDescriptor);
}
fieldPool.intern(field);
annotationSetPool.intern(field.getAnnotations());
}
HashSet<String> methods = new HashSet<String>();
for (PoolMethod method: poolClassDef.getMethods()) {
String methodDescriptor = ReferenceUtil.getShortMethodDescriptor(method);
if (!methods.add(methodDescriptor)) {
throw new ExceptionWithContext("Multiple definitions for method %s->%s",
poolClassDef.getType(), methodDescriptor);
}
methodPool.intern(method);
internCode(method);
internDebug(method);
annotationSetPool.intern(method.getAnnotations());
annotationSetRefPool.intern(method);
}
annotationSetPool.intern(poolClassDef.getAnnotations());
}
private void internCode(@Nonnull Method method) {
// this also handles parameter names, which aren't directly tied to the MethodImplementation, even though the debug items are
boolean hasInstruction = false;
MethodImplementation methodImpl = method.getImplementation();
if (methodImpl != null) {
for (Instruction instruction: methodImpl.getInstructions()) {
hasInstruction = true;
if (instruction instanceof ReferenceInstruction) {
Reference reference = ((ReferenceInstruction)instruction).getReference();
switch (instruction.getOpcode().referenceType) {
case ReferenceType.STRING:
stringPool.intern((StringReference)reference);
break;
case ReferenceType.TYPE:
typePool.intern((TypeReference)reference);
break;
case ReferenceType.FIELD:
fieldPool.intern((FieldReference) reference);
break;
case ReferenceType.METHOD:
methodPool.intern((MethodReference)reference);
break;
default:
throw new ExceptionWithContext("Unrecognized reference type: %d",
instruction.getOpcode().referenceType);
}
}
}
List<? extends TryBlock> tryBlocks = methodImpl.getTryBlocks();
if (!hasInstruction && tryBlocks.size() > 0) {
throw new ExceptionWithContext("Method %s has no instructions, but has try blocks.",
ReferenceUtil.getMethodDescriptor(method));
}
for (TryBlock<? extends ExceptionHandler> tryBlock: methodImpl.getTryBlocks()) {
for (ExceptionHandler handler: tryBlock.getExceptionHandlers()) {
typePool.internNullable(handler.getExceptionType());
}
}
}
}
private void internDebug(@Nonnull Method method) {
for (MethodParameter param: method.getParameters()) {
String paramName = param.getName();
if (paramName != null) {
stringPool.intern(paramName);
}
}
MethodImplementation methodImpl = method.getImplementation();
if (methodImpl != null) {
for (DebugItem debugItem: methodImpl.getDebugItems()) {
switch (debugItem.getDebugItemType()) {
case DebugItemType.START_LOCAL:
StartLocal startLocal = (StartLocal)debugItem;
stringPool.internNullable(startLocal.getName());
typePool.internNullable(startLocal.getType());
stringPool.internNullable(startLocal.getSignature());
break;
case DebugItemType.SET_SOURCE_FILE:
stringPool.internNullable(((SetSourceFile) debugItem).getSourceFile());
break;
}
}
}
}
private ImmutableList<PoolClassDef> sortedClasses = null;
@Nonnull @Override public Collection<? extends PoolClassDef> getSortedClasses() {
if (sortedClasses == null) {
sortedClasses = Ordering.natural().immutableSortedCopy(internedItems.values());
}
return sortedClasses;
}
@Nullable @Override
public Map.Entry<? extends PoolClassDef, Integer> getClassEntryByType(@Nullable CharSequence name) {
if (name == null) {
return null;
}
final PoolClassDef classDef = internedItems.get(name.toString());
if (classDef == null) {
return null;
}
return new Map.Entry<PoolClassDef, Integer>() {
@Override public PoolClassDef getKey() {
return classDef;
}
@Override public Integer getValue() {
return classDef.classDefOffset;
}
@Override public Integer setValue(Integer value) {
return classDef.classDefOffset = value;
}
};
}
@Nonnull @Override public CharSequence getType(@Nonnull PoolClassDef classDef) {
return classDef.getType();
}
@Override public int getAccessFlags(@Nonnull PoolClassDef classDef) {
return classDef.getAccessFlags();
}
@Nullable @Override public CharSequence getSuperclass(@Nonnull PoolClassDef classDef) {
return classDef.getSuperclass();
}
@Nullable @Override public TypeListPool.Key<SortedSet<String>> getSortedInterfaces(@Nonnull PoolClassDef classDef) {
return classDef.interfaces;
}
@Nullable @Override public CharSequence getSourceFile(@Nonnull PoolClassDef classDef) {
return classDef.getSourceFile();
}
@Nullable @Override public EncodedArrayPool.Key getStaticInitializers(@Nonnull PoolClassDef classDef) {
return EncodedArrayPool.Key.of(classDef);
}
@Nonnull @Override public Collection<? extends Field> getSortedStaticFields(@Nonnull PoolClassDef classDef) {
return classDef.getStaticFields();
}
@Nonnull @Override public Collection<? extends Field> getSortedInstanceFields(@Nonnull PoolClassDef classDef) {
return classDef.getInstanceFields();
}
@Nonnull @Override public Collection<PoolMethod> getSortedDirectMethods(@Nonnull PoolClassDef classDef) {
return classDef.getDirectMethods();
}
@Nonnull @Override public Collection<PoolMethod> getSortedVirtualMethods(@Nonnull PoolClassDef classDef) {
return classDef.getVirtualMethods();
}
@Override public int getFieldAccessFlags(@Nonnull Field field) {
return field.getAccessFlags();
}
@Override public int getMethodAccessFlags(@Nonnull PoolMethod method) {
return method.getAccessFlags();
}
@Nullable @Override public Set<? extends Annotation> getClassAnnotations(@Nonnull PoolClassDef classDef) {
Set<? extends Annotation> annotations = classDef.getAnnotations();
if (annotations.size() == 0) {
return null;
}
return annotations;
}
@Nullable @Override public Set<? extends Annotation> getFieldAnnotations(@Nonnull Field field) {
Set<? extends Annotation> annotations = field.getAnnotations();
if (annotations.size() == 0) {
return null;
}
return annotations;
}
@Nullable @Override public Set<? extends Annotation> getMethodAnnotations(@Nonnull PoolMethod method) {
Set<? extends Annotation> annotations = method.getAnnotations();
if (annotations.size() == 0) {
return null;
}
return annotations;
}
@Nullable @Override public AnnotationSetRefPool.Key getParameterAnnotations(@Nonnull PoolMethod method) {
AnnotationSetRefPool.Key key = new AnnotationSetRefPool.Key(method);
Collection<Set<? extends Annotation>> annotations = key.getAnnotationSets();
if (annotations.size() == 0) {
return null;
}
return key;
}
@Nullable @Override public Iterable<? extends DebugItem> getDebugItems(@Nonnull PoolMethod method) {
MethodImplementation impl = method.getImplementation();
if (impl != null) {
return impl.getDebugItems();
}
return null;
}
@Nullable @Override public Iterable<CharSequence> getParameterNames(@Nonnull PoolMethod method) {
return Iterables.transform(method.getParameters(), new Function<MethodParameter, CharSequence>() {
@Nullable @Override public CharSequence apply(MethodParameter input) {
return input.getName();
}
});
}
@Override public int getRegisterCount(@Nonnull PoolMethod method) {
MethodImplementation impl = method.getImplementation();
if (impl != null) {
return impl.getRegisterCount();
}
return 0;
}
@Nullable @Override public Iterable<? extends Instruction> getInstructions(@Nonnull PoolMethod method) {
MethodImplementation impl = method.getImplementation();
if (impl != null) {
return impl.getInstructions();
}
return null;
}
@Nonnull @Override public List<? extends TryBlock<? extends ExceptionHandler>> getTryBlocks(
@Nonnull PoolMethod method) {
MethodImplementation impl = method.getImplementation();
if (impl != null) {
return impl.getTryBlocks();
}
return ImmutableList.of();
}
@Nullable @Override public CharSequence getExceptionType(@Nonnull ExceptionHandler handler) {
return handler.getExceptionType();
}
@Override public void setAnnotationDirectoryOffset(@Nonnull PoolClassDef classDef, int offset) {
classDef.annotationDirectoryOffset = offset;
}
@Override public int getAnnotationDirectoryOffset(@Nonnull PoolClassDef classDef) {
return classDef.annotationDirectoryOffset;
}
@Override public void setCodeItemOffset(@Nonnull PoolMethod method, int offset) {
method.codeItemOffset = offset;
}
@Override public int getCodeItemOffset(@Nonnull PoolMethod method) {
return method.codeItemOffset;
}
@Override public void setDebugItemOffset(@Nonnull PoolMethod method, int offset) {
method.debugInfoOffset = offset;
}
@Override public int getDebugItemOffset(@Nonnull PoolMethod method) {
return method.debugInfoOffset;
}
@Override public void writeDebugItem(@Nonnull DebugWriter<CharSequence, CharSequence> writer,
DebugItem debugItem) throws IOException {
switch (debugItem.getDebugItemType()) {
case DebugItemType.START_LOCAL: {
StartLocal startLocal = (StartLocal)debugItem;
writer.writeStartLocal(startLocal.getCodeAddress(),
startLocal.getRegister(),
startLocal.getName(),
startLocal.getType(),
startLocal.getSignature());
break;
}
case DebugItemType.END_LOCAL: {
EndLocal endLocal = (EndLocal)debugItem;
writer.writeEndLocal(endLocal.getCodeAddress(), endLocal.getRegister());
break;
}
case DebugItemType.RESTART_LOCAL: {
RestartLocal restartLocal = (RestartLocal)debugItem;
writer.writeRestartLocal(restartLocal.getCodeAddress(), restartLocal.getRegister());
break;
}
case DebugItemType.PROLOGUE_END: {
writer.writePrologueEnd(debugItem.getCodeAddress());
break;
}
case DebugItemType.EPILOGUE_BEGIN: {
writer.writeEpilogueBegin(debugItem.getCodeAddress());
break;
}
case DebugItemType.LINE_NUMBER: {
LineNumber lineNumber = (LineNumber)debugItem;
writer.writeLineNumber(lineNumber.getCodeAddress(), lineNumber.getLineNumber());
break;
}
case DebugItemType.SET_SOURCE_FILE: {
SetSourceFile setSourceFile = (SetSourceFile)debugItem;
writer.writeSetSourceFile(setSourceFile.getCodeAddress(), setSourceFile.getSourceFile());
}
default:
throw new ExceptionWithContext("Unexpected debug item type: %d", debugItem.getDebugItemType());
}
}
@Override public int getItemIndex(@Nonnull PoolClassDef classDef) {
return classDef.classDefOffset;
}
@Nonnull @Override public Collection<? extends Map.Entry<PoolClassDef, Integer>> getItems() {
class MapEntry implements Map.Entry<PoolClassDef, Integer> {
PoolClassDef classDef = null;
@Override public PoolClassDef getKey() {
return classDef;
}
@Override public Integer getValue() {
return classDef.classDefOffset;
}
@Override public Integer setValue(Integer value) {
int prev = classDef.classDefOffset;
classDef.classDefOffset = value;
return prev;
}
}
final MapEntry entry = new MapEntry();
return new AbstractCollection<Entry<PoolClassDef, Integer>>() {
@Nonnull @Override public Iterator<Entry<PoolClassDef, Integer>> iterator() {
return new Iterator<Entry<PoolClassDef, Integer>>() {
Iterator<PoolClassDef> iter = internedItems.values().iterator();
@Override public boolean hasNext() {
return iter.hasNext();
}
@Override public Entry<PoolClassDef, Integer> next() {
entry.classDef = iter.next();
return entry;
}
@Override public void remove() {
throw new UnsupportedOperationException();
}
};
}
@Override public int size() {
return internedItems.size();
}
};
}
}

View File

@ -0,0 +1,190 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer.pool;
import org.jf.dexlib2.ValueType;
import org.jf.dexlib2.iface.*;
import org.jf.dexlib2.iface.debug.DebugItem;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.iface.reference.StringReference;
import org.jf.dexlib2.iface.reference.TypeReference;
import org.jf.dexlib2.iface.value.*;
import org.jf.dexlib2.immutable.instruction.ImmutableInstructionFactory;
import org.jf.dexlib2.writer.pool.ProtoPool.Key;
import org.jf.dexlib2.writer.DexWriter;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.Collection;
import java.util.Set;
public class DexPool extends DexWriter<CharSequence, StringReference, CharSequence, TypeReference, Key,
FieldReference, MethodReference, PoolClassDef,
Annotation, Set<? extends Annotation>, AnnotationSetRefPool.Key,
TypeListPool.Key<? extends Collection<? extends CharSequence>>, EncodedArrayPool.Key, Field, PoolMethod,
EncodedValue, AnnotationElement, DebugItem, Instruction, ExceptionHandler> {
public static DexPool makeDexPool() {
StringPool stringPool = new StringPool();
TypePool typePool = new TypePool(stringPool);
FieldPool fieldPool = new FieldPool(stringPool, typePool);
TypeListPool typeListPool = new TypeListPool(typePool);
ProtoPool protoPool = new ProtoPool(stringPool, typePool, typeListPool);
MethodPool methodPool = new MethodPool(stringPool, typePool, protoPool);
EncodedArrayPool encodedArrayPool = new EncodedArrayPool(stringPool, typePool, fieldPool, methodPool);
AnnotationPool annotationPool = new AnnotationPool(stringPool, typePool, fieldPool, methodPool);
AnnotationSetPool annotationSetPool = new AnnotationSetPool(annotationPool);
AnnotationSetRefPool annotationSetRefPool = new AnnotationSetRefPool(annotationSetPool);
ClassPool classPool = new ClassPool(stringPool, typePool, fieldPool, methodPool, annotationSetPool,
annotationSetRefPool, typeListPool, encodedArrayPool);
return new DexPool(stringPool, typePool, protoPool, fieldPool, methodPool, classPool, typeListPool,
annotationPool, annotationSetPool, annotationSetRefPool, encodedArrayPool);
}
private DexPool(StringPool stringPool, TypePool typePool, ProtoPool protoPool, FieldPool fieldPool,
MethodPool methodPool, ClassPool classPool, TypeListPool typeListPool,
AnnotationPool annotationPool, AnnotationSetPool annotationSetPool,
AnnotationSetRefPool annotationSetRefPool, EncodedArrayPool encodedArrayPool) {
super(ImmutableInstructionFactory.INSTANCE, stringPool, typePool, protoPool, fieldPool, methodPool, classPool,
typeListPool, annotationPool, annotationSetPool, annotationSetRefPool, encodedArrayPool);
}
public static void writeTo(@Nonnull String path, @Nonnull org.jf.dexlib2.iface.DexFile input) throws IOException {
DexPool dexPool = makeDexPool();
for (ClassDef classDef: input.getClasses()) {
((ClassPool)dexPool.classSection).intern(classDef);
}
/*System.out.println("here");
while(true);*/
dexPool.writeTo(path);
}
@Override protected void writeEncodedValue(@Nonnull InternalEncodedValueWriter writer,
@Nonnull EncodedValue encodedValue) throws IOException {
switch (encodedValue.getValueType()) {
case ValueType.ANNOTATION:
AnnotationEncodedValue annotationEncodedValue = (AnnotationEncodedValue)encodedValue;
writer.writeAnnotation(annotationEncodedValue.getType(), annotationEncodedValue.getElements());
break;
case ValueType.ARRAY:
ArrayEncodedValue arrayEncodedValue = (ArrayEncodedValue)encodedValue;
writer.writeArray(arrayEncodedValue.getValue());
break;
case ValueType.BOOLEAN:
writer.writeBoolean(((BooleanEncodedValue)encodedValue).getValue());
break;
case ValueType.BYTE:
writer.writeByte(((ByteEncodedValue)encodedValue).getValue());
break;
case ValueType.CHAR:
writer.writeChar(((CharEncodedValue)encodedValue).getValue());
break;
case ValueType.DOUBLE:
writer.writeDouble(((DoubleEncodedValue)encodedValue).getValue());
break;
case ValueType.ENUM:
writer.writeEnum(((EnumEncodedValue)encodedValue).getValue());
break;
case ValueType.FIELD:
writer.writeField(((FieldEncodedValue)encodedValue).getValue());
break;
case ValueType.FLOAT:
writer.writeFloat(((FloatEncodedValue)encodedValue).getValue());
break;
case ValueType.INT:
writer.writeInt(((IntEncodedValue)encodedValue).getValue());
break;
case ValueType.LONG:
writer.writeLong(((LongEncodedValue)encodedValue).getValue());
break;
case ValueType.METHOD:
writer.writeMethod(((MethodEncodedValue)encodedValue).getValue());
break;
case ValueType.NULL:
writer.writeNull();
break;
case ValueType.SHORT:
writer.writeShort(((ShortEncodedValue)encodedValue).getValue());
break;
case ValueType.STRING:
writer.writeString(((StringEncodedValue)encodedValue).getValue());
break;
case ValueType.TYPE:
writer.writeType(((TypeEncodedValue)encodedValue).getValue());
break;
default:
throw new ExceptionWithContext("Unrecognized value type: %d", encodedValue.getValueType());
}
}
public static void internEncodedValue(@Nonnull EncodedValue encodedValue,
@Nonnull StringPool stringPool,
@Nonnull TypePool typePool,
@Nonnull FieldPool fieldPool,
@Nonnull MethodPool methodPool) {
switch (encodedValue.getValueType()) {
case ValueType.ANNOTATION:
AnnotationEncodedValue annotationEncodedValue = (AnnotationEncodedValue)encodedValue;
typePool.intern(annotationEncodedValue.getType());
for (AnnotationElement element: annotationEncodedValue.getElements()) {
stringPool.intern(element.getName());
internEncodedValue(element.getValue(), stringPool, typePool, fieldPool, methodPool);
}
break;
case ValueType.ARRAY:
for (EncodedValue element: ((ArrayEncodedValue)encodedValue).getValue()) {
internEncodedValue(element, stringPool, typePool, fieldPool, methodPool);
}
break;
case ValueType.STRING:
stringPool.intern(((StringEncodedValue)encodedValue).getValue());
break;
case ValueType.TYPE:
typePool.intern(((TypeEncodedValue)encodedValue).getValue());
break;
case ValueType.ENUM:
fieldPool.intern(((EnumEncodedValue)encodedValue).getValue());
break;
case ValueType.FIELD:
fieldPool.intern(((FieldEncodedValue)encodedValue).getValue());
break;
case ValueType.METHOD:
methodPool.intern(((MethodEncodedValue)encodedValue).getValue());
break;
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012, Google Inc.
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -29,84 +29,64 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
package org.jf.dexlib2.writer.pool;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.*;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Iterables;
import com.google.common.collect.Ordering;
import com.google.common.primitives.Ints;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.Field;
import org.jf.dexlib2.iface.value.EncodedValue;
import org.jf.dexlib2.immutable.value.ImmutableEncodedValueFactory;
import org.jf.dexlib2.util.EncodedValueUtils;
import org.jf.dexlib2.writer.pool.EncodedArrayPool.Key;
import org.jf.dexlib2.writer.EncodedArraySection;
import org.jf.util.CollectionUtils;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.*;
import java.util.AbstractCollection;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
public class EncodedArrayPool {
@Nonnull private final Map<Key, Integer> internedEncodedArrayItems = Maps.newHashMap();
@Nonnull private final DexFile dexFile;
private int sectionOffset = -1;
public class EncodedArrayPool extends BaseNullableOffsetPool<Key>
implements EncodedArraySection<Key, EncodedValue> {
@Nonnull private final StringPool stringPool;
@Nonnull private final TypePool typePool;
@Nonnull private final FieldPool fieldPool;
@Nonnull private final MethodPool methodPool;
public EncodedArrayPool(@Nonnull DexFile dexFile) {
this.dexFile = dexFile;
public EncodedArrayPool(@Nonnull StringPool stringPool,
@Nonnull TypePool typePool,
@Nonnull FieldPool fieldPool,
@Nonnull MethodPool methodPool) {
this.stringPool = stringPool;
this.typePool = typePool;
this.fieldPool = fieldPool;
this.methodPool = methodPool;
}
public void intern(@Nonnull ClassDef classDef) {
Key key = Key.of(classDef);
if (key != null) {
Integer prev = internedEncodedArrayItems.put(key, 0);
Integer prev = internedItems.put(key, 0);
if (prev == null) {
for (EncodedValue encodedValue: key.getElements()) {
dexFile.internEncodedValue(encodedValue);
for (EncodedValue encodedValue: key) {
DexPool.internEncodedValue(encodedValue, stringPool, typePool, fieldPool, methodPool);
}
}
}
}
public int getOffset(@Nonnull ClassDef classDef) {
Key key = Key.of(classDef);
if (key != null) {
Integer offset = internedEncodedArrayItems.get(key);
if (offset == null) {
throw new ExceptionWithContext("Encoded array not found.");
}
return offset;
}
return 0;
@Nonnull @Override public Collection<EncodedValue> getElements(@Nonnull Key key) {
return key;
}
public int getNumItems() {
return internedEncodedArrayItems.size();
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
List<Key> encodedArrays = Lists.newArrayList(internedEncodedArrayItems.keySet());
Collections.sort(encodedArrays);
sectionOffset = writer.getPosition();
for (Key encodedArray: encodedArrays) {
internedEncodedArrayItems.put(encodedArray, writer.getPosition());
writer.writeUleb128(encodedArray.getElementCount());
for (EncodedValue value: encodedArray.getElements()) {
dexFile.writeEncodedValue(writer, value);
}
}
}
public static class Key implements Comparable<Key> {
public static class Key extends AbstractCollection<EncodedValue> implements Comparable<Key> {
private final List<? extends Field> fields;
private final int size;
@ -139,20 +119,9 @@ public class EncodedArrayPool {
return null;
}
public int getElementCount() {
return size;
}
@Nonnull
public Iterable<EncodedValue> getElements() {
return FluentIterable.from(fields)
.limit(size)
.transform(GET_INITIAL_VALUE);
}
@Override
public int hashCode() {
return CollectionUtils.listHashCode(getElements());
return CollectionUtils.listHashCode(this);
}
@Override
@ -162,7 +131,7 @@ public class EncodedArrayPool {
if (size != other.size) {
return false;
}
return Iterables.elementsEqual(getElements(), other.getElements());
return Iterables.elementsEqual(this, other);
}
return false;
}
@ -181,8 +150,8 @@ public class EncodedArrayPool {
if (res != 0) {
return res;
}
Iterator<EncodedValue> otherElements = o.getElements().iterator();
for (EncodedValue element: getElements()) {
Iterator<EncodedValue> otherElements = o.iterator();
for (EncodedValue element: this) {
res = element.compareTo(otherElements.next());
if (res != 0) {
return res;
@ -190,5 +159,15 @@ public class EncodedArrayPool {
}
return 0;
}
@Nonnull @Override public Iterator<EncodedValue> iterator() {
return FluentIterable.from(fields)
.limit(size)
.transform(GET_INITIAL_VALUE).iterator();
}
@Override public int size() {
return size;
}
}
}

View File

@ -0,0 +1,69 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer.pool;
import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.writer.FieldSection;
import javax.annotation.Nonnull;
public class FieldPool extends BaseIndexPool<FieldReference>
implements FieldSection<CharSequence, CharSequence, FieldReference> {
@Nonnull private final StringPool stringPool;
@Nonnull private final TypePool typePool;
public FieldPool(@Nonnull StringPool stringPool, @Nonnull TypePool typePool) {
this.stringPool = stringPool;
this.typePool = typePool;
}
public void intern(@Nonnull FieldReference field) {
Integer prev = internedItems.put(field, 0);
if (prev == null) {
typePool.intern(field.getDefiningClass());
stringPool.intern(field.getName());
typePool.intern(field.getType());
}
}
@Nonnull @Override public CharSequence getDefiningClass(@Nonnull FieldReference fieldReference) {
return fieldReference.getDefiningClass();
}
@Nonnull @Override public CharSequence getFieldType(@Nonnull FieldReference fieldReference) {
return fieldReference.getType();
}
@Nonnull @Override public CharSequence getName(@Nonnull FieldReference fieldReference) {
return fieldReference.getName();
}
}

View File

@ -0,0 +1,72 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer.pool;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.writer.MethodSection;
import javax.annotation.Nonnull;
public class MethodPool extends BaseIndexPool<MethodReference>
implements MethodSection<CharSequence, CharSequence, ProtoPool.Key, MethodReference> {
@Nonnull private final StringPool stringPool;
@Nonnull private final TypePool typePool;
@Nonnull private final ProtoPool protoPool;
public MethodPool(@Nonnull StringPool stringPool, @Nonnull TypePool typePool,
@Nonnull ProtoPool protoPool) {
this.stringPool = stringPool;
this.typePool = typePool;
this.protoPool = protoPool;
}
public void intern(@Nonnull MethodReference method) {
Integer prev = internedItems.put(method, 0);
if (prev == null) {
typePool.intern(method.getDefiningClass());
protoPool.intern(method);
stringPool.intern(method.getName());
}
}
@Nonnull @Override public CharSequence getDefiningClass(@Nonnull MethodReference methodReference) {
return methodReference.getDefiningClass();
}
@Nonnull @Override public ProtoPool.Key getPrototype(@Nonnull MethodReference methodReference) {
return new ProtoPool.Key(methodReference);
}
@Nonnull @Override public CharSequence getName(@Nonnull MethodReference methodReference) {
return methodReference.getName();
}
}

View File

@ -0,0 +1,134 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer.pool;
import com.google.common.collect.*;
import org.jf.dexlib2.base.reference.BaseTypeReference;
import org.jf.dexlib2.iface.Annotation;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.Field;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
class PoolClassDef extends BaseTypeReference implements ClassDef {
@Nonnull final ClassDef classDef;
@Nonnull final TypeListPool.Key<SortedSet<String>> interfaces;
@Nonnull final ImmutableSortedSet<Field> staticFields;
@Nonnull final ImmutableSortedSet<Field> instanceFields;
@Nonnull final ImmutableSortedSet<PoolMethod> directMethods;
@Nonnull final ImmutableSortedSet<PoolMethod> virtualMethods;
int classDefOffset = DexPool.NO_OFFSET;
int annotationDirectoryOffset = DexPool.NO_OFFSET;
PoolClassDef(@Nonnull ClassDef classDef) {
this.classDef = classDef;
interfaces = new TypeListPool.Key<SortedSet<String>>(ImmutableSortedSet.copyOf(classDef.getInterfaces()));
staticFields = ImmutableSortedSet.copyOf(classDef.getStaticFields());
instanceFields = ImmutableSortedSet.copyOf(classDef.getInstanceFields());
directMethods = ImmutableSortedSet.copyOf(
Iterables.transform(classDef.getDirectMethods(), PoolMethod.TRANSFORM));
virtualMethods = ImmutableSortedSet.copyOf(
Iterables.transform(classDef.getVirtualMethods(), PoolMethod.TRANSFORM));
}
@Nonnull @Override public String getType() {
return classDef.getType();
}
@Override public int getAccessFlags() {
return classDef.getAccessFlags();
}
@Nullable @Override public String getSuperclass() {
return classDef.getSuperclass();
}
@Nonnull @Override public SortedSet<String> getInterfaces() {
return interfaces.types;
}
@Nullable @Override public String getSourceFile() {
return classDef.getSourceFile();
}
@Nonnull @Override public Set<? extends Annotation> getAnnotations() {
return classDef.getAnnotations();
}
@Nonnull @Override public SortedSet<Field> getStaticFields() {
return staticFields;
}
@Nonnull @Override public SortedSet<Field> getInstanceFields() {
return instanceFields;
}
@Nonnull @Override public Collection<Field> getFields() {
return new AbstractCollection<Field>() {
@Nonnull @Override public Iterator<Field> iterator() {
return Iterators.mergeSorted(
ImmutableList.of(staticFields.iterator(), instanceFields.iterator()),
Ordering.natural());
}
@Override public int size() {
return staticFields.size() + instanceFields.size();
}
};
}
@Nonnull @Override public SortedSet<PoolMethod> getDirectMethods() {
return directMethods;
}
@Nonnull @Override public SortedSet<PoolMethod> getVirtualMethods() {
return virtualMethods;
}
@Nonnull @Override public Iterable<PoolMethod> getMethods() {
return new AbstractCollection<PoolMethod>() {
@Nonnull @Override public Iterator<PoolMethod> iterator() {
return Iterators.mergeSorted(
ImmutableList.of(directMethods.iterator(), virtualMethods.iterator()),
Ordering.natural());
}
@Override public int size() {
return directMethods.size() + virtualMethods.size();
}
};
}
}

View File

@ -0,0 +1,93 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer.pool;
import com.google.common.base.Function;
import org.jf.dexlib2.base.reference.BaseMethodReference;
import org.jf.dexlib2.iface.Annotation;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.MethodImplementation;
import org.jf.dexlib2.iface.MethodParameter;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Set;
class PoolMethod extends BaseMethodReference implements Method {
@Nonnull private final Method method;
protected int codeItemOffset = DexPool.NO_OFFSET;
protected int debugInfoOffset = DexPool.NO_OFFSET;
public static final Function<Method, PoolMethod> TRANSFORM = new Function<Method, PoolMethod>() {
@Override public PoolMethod apply(Method method) {
return new PoolMethod(method);
}
};
PoolMethod(@Nonnull Method method) {
this.method = method;
}
@Override @Nonnull public String getDefiningClass() {
return method.getDefiningClass();
}
@Override @Nonnull public String getName() {
return method.getName();
}
@Override @Nonnull public List<? extends CharSequence> getParameterTypes() {
return method.getParameterTypes();
}
@Override @Nonnull public List<? extends MethodParameter> getParameters() {
return method.getParameters();
}
@Override @Nonnull public String getReturnType() {
return method.getReturnType();
}
@Override public int getAccessFlags() {
return method.getAccessFlags();
}
@Override @Nonnull public Set<? extends Annotation> getAnnotations() {
return method.getAnnotations();
}
@Override @Nullable public MethodImplementation getImplementation() {
return method.getImplementation();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012, Google Inc.
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -29,87 +29,74 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
package org.jf.dexlib2.writer.pool;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.writer.pool.ProtoPool.Key;
import org.jf.dexlib2.writer.ProtoSection;
import org.jf.util.CharSequenceUtils;
import org.jf.util.CollectionUtils;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class ProtoPool {
public final static int PROTO_ID_ITEM_SIZE = 0x0C;
public class ProtoPool extends BaseIndexPool<Key>
implements ProtoSection<CharSequence, CharSequence, Key, TypeListPool.Key<? extends Collection<? extends CharSequence>>> {
@Nonnull private final StringPool stringPool;
@Nonnull private final TypePool typePool;
@Nonnull private final TypeListPool typeListPool;
@Nonnull private final Map<Key, Integer> internedProtoIdItems = Maps.newHashMap();
@Nonnull private final DexFile dexFile;
private int sectionOffset = -1;
public ProtoPool(@Nonnull DexFile dexFile) {
this.dexFile = dexFile;
public ProtoPool(@Nonnull StringPool stringPool, @Nonnull TypePool typePool,
@Nonnull TypeListPool typeListPool) {
this.stringPool = stringPool;
this.typePool = typePool;
this.typeListPool = typeListPool;
}
public void intern(@Nonnull MethodReference method) {
// We can't use method directly, because it is likely a full MethodReference. We use a wrapper that computes
// hashCode and equals based only on the prototype fields
Key key = new Key(method);
Integer prev = internedProtoIdItems.put(key, 0);
Integer prev = internedItems.put(key, 0);
if (prev == null) {
dexFile.stringPool.intern(key.getShorty());
dexFile.typePool.intern(method.getReturnType());
dexFile.typeListPool.intern(method.getParameterTypes());
stringPool.intern(key.getShorty());
typePool.intern(method.getReturnType());
typeListPool.intern(method.getParameterTypes());
}
}
public int getIndex(@Nonnull MethodReference method) {
Key key = new Key(method);
Integer index = internedProtoIdItems.get(key);
if (index == null) {
throw new ExceptionWithContext("Prototype not found.: %s", key);
@Nonnull @Override public CharSequence getShorty(@Nonnull Key key) {
return key.getShorty();
}
@Nonnull @Override public CharSequence getReturnType(@Nonnull Key key) {
return key.getReturnType();
}
@Nullable @Override public TypeListPool.Key<List<? extends CharSequence>> getParameters(@Nonnull Key key) {
return new TypeListPool.Key<List<? extends CharSequence>>(key.getParameters());
}
private static char getShortyType(CharSequence type) {
if (type.length() > 1) {
return 'L';
}
return index;
return type.charAt(0);
}
public int getIndexedSectionSize() {
return internedProtoIdItems.size() * PROTO_ID_ITEM_SIZE;
}
public int getNumItems() {
return internedProtoIdItems.size();
}
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
private static String getShorty(Collection<? extends CharSequence> params, CharSequence returnType) {
StringBuilder sb = new StringBuilder(params.size() + 1);
sb.append(getShortyType(returnType));
for (CharSequence typeRef: params) {
sb.append(getShortyType(typeRef));
}
return sectionOffset;
return sb.toString();
}
public void write(@Nonnull DexWriter writer) throws IOException {
List<Key> prototypes = Lists.newArrayList(internedProtoIdItems.keySet());
Collections.sort(prototypes);
sectionOffset = writer.getPosition();
int index = 0;
for (Key proto: prototypes) {
internedProtoIdItems.put(proto, index++);
writer.writeInt(dexFile.stringPool.getIndex(proto.getShorty()));
writer.writeInt(dexFile.typePool.getIndex(proto.getReturnType()));
writer.writeInt(dexFile.typeListPool.getOffset(proto.getParameters()));
}
}
private static class Key implements Comparable<Key> {
public static class Key implements Comparable<Key> {
@Nonnull private final MethodReference method;
public Key(@Nonnull MethodReference method) {
@ -122,20 +109,7 @@ public class ProtoPool {
}
public String getShorty() {
Collection<? extends CharSequence> params = getParameters();
StringBuilder sb = new StringBuilder(params.size() + 1);
sb.append(getShortyType(method.getReturnType()));
for (CharSequence typeRef: params) {
sb.append(getShortyType(typeRef));
}
return sb.toString();
}
private static char getShortyType(CharSequence type) {
if (type.length() > 1) {
return 'L';
}
return type.charAt(0);
return ProtoPool.getShorty(method.getParameterTypes(), method.getReturnType());
}
public String toString() {
@ -160,7 +134,7 @@ public class ProtoPool {
if (o instanceof Key) {
Key other = (Key)o;
return getReturnType().equals(other.getReturnType()) &&
CharSequenceUtils.listEquals(getParameters(), other.getParameters());
CharSequenceUtils.listEquals(getParameters(), other.getParameters());
}
return false;
}

View File

@ -0,0 +1,54 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer.pool;
import org.jf.dexlib2.iface.reference.StringReference;
import org.jf.dexlib2.writer.StringSection;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class StringPool extends StringTypeBasePool implements StringSection<CharSequence, StringReference> {
public void intern(@Nonnull CharSequence string) {
internedItems.put(string.toString(), 0);
}
public void internNullable(@Nullable CharSequence string) {
if (string != null) {
intern(string);
}
}
@Override public int getItemIndex(@Nonnull StringReference key) {
return getItemIndex(key.getString());
}
}

View File

@ -0,0 +1,65 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer.pool;
import com.google.common.collect.Maps;
import org.jf.dexlib2.writer.DexWriter;
import org.jf.dexlib2.writer.NullableIndexSection;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Map;
public abstract class StringTypeBasePool implements NullableIndexSection<CharSequence> {
@Nonnull protected final Map<String, Integer> internedItems = Maps.newHashMap();
@Nonnull @Override public Collection<Map.Entry<String, Integer>> getItems() {
return internedItems.entrySet();
}
@Override public int getItemIndex(@Nonnull CharSequence key) {
Integer index = internedItems.get(key.toString());
if (index == null) {
throw new ExceptionWithContext("Item not found.: %s", key.toString());
}
return index;
}
@Override public int getNullableItemIndex(@Nullable CharSequence key) {
if (key == null) {
return DexWriter.NO_INDEX;
}
return getItemIndex(key);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012, Google Inc.
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -29,76 +29,47 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
package org.jf.dexlib2.writer.pool;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.jf.util.ExceptionWithContext;
import com.google.common.collect.ImmutableList;
import org.jf.dexlib2.writer.pool.TypeListPool.Key;
import org.jf.dexlib2.writer.TypeListSection;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.*;
import java.util.Collection;
import java.util.Iterator;
public class TypeListPool {
@Nonnull private final Map<Key, Integer> internedTypeListItems = Maps.newHashMap();
@Nonnull private final DexFile dexFile;
private int sectionOffset = -1;
public class TypeListPool extends BaseNullableOffsetPool<Key<? extends Collection<? extends CharSequence>>>
implements TypeListSection<CharSequence, Key<? extends Collection<? extends CharSequence>>> {
@Nonnull private final TypePool typePool;
public TypeListPool(@Nonnull DexFile dexFile) {
this.dexFile = dexFile;
public TypeListPool(@Nonnull TypePool typePool) {
this.typePool = typePool;
}
public void intern(@Nonnull Collection<? extends CharSequence> types) {
Key key = new Key(types);
Integer prev = internedTypeListItems.put(key, 0);
Key<? extends Collection<? extends CharSequence>> key = new Key<Collection<? extends CharSequence>>(types);
Integer prev = internedItems.put(key, 0);
if (prev == null) {
for (CharSequence type: types) {
dexFile.typePool.intern(type);
typePool.intern(type);
}
}
}
public int getOffset(@Nonnull Collection<? extends CharSequence> types) {
Key key = new Key(types);
Integer offset = internedTypeListItems.get(key);
if (offset == null) {
throw new ExceptionWithContext("Type list not found.: %s", key);
@Nonnull @Override
public Collection<? extends CharSequence> getTypes(Key<? extends Collection<? extends CharSequence>> typesKey) {
if (typesKey == null) {
return ImmutableList.of();
}
return offset;
return typesKey.types;
}
public int getNumItems() {
return internedTypeListItems.size();
}
public static class Key<TypeCollection extends Collection<? extends CharSequence>>
implements Comparable<Key<? extends Collection<? extends CharSequence>>> {
@Nonnull TypeCollection types;
public int getSectionOffset() {
if (sectionOffset < 0) {
throw new ExceptionWithContext("Section offset has not been set yet!");
}
return sectionOffset;
}
public void write(@Nonnull DexWriter writer) throws IOException {
List<Key> typeLists = Lists.newArrayList(internedTypeListItems.keySet());
Collections.sort(typeLists);
writer.align();
sectionOffset = writer.getPosition();
for (Key typeList: typeLists) {
writer.align();
internedTypeListItems.put(typeList, writer.getPosition());
Collection<? extends CharSequence> types = typeList.getTypes();
writer.writeInt(types.size());
for (CharSequence type: types) {
writer.writeUshort(dexFile.typePool.getIndex(type));
}
}
}
public static class Key implements Comparable<Key> {
@Nonnull private Collection<? extends CharSequence> types;
public Key(@Nonnull Collection<? extends CharSequence> types) {
public Key(@Nonnull TypeCollection types) {
this.types = types;
}
@ -114,7 +85,8 @@ public class TypeListPool {
@Override
public boolean equals(Object o) {
if (o instanceof Key) {
Key other = (Key)o;
Key<? extends Collection<? extends CharSequence>> other =
(Key<? extends Collection<? extends CharSequence>>)o;
if (types.size() != other.types.size()) {
return false;
}
@ -138,13 +110,8 @@ public class TypeListPool {
return sb.toString();
}
@Nonnull
public Collection<? extends CharSequence> getTypes() {
return types;
}
@Override
public int compareTo(Key o) {
public int compareTo(Key<? extends Collection<? extends CharSequence>> o) {
Iterator<? extends CharSequence> other = o.types.iterator();
for (CharSequence type: types) {
if (!other.hasNext()) {

View File

@ -0,0 +1,69 @@
/*
* Copyright 2013, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer.pool;
import org.jf.dexlib2.iface.reference.TypeReference;
import org.jf.dexlib2.writer.TypeSection;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class TypePool extends StringTypeBasePool
implements TypeSection<CharSequence, CharSequence, TypeReference> {
@Nonnull private final StringPool stringPool;
public TypePool(@Nonnull StringPool stringPool) {
this.stringPool = stringPool;
}
public void intern(@Nonnull CharSequence type) {
String typeString = type.toString();
Integer prev = internedItems.put(typeString, 0);
if (prev == null) {
stringPool.intern(typeString);
}
}
public void internNullable(@Nullable CharSequence type) {
if (type != null) {
intern(type);
}
}
@Override public int getItemIndex(@Nonnull TypeReference key) {
return getItemIndex(key.getType());
}
@Nonnull @Override public CharSequence getString(@Nonnull CharSequence type) {
return type;
}
}

View File

@ -35,7 +35,6 @@ import com.google.common.collect.Lists;
import org.jf.dexlib2.Format;
import org.jf.dexlib2.Opcode;
import org.jf.dexlib2.ReferenceType;
import org.jf.dexlib2.iface.MethodImplementation;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
import org.jf.dexlib2.iface.instruction.SwitchElement;
@ -45,7 +44,7 @@ import org.jf.dexlib2.iface.reference.*;
import org.jf.dexlib2.immutable.instruction.*;
import org.jf.dexlib2.util.InstructionUtil;
import org.jf.dexlib2.util.MethodUtil;
import org.jf.dexlib2.writer.StringPool;
import org.jf.dexlib2.writer.InstructionFactory;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
@ -53,28 +52,35 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class InstructionWriteUtil {
private final StringPool stringPool;
MethodImplementation methodImplementation;
public class InstructionWriteUtil<Insn extends Instruction, StringRef extends StringReference> {
private final StringIndexProvider<StringRef> stringIndexProvider;
private final InstructionFactory<? extends Insn> instructionFactory;
private final Iterable<? extends Insn> originalInstructions;
private List<Instruction> instructions;
private List<Insn> instructions;
private ArrayList<Integer> codeOffsetShifts;
private HashMap<Integer,Format> offsetToNewInstructionMap;
private int codeUnitCount;
private int outParamCount;
public InstructionWriteUtil(@Nonnull MethodImplementation methodImpl, @Nonnull StringPool stringPool) {
this.stringPool = stringPool;
methodImplementation = methodImpl;
public static interface StringIndexProvider<StringRef extends StringReference> {
int getItemIndex(@Nonnull StringRef reference);
}
public InstructionWriteUtil(@Nonnull Iterable<? extends Insn> instructions,
@Nonnull StringIndexProvider<StringRef> stringIndexProvider,
@Nonnull InstructionFactory<? extends Insn> instructionFactory) {
this.stringIndexProvider = stringIndexProvider;
this.instructionFactory = instructionFactory;
this.originalInstructions = instructions;
calculateMaxOutParamCount();
findCodeOffsetShifts();
modifyInstructions();
}
private void calculateMaxOutParamCount() {
for (Instruction instruction: methodImplementation.getInstructions()) {
for (Insn instruction: originalInstructions) {
codeUnitCount += instruction.getCodeUnits();
if (instruction.getOpcode().referenceType == ReferenceType.METHOD) {
ReferenceInstruction refInsn = (ReferenceInstruction)instruction;
@ -86,12 +92,11 @@ public class InstructionWriteUtil {
}
}
}
public Iterable<? extends Instruction> getInstructions() {
public Iterable<? extends Insn> getInstructions() {
if (instructions != null) {
return instructions;
} else {
return methodImplementation.getInstructions();
return originalInstructions;
}
}
@ -142,16 +147,17 @@ public class InstructionWriteUtil {
private void findCodeOffsetShifts() {
// first, process const-string to const-string/jumbo conversions
int currentCodeOffset = 0;
for (Instruction instruction: methodImplementation.getInstructions()) {
for (Instruction instruction: originalInstructions) {
if (instruction.getOpcode().equals(Opcode.CONST_STRING)) {
ReferenceInstruction refInstr = (ReferenceInstruction) instruction;
int referenceIndex = stringPool.getIndex((StringReference)refInstr.getReference());
// TODO: add the necessary generic plumbing to the Instruction interface to make this work without a warning (ugh)
int referenceIndex = stringIndexProvider.getItemIndex((StringRef)refInstr.getReference());
if (referenceIndex > 0xFFFF) {
if (codeOffsetShifts == null) {
codeOffsetShifts = new ArrayList<Integer>();
}
if (offsetToNewInstructionMap == null) {
offsetToNewInstructionMap = new HashMap<Integer,Format>();
offsetToNewInstructionMap = new HashMap<Integer,Format>();
}
codeOffsetShifts.add(currentCodeOffset+instruction.getCodeUnits());
offsetToNewInstructionMap.put(currentCodeOffset, Opcode.CONST_STRING_JUMBO.format);
@ -172,16 +178,16 @@ public class InstructionWriteUtil {
do {
currentCodeOffset = 0;
shiftsInserted = false;
for (Instruction instruction: methodImplementation.getInstructions()) {
for (Instruction instruction: originalInstructions) {
if (instruction.getOpcode().format.equals(Format.Format10t) && !offsetToNewInstructionMap.containsKey(currentCodeOffset)) {
int targetOffset = ((Instruction10t)instruction).getCodeOffset();
int codeOffsetDelta = codeOffsetShift(currentCodeOffset);
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
if ((byte)newTargetOffset != newTargetOffset) {
if ((short)newTargetOffset != newTargetOffset) {
// handling very small (negligible) possibility of goto becoming goto/32
// we insert extra 1 code unit shift referring to the same position
// this will cause subsequent code offsets to be shifted by 2 code units
// handling very small (negligible) possibility of goto becoming goto/32
// we insert extra 1 code unit shift referring to the same position
// this will cause subsequent code offsets to be shifted by 2 code units
codeOffsetShifts.add(codeOffsetDelta, currentCodeOffset+instruction.getCodeUnits());
offsetToNewInstructionMap.put(currentCodeOffset, Format.Format30t);
} else {
@ -228,8 +234,8 @@ public class InstructionWriteUtil {
instructions = Lists.newArrayList();
int currentCodeOffset = 0;
for (Instruction instruction: methodImplementation.getInstructions()) {
Instruction modifiedInstruction = null;
for (Insn instruction: originalInstructions) {
Insn modifiedInstruction = null;
switch (instruction.getOpcode().format) {
case Format10t: {
Instruction10t instr = (Instruction10t)instruction;
@ -237,13 +243,13 @@ public class InstructionWriteUtil {
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
Format newInstructionFormat = offsetToNewInstructionMap.get(currentCodeOffset);
if (newInstructionFormat != null) {
if (newInstructionFormat.equals(Format.Format30t)) {
modifiedInstruction = new ImmutableInstruction30t(Opcode.GOTO_32, newTargetOffset);
if (newInstructionFormat.equals(Format.Format30t)) {
modifiedInstruction = instructionFactory.makeInstruction30t(Opcode.GOTO_32, newTargetOffset);
} else if (newInstructionFormat.equals(Format.Format20t)) {
modifiedInstruction = new ImmutableInstruction20t(Opcode.GOTO_16, newTargetOffset);
modifiedInstruction = instructionFactory.makeInstruction20t(Opcode.GOTO_16, newTargetOffset);
}
} else if (newTargetOffset != targetOffset) {
modifiedInstruction = new ImmutableInstruction10t(instr.getOpcode(), newTargetOffset);
modifiedInstruction = instructionFactory.makeInstruction10t(instr.getOpcode(), newTargetOffset);
}
break;
}
@ -253,18 +259,19 @@ public class InstructionWriteUtil {
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
Format newInstructionFormat = offsetToNewInstructionMap.get(currentCodeOffset);
if (newInstructionFormat != null && newInstructionFormat.equals(Format.Format30t)) {
modifiedInstruction = new ImmutableInstruction30t(Opcode.GOTO_32, newTargetOffset);
modifiedInstruction = instructionFactory.makeInstruction30t(Opcode.GOTO_32, newTargetOffset);
} else if (newTargetOffset != targetOffset) {
modifiedInstruction = new ImmutableInstruction20t(Opcode.GOTO_16, newTargetOffset);
modifiedInstruction = instructionFactory.makeInstruction20t(Opcode.GOTO_16, newTargetOffset);
}
break;
}
case Format21c: {
Instruction21c instr = (Instruction21c)instruction;
if (instr.getOpcode().equals(Opcode.CONST_STRING)) {
int referenceIndex = stringPool.getIndex((StringReference)instr.getReference());
int referenceIndex = stringIndexProvider.getItemIndex((StringRef)instr.getReference());
if (referenceIndex > 0xFFFF) {
modifiedInstruction = new ImmutableInstruction31c(Opcode.CONST_STRING_JUMBO, instr.getRegisterA(), instr.getReference());
modifiedInstruction = instructionFactory.makeInstruction31c(Opcode.CONST_STRING_JUMBO,
instr.getRegisterA(), instr.getReference());
}
}
break;
@ -274,7 +281,8 @@ public class InstructionWriteUtil {
int targetOffset = instr.getCodeOffset();
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
if (newTargetOffset != targetOffset) {
modifiedInstruction = new ImmutableInstruction21t(instr.getOpcode(), instr.getRegisterA(), newTargetOffset);
modifiedInstruction = instructionFactory.makeInstruction21t(instr.getOpcode(),
instr.getRegisterA(), newTargetOffset);
}
break;
}
@ -283,7 +291,8 @@ public class InstructionWriteUtil {
int targetOffset = instr.getCodeOffset();
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
if (newTargetOffset != targetOffset) {
modifiedInstruction = new ImmutableInstruction22t(instr.getOpcode(), instr.getRegisterA(), instr.getRegisterB(), newTargetOffset);
modifiedInstruction = instructionFactory.makeInstruction22t(instr.getOpcode(),
instr.getRegisterA(), instr.getRegisterB(), newTargetOffset);
}
break;
}
@ -292,7 +301,7 @@ public class InstructionWriteUtil {
int targetOffset = instr.getCodeOffset();
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
if (newTargetOffset != targetOffset) {
modifiedInstruction = new ImmutableInstruction30t(instr.getOpcode(), newTargetOffset);
modifiedInstruction = instructionFactory.makeInstruction30t(instr.getOpcode(), newTargetOffset);
}
break;
}
@ -301,40 +310,41 @@ public class InstructionWriteUtil {
int targetOffset = instr.getCodeOffset();
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
if (newTargetOffset != targetOffset) {
modifiedInstruction = new ImmutableInstruction31t(instr.getOpcode(), instr.getRegisterA(), newTargetOffset);
modifiedInstruction = instructionFactory.makeInstruction31t(instr.getOpcode(),
instr.getRegisterA(), newTargetOffset);
}
break;
}
case SparseSwitchPayload: {
alignPayload(currentCodeOffset);
int switchInstructionOffset = findSwitchInstructionOffset(currentCodeOffset);
alignPayload(currentCodeOffset);
int switchInstructionOffset = findSwitchInstructionOffset(currentCodeOffset);
SwitchPayload payload = (SwitchPayload)instruction;
if (isSwitchTargetOffsetChanged(payload, switchInstructionOffset)) {
List<SwitchElement> newSwitchElements = modifySwitchElements(payload, switchInstructionOffset);
modifiedInstruction = new ImmutableSparseSwitchPayload(newSwitchElements);
List<SwitchElement> newSwitchElements = modifySwitchElements(payload, switchInstructionOffset);
modifiedInstruction = instructionFactory.makeSparseSwitchPayload(newSwitchElements);
}
break;
}
case PackedSwitchPayload: {
alignPayload(currentCodeOffset);
int switchInstructionOffset = findSwitchInstructionOffset(currentCodeOffset);
alignPayload(currentCodeOffset);
int switchInstructionOffset = findSwitchInstructionOffset(currentCodeOffset);
SwitchPayload payload = (SwitchPayload)instruction;
if (isSwitchTargetOffsetChanged(payload, switchInstructionOffset)) {
List<SwitchElement> newSwitchElements = modifySwitchElements(payload, switchInstructionOffset);
modifiedInstruction = new ImmutablePackedSwitchPayload(newSwitchElements);
modifiedInstruction = instructionFactory.makePackedSwitchPayload(newSwitchElements);
}
break;
}
case ArrayPayload: {
alignPayload(currentCodeOffset);
alignPayload(currentCodeOffset);
break;
}
}
if (modifiedInstruction != null) {
instructions.add(modifiedInstruction);
instructions.add(modifiedInstruction);
} else {
instructions.add(instruction);
instructions.add(instruction);
}
currentCodeOffset += instruction.getCodeUnits();
@ -342,25 +352,25 @@ public class InstructionWriteUtil {
}
private void alignPayload(int codeOffset) {
Format newInstructionFormat = offsetToNewInstructionMap.get(codeOffset);
if (newInstructionFormat != null && newInstructionFormat.equals(Format.Format10x)) {
instructions.add(new ImmutableInstruction10x(Opcode.NOP));
}
Format newInstructionFormat = offsetToNewInstructionMap.get(codeOffset);
if (newInstructionFormat != null && newInstructionFormat.equals(Format.Format10x)) {
instructions.add(instructionFactory.makeInstruction10x(Opcode.NOP));
}
}
private int findSwitchInstructionOffset(int payloadOffset) {
int currentCodeOffset = 0;
int switchInstructionOffset = -1;
for (Instruction instruction: methodImplementation.getInstructions()) {
for (Instruction instruction: originalInstructions) {
if (instruction.getOpcode().equals(Opcode.PACKED_SWITCH)
|| instruction.getOpcode().equals(Opcode.SPARSE_SWITCH)) {
int targetOffset = currentCodeOffset + ((Instruction31t)instruction).getCodeOffset();
if (targetOffset == payloadOffset) {
if (switchInstructionOffset < 0) {
switchInstructionOffset = currentCodeOffset;
} else {
throw new ExceptionWithContext("Multiple switch instructions refer to the same switch payload!");
}
if (switchInstructionOffset < 0) {
switchInstructionOffset = currentCodeOffset;
} else {
throw new ExceptionWithContext("Multiple switch instructions refer to the same switch payload!");
}
}
}
currentCodeOffset += instruction.getCodeUnits();

View File

@ -35,7 +35,6 @@ import com.google.common.collect.Lists;
import org.jf.dexlib2.base.BaseTryBlock;
import org.jf.dexlib2.iface.ExceptionHandler;
import org.jf.dexlib2.iface.TryBlock;
import org.jf.dexlib2.immutable.ImmutableExceptionHandler;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
@ -44,43 +43,40 @@ import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
public class TryListBuilder
public class TryListBuilder<EH extends ExceptionHandler>
{
/*TODO: add logic to merge adjacent, identical try blocks, and remove superflous handlers
Also provide a "strict" mode, where the above isn't performed, which will be useful to be able to
exactly reproduce the original .dex file (for testing/verification purposes)*/
// Linked list sentinels that don't represent an actual try block
// Their values are never modified, only their links
private final MutableTryBlock listStart;
private final MutableTryBlock listEnd;
private final MutableTryBlock<EH> listStart;
private final MutableTryBlock<EH> listEnd;
public TryListBuilder() {
listStart = new MutableTryBlock(0, 0);
listEnd = new MutableTryBlock(0, 0);
listStart = new MutableTryBlock<EH>(0, 0);
listEnd = new MutableTryBlock<EH>(0, 0);
listStart.next = listEnd;
listEnd.prev = listStart;
}
public static List<TryBlock> massageTryBlocks(List<? extends TryBlock> tryBlocks) {
TryListBuilder tlb = new TryListBuilder();
for (TryBlock tryBlock: tryBlocks) {
public static <EH extends ExceptionHandler> List<TryBlock<EH>> massageTryBlocks(
List<? extends TryBlock<? extends EH>> tryBlocks) {
TryListBuilder<EH> tlb = new TryListBuilder<EH>();
for (TryBlock<? extends EH> tryBlock: tryBlocks) {
int startAddress = tryBlock.getStartCodeAddress();
int endAddress = startAddress + tryBlock.getCodeUnitCount();
for (ExceptionHandler exceptionHandler: tryBlock.getExceptionHandlers()) {
tlb.addHandler(exceptionHandler.getExceptionType(), startAddress, endAddress,
exceptionHandler.getHandlerCodeAddress());
for (EH exceptionHandler: tryBlock.getExceptionHandlers()) {
tlb.addHandler(startAddress, endAddress, exceptionHandler);
}
}
return tlb.getTryBlocks();
}
private static class TryBounds {
@Nonnull public final MutableTryBlock start;
@Nonnull public final MutableTryBlock end;
private static class TryBounds<EH extends ExceptionHandler> {
@Nonnull public final MutableTryBlock<EH> start;
@Nonnull public final MutableTryBlock<EH> end;
public TryBounds(@Nonnull MutableTryBlock start, @Nonnull MutableTryBlock end) {
public TryBounds(@Nonnull MutableTryBlock<EH> start, @Nonnull MutableTryBlock<EH> end) {
this.start = start;
this.end = end;
}
@ -100,13 +96,13 @@ public class TryListBuilder
}
}
private static class MutableTryBlock extends BaseTryBlock implements TryBlock {
public MutableTryBlock prev = null;
public MutableTryBlock next = null;
private static class MutableTryBlock<EH extends ExceptionHandler> extends BaseTryBlock<EH> {
public MutableTryBlock<EH> prev = null;
public MutableTryBlock<EH> next = null;
public int startCodeAddress;
public int endCodeAddress;
@Nonnull public List<ExceptionHandler> exceptionHandlers = Lists.newArrayList();
@Nonnull public List<EH> exceptionHandlers = Lists.newArrayList();
public MutableTryBlock(int startCodeAddress, int endCodeAddress) {
this.startCodeAddress = startCodeAddress;
@ -114,7 +110,7 @@ public class TryListBuilder
}
public MutableTryBlock(int startCodeAddress, int endCodeAddress,
@Nonnull List<? extends ExceptionHandler> exceptionHandlers) {
@Nonnull List<EH> exceptionHandlers) {
this.startCodeAddress = startCodeAddress;
this.endCodeAddress = endCodeAddress;
this.exceptionHandlers = Lists.newArrayList(exceptionHandlers);
@ -128,13 +124,13 @@ public class TryListBuilder
return endCodeAddress - startCodeAddress;
}
@Nonnull @Override public List<? extends ExceptionHandler> getExceptionHandlers() {
@Nonnull @Override public List<EH> getExceptionHandlers() {
return exceptionHandlers;
}
@Nonnull
public MutableTryBlock split(int splitAddress) {
MutableTryBlock newTryBlock = new MutableTryBlock(splitAddress, endCodeAddress, exceptionHandlers);
public MutableTryBlock<EH> split(int splitAddress) {
MutableTryBlock<EH> newTryBlock = new MutableTryBlock<EH>(splitAddress, endCodeAddress, exceptionHandlers);
endCodeAddress = splitAddress;
append(newTryBlock);
return newTryBlock;
@ -151,21 +147,21 @@ public class TryListBuilder
next.delete();
}
public void append(@Nonnull MutableTryBlock tryBlock) {
public void append(@Nonnull MutableTryBlock<EH> tryBlock) {
next.prev = tryBlock;
tryBlock.next = next;
tryBlock.prev = this;
next = tryBlock;
}
public void prepend(@Nonnull MutableTryBlock tryBlock) {
public void prepend(@Nonnull MutableTryBlock<EH> tryBlock) {
prev.next = tryBlock;
tryBlock.prev = prev;
tryBlock.next = this;
prev = tryBlock;
}
public void addHandler(@Nonnull ExceptionHandler handler) {
public void addHandler(@Nonnull EH handler) {
for (ExceptionHandler existingHandler: exceptionHandlers) {
String existingType = existingHandler.getExceptionType();
String newType = handler.getExceptionType();
@ -192,10 +188,10 @@ public class TryListBuilder
}
}
private TryBounds getBoundingRanges(int startAddress, int endAddress) {
MutableTryBlock startBlock = null;
private TryBounds<EH> getBoundingRanges(int startAddress, int endAddress) {
MutableTryBlock<EH> startBlock = null;
MutableTryBlock tryBlock = listStart.next;
MutableTryBlock<EH> tryBlock = listStart.next;
while (tryBlock != listEnd) {
int currentStartAddress = tryBlock.startCodeAddress;
int currentEndAddress = tryBlock.endCodeAddress;
@ -220,16 +216,16 @@ public class TryListBuilder
//^--^
/*Oops, totally too far! The new range doesn't overlap any existing
ones, so we just add it and return*/
startBlock = new MutableTryBlock(startAddress, endAddress);
startBlock = new MutableTryBlock<EH>(startAddress, endAddress);
tryBlock.prepend(startBlock);
return new TryBounds(startBlock, startBlock);
return new TryBounds<EH>(startBlock, startBlock);
} else {
// |-----|
//^---------
/*Oops, too far! We've passed the start of the range being added, but
the new range does overlap this one. We need to add a new range just
before this one*/
startBlock = new MutableTryBlock(startAddress, currentStartAddress);
startBlock = new MutableTryBlock<EH>(startAddress, currentStartAddress);
tryBlock.prepend(startBlock);
break;
}
@ -244,9 +240,9 @@ public class TryListBuilder
end before the range being added starts. In either case, we just need
to add a new range at the end of the list*/
if (startBlock == null) {
startBlock = new MutableTryBlock(startAddress, endAddress);
startBlock = new MutableTryBlock<EH>(startAddress, endAddress);
listEnd.prepend(startBlock);
return new TryBounds(startBlock, startBlock);
return new TryBounds<EH>(startBlock, startBlock);
}
tryBlock = startBlock;
@ -258,7 +254,7 @@ public class TryListBuilder
//|-----|
//------^
/*Bam! We hit the end right on the head... err, tail.*/
return new TryBounds(startBlock, tryBlock);
return new TryBounds<EH>(startBlock, tryBlock);
} else if (endAddress > currentStartAddress && endAddress < currentEndAddress) {
//|-----|
//--^
@ -266,16 +262,16 @@ public class TryListBuilder
existing range. We need to split the existing range
at the end of the range being added.*/
tryBlock.split(endAddress);
return new TryBounds(startBlock, tryBlock);
return new TryBounds<EH>(startBlock, tryBlock);
} else if (endAddress <= currentStartAddress) {
//|-----| |-----|
//-----------^
/*Oops, too far! The current range starts after the range being added
ends. We need to create a new range that starts at the end of the
previous range, and ends at the end of the range being added*/
MutableTryBlock endBlock = new MutableTryBlock(tryBlock.prev.endCodeAddress, endAddress);
MutableTryBlock<EH> endBlock = new MutableTryBlock<EH>(tryBlock.prev.endCodeAddress, endAddress);
tryBlock.prepend(endBlock);
return new TryBounds(startBlock, endBlock);
return new TryBounds<EH>(startBlock, endBlock);
}
tryBlock = tryBlock.next;
}
@ -285,21 +281,19 @@ public class TryListBuilder
/*The last range in the list ended before the end of the range being added.
We need to add a new range that starts at the end of the last range in the
list, and ends at the end of the range being added.*/
MutableTryBlock endBlock = new MutableTryBlock(listEnd.prev.endCodeAddress, endAddress);
MutableTryBlock<EH> endBlock = new MutableTryBlock<EH>(listEnd.prev.endCodeAddress, endAddress);
listEnd.prepend(endBlock);
return new TryBounds(startBlock, endBlock);
return new TryBounds<EH>(startBlock, endBlock);
}
public void addHandler(String type, int startAddress, int endAddress, int handlerAddress) {
TryBounds bounds = getBoundingRanges(startAddress, endAddress);
public void addHandler(int startAddress, int endAddress, EH handler) {
TryBounds<EH> bounds = getBoundingRanges(startAddress, endAddress);
MutableTryBlock startBlock = bounds.start;
MutableTryBlock endBlock = bounds.end;
ExceptionHandler handler = new ImmutableExceptionHandler(type, handlerAddress);
MutableTryBlock<EH> startBlock = bounds.start;
MutableTryBlock<EH> endBlock = bounds.end;
int previousEnd = startAddress;
MutableTryBlock tryBlock = startBlock;
MutableTryBlock<EH> tryBlock = startBlock;
/*Now we have the start and end ranges that exactly match the start and end
of the range being added. We need to iterate over all the ranges from the start
@ -309,7 +303,7 @@ public class TryListBuilder
{
//is there a hole? If so, add a new range to fill the hole
if (tryBlock.startCodeAddress > previousEnd) {
MutableTryBlock newBlock = new MutableTryBlock(previousEnd, tryBlock.startCodeAddress);
MutableTryBlock<EH> newBlock = new MutableTryBlock<EH>(previousEnd, tryBlock.startCodeAddress);
tryBlock.prepend(newBlock);
tryBlock = newBlock;
}
@ -320,10 +314,10 @@ public class TryListBuilder
} while (tryBlock.prev != endBlock);
}
public List<TryBlock> getTryBlocks() {
return Lists.newArrayList(new Iterator<TryBlock>() {
public List<TryBlock<EH>> getTryBlocks() {
return Lists.newArrayList(new Iterator<TryBlock<EH>>() {
// The next TryBlock to return. This has already been merged, if needed.
@Nullable private MutableTryBlock next;
@Nullable private MutableTryBlock<EH> next;
{
next = listStart;
@ -334,9 +328,9 @@ public class TryListBuilder
* Read the item that comes after the current value of the next field.
* @return The next item, or null if there is no next item
*/
@Nullable protected MutableTryBlock readNextItem() {
// We can assume that next is not null
MutableTryBlock ret = next.next;
@Nullable protected MutableTryBlock<EH> readNextItem() {
// We can assume that next is not null, due to the way iteration happens
MutableTryBlock<EH> ret = next.next;
if (ret == listEnd) {
return null;
@ -357,12 +351,13 @@ public class TryListBuilder
return next != null;
}
@Override public TryBlock next() {
@Override @Nonnull public TryBlock<EH> next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
TryBlock ret = next;
TryBlock<EH> ret = next;
next = readNextItem();
// ret can't be null (ret=next and hasNext returned true)
return ret;
}

View File

@ -42,11 +42,11 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.Random;
public class DexWriterTest {
public class DexDataWriterTest {
private Random random;
private NakedByteArrayOutputStream output = new NakedByteArrayOutputStream();
private int startPosition;
private DexWriter writer;
private DexDataWriter writer;
@Before
public void setup() throws IOException {
@ -55,7 +55,7 @@ public class DexWriterTest {
output.reset();
startPosition = 123;
int bufferSize = 256;
writer = new DexWriter(output, startPosition, bufferSize);
writer = new DexDataWriter(output, startPosition, bufferSize);
}
// Note: we use int[] rather than byte[] so that we don't have to cast every value when manually constructing an
@ -500,7 +500,7 @@ public class DexWriterTest {
public void testAlign() throws IOException {
// create a new writer so we can start at file position 0
startPosition = 0;
writer = new DexWriter(output, startPosition, 256);
writer = new DexDataWriter(output, startPosition, 256);
writer.align();
writer.write(1);

View File

@ -40,13 +40,13 @@ import java.io.IOException;
public class DexWriterSleb128Test {
private NakedByteArrayOutputStream output = new NakedByteArrayOutputStream();
private int startPosition;
private DexWriter writer;
private DexDataWriter writer;
public void setup() throws IOException {
output.reset();
startPosition = 123;
int bufferSize = 256;
writer = new DexWriter(output, startPosition, bufferSize);
writer = new DexDataWriter(output, startPosition, bufferSize);
}
@Test

View File

@ -40,13 +40,13 @@ import java.io.IOException;
public class DexWriterUleb128Test {
private NakedByteArrayOutputStream output = new NakedByteArrayOutputStream();
private int startPosition;
private DexWriter writer;
private DexDataWriter writer;
public void setup() throws IOException {
output.reset();
startPosition = 123;
int bufferSize = 256;
writer = new DexWriter(output, startPosition, bufferSize);
writer = new DexDataWriter(output, startPosition, bufferSize);
}
@Test

View File

@ -34,9 +34,11 @@ package org.jf.dexlib2.writer;
import com.google.common.collect.Lists;
import junit.framework.Assert;
import org.jf.dexlib2.Opcode;
import org.jf.dexlib2.iface.MethodImplementation;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.instruction.SwitchElement;
import org.jf.dexlib2.iface.instruction.formats.*;
import org.jf.dexlib2.iface.reference.StringReference;
import org.jf.dexlib2.immutable.ImmutableMethodImplementation;
import org.jf.dexlib2.immutable.instruction.*;
import org.jf.dexlib2.immutable.reference.ImmutableStringReference;
@ -44,17 +46,24 @@ import org.jf.dexlib2.writer.util.InstructionWriteUtil;
import org.junit.Before;
import org.junit.Test;
import javax.annotation.Nonnull;
import java.util.ArrayList;
public class JumboStringConversionTest {
private static final int MIN_NUM_JUMBO_STRINGS = 2;
private MockStringPool mStringPool;
private MockStringIndexProvider mockStringIndexProvider;
ArrayList<String> mJumboStrings;
private class InsnWriteUtil extends InstructionWriteUtil<Instruction, StringReference> {
public InsnWriteUtil(@Nonnull MethodImplementation implementation) {
super(implementation.getInstructions(), mockStringIndexProvider, ImmutableInstructionFactory.INSTANCE);
}
}
@Before
public void setup() {
mStringPool = new MockStringPool();
mockStringIndexProvider = new MockStringIndexProvider();
StringBuilder stringBuilder = new StringBuilder("a");
mJumboStrings = Lists.newArrayList();
int index = 0;
@ -64,8 +73,8 @@ public class JumboStringConversionTest {
for (int pos=stringBuilder.length()-1;pos>=0;pos--) {
for (char ch='a';ch<='z';ch++) {
stringBuilder.setCharAt(pos, ch);
mStringPool.intern(stringBuilder.toString(), index++);
if (mStringPool.getNumItems()>0xFFFF) {
mockStringIndexProvider.intern(stringBuilder.toString(), index++);
if (mockStringIndexProvider.getNumItems()>0xFFFF) {
mJumboStrings.add(stringBuilder.toString());
}
}
@ -81,13 +90,16 @@ public class JumboStringConversionTest {
@Test
public void testInstruction21c() {
ArrayList<ImmutableInstruction> instructions = Lists.newArrayList();
instructions.add(new ImmutableInstruction21c(Opcode.CONST_STRING, 0, new ImmutableStringReference(mJumboStrings.get(0))));
instructions.add(new ImmutableInstruction21c(Opcode.CONST_STRING, 0,
new ImmutableStringReference(mJumboStrings.get(0))));
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
ImmutableMethodImplementation methodImplementation =
new ImmutableMethodImplementation(1, instructions, null, null);
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
for (Instruction instr: writeUtil.getInstructions()) {
Assert.assertEquals("Jumbo string conversion was not performed!", instr.getOpcode(), Opcode.CONST_STRING_JUMBO);
Assert.assertEquals("Jumbo string conversion was not performed!",
instr.getOpcode(), Opcode.CONST_STRING_JUMBO);
}
}
@ -111,7 +123,7 @@ public class JumboStringConversionTest {
instructions.add(1, new ImmutableInstruction10t(Opcode.GOTO, 3));
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
for (Instruction instr: writeUtil.getInstructions()) {
if (instr instanceof Instruction10t) {
@ -128,7 +140,7 @@ public class JumboStringConversionTest {
instructions.add(1, new ImmutableInstruction20t(Opcode.GOTO_16, 4));
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
for (Instruction instr: writeUtil.getInstructions()) {
if (instr instanceof Instruction20t) {
@ -145,7 +157,7 @@ public class JumboStringConversionTest {
instructions.add(1, new ImmutableInstruction30t(Opcode.GOTO_32, 5));
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
for (Instruction instr: writeUtil.getInstructions()) {
if (instr instanceof Instruction30t) {
@ -162,7 +174,7 @@ public class JumboStringConversionTest {
instructions.add(1, new ImmutableInstruction21t(Opcode.IF_EQZ, 0, 4));
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
for (Instruction instr: writeUtil.getInstructions()) {
if (instr instanceof Instruction21t) {
@ -179,7 +191,7 @@ public class JumboStringConversionTest {
instructions.add(1, new ImmutableInstruction22t(Opcode.IF_EQ, 0, 1, 4));
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
for (Instruction instr: writeUtil.getInstructions()) {
if (instr instanceof Instruction22t) {
@ -196,7 +208,7 @@ public class JumboStringConversionTest {
instructions.add(1, new ImmutableInstruction31t(Opcode.PACKED_SWITCH, 0, 5));
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
for (Instruction instr: writeUtil.getInstructions()) {
if (instr instanceof Instruction31t) {
@ -213,7 +225,7 @@ public class JumboStringConversionTest {
instructions.add(1, new ImmutableInstruction31t(Opcode.PACKED_SWITCH, 0, 6));
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
for (Instruction instr: writeUtil.getInstructions()) {
if (instr instanceof PackedSwitchPayload) {
@ -232,7 +244,7 @@ public class JumboStringConversionTest {
instructions.add(1, new ImmutableInstruction31t(Opcode.SPARSE_SWITCH, 0, 12));
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
for (Instruction instr: writeUtil.getInstructions()) {
if (instr instanceof SparseSwitchPayload) {
@ -253,7 +265,7 @@ public class JumboStringConversionTest {
instructions.add(new ImmutableArrayPayload(4, null));
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
int codeOffset = 0;
for (Instruction instr: writeUtil.getInstructions()) {
@ -270,7 +282,7 @@ public class JumboStringConversionTest {
// packed switch instruction is already misaligned
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
int codeOffset = 0;
for (Instruction instr: writeUtil.getInstructions()) {
@ -288,7 +300,7 @@ public class JumboStringConversionTest {
instructions.add(4, new ImmutableInstruction10x(Opcode.NOP));
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
int codeOffset = 0;
for (Instruction instr: writeUtil.getInstructions()) {
@ -309,7 +321,7 @@ public class JumboStringConversionTest {
}
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
Instruction instr = writeUtil.getInstructions().iterator().next();
Assert.assertEquals("goto was not converted to goto/16 properly", instr.getOpcode(), Opcode.GOTO_16);
@ -325,7 +337,7 @@ public class JumboStringConversionTest {
}
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
Instruction instr = writeUtil.getInstructions().iterator().next();
Assert.assertEquals("goto/16 was not converted to goto/32 properly", instr.getOpcode(), Opcode.GOTO_32);
@ -349,7 +361,7 @@ public class JumboStringConversionTest {
instructions.add(new ImmutableArrayPayload(4, null));
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
Instruction instr = writeUtil.getInstructions().iterator().next();
Assert.assertEquals("goto was not converted to goto/16 properly", instr.getOpcode(), Opcode.GOTO_16);

View File

@ -0,0 +1,55 @@
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.jf.dexlib2.writer;
import com.google.common.collect.Maps;
import org.jf.dexlib2.iface.reference.StringReference;
import org.jf.dexlib2.writer.util.InstructionWriteUtil.StringIndexProvider;
import javax.annotation.Nonnull;
import java.util.HashMap;
public class MockStringIndexProvider implements StringIndexProvider<StringReference> {
private HashMap<String, Integer> internedItems = Maps.newHashMap();
public void intern(@Nonnull CharSequence string, int index) {
internedItems.put(string.toString(), index);
}
@Override public int getItemIndex(@Nonnull StringReference reference) {
return internedItems.get(reference.getString());
}
public int getNumItems() {
return internedItems.size();
}
}

View File

@ -33,6 +33,7 @@ package org.jf.dexlib2.writer.util;
import com.google.common.collect.ImmutableList;
import junit.framework.Assert;
import org.jf.dexlib2.iface.ExceptionHandler;
import org.jf.dexlib2.iface.TryBlock;
import org.jf.dexlib2.immutable.ImmutableExceptionHandler;
import org.jf.dexlib2.immutable.ImmutableTryBlock;
@ -41,13 +42,16 @@ import org.junit.Test;
import java.util.List;
public class TryListBuilderTest {
private static class TryListBuilder extends org.jf.dexlib2.writer.util.TryListBuilder<ExceptionHandler> {
}
@Test
public void testSingleCatchAll_Beginning() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler(null, 0, 10, 5);
tlb.addHandler(0, 10, new ImmutableExceptionHandler(null, 5));
List<TryBlock> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock> expected = ImmutableList.of(new ImmutableTryBlock(0, 10,
ImmutableList.of(new ImmutableExceptionHandler(null, 5))));
@ -59,9 +63,9 @@ public class TryListBuilderTest {
public void testSingleCatchAll_Middle() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler(null, 5, 10, 15);
tlb.addHandler(5, 10, new ImmutableExceptionHandler(null, 15));
List<TryBlock> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock> expected = ImmutableList.of(new ImmutableTryBlock(5, 5,
ImmutableList.of(new ImmutableExceptionHandler(null, 15))));
@ -73,9 +77,9 @@ public class TryListBuilderTest {
public void testSingleCatch_Beginning() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler("Ljava/lang/Exception;", 0, 10, 5);
tlb.addHandler(0, 10, new ImmutableExceptionHandler("Ljava/lang/Exception;", 5));
List<TryBlock> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock> expected = ImmutableList.of(new ImmutableTryBlock(0, 10,
ImmutableList.of(new ImmutableExceptionHandler("Ljava/lang/Exception;", 5))));
@ -87,9 +91,9 @@ public class TryListBuilderTest {
public void testSingleCatch_Middle() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler("Ljava/lang/Exception;", 5, 10, 15);
tlb.addHandler(5, 10, new ImmutableExceptionHandler("Ljava/lang/Exception;", 15));
List<TryBlock> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock> expected = ImmutableList.of(new ImmutableTryBlock(5, 5,
ImmutableList.of(new ImmutableExceptionHandler("Ljava/lang/Exception;", 15))));
@ -101,10 +105,10 @@ public class TryListBuilderTest {
public void testOverlap_End_After() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler("LException1;", 0, 10, 5);
tlb.addHandler("LException2;", 10, 20, 6);
tlb.addHandler(0, 10, new ImmutableExceptionHandler("LException1;", 5));
tlb.addHandler(10, 20, new ImmutableExceptionHandler("LException2;", 6));
List<TryBlock> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock> expected = ImmutableList.of(
new ImmutableTryBlock(0, 10,
@ -119,10 +123,10 @@ public class TryListBuilderTest {
public void testOverlap_After_After() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler("LException1;", 0, 10, 5);
tlb.addHandler("LException2;", 15, 20, 6);
tlb.addHandler(0, 10, new ImmutableExceptionHandler("LException1;", 5));
tlb.addHandler(15, 20, new ImmutableExceptionHandler("LException2;", 6));
List<TryBlock> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock> expected = ImmutableList.of(
new ImmutableTryBlock(0, 10,
@ -137,10 +141,10 @@ public class TryListBuilderTest {
public void testOverlap_Before_Start() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler("LException1;", 5, 10, 5);
tlb.addHandler("LException2;", 0, 5, 6);
tlb.addHandler(5, 10, new ImmutableExceptionHandler("LException1;", 5));
tlb.addHandler(0, 5, new ImmutableExceptionHandler("LException2;", 6));
List<TryBlock> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock> expected = ImmutableList.of(
new ImmutableTryBlock(0, 5,
@ -155,10 +159,10 @@ public class TryListBuilderTest {
public void testOverlap_Before_Before() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler("LException1;", 5, 10, 5);
tlb.addHandler("LException2;", 0, 3, 6);
tlb.addHandler(5, 10, new ImmutableExceptionHandler("LException1;", 5));
tlb.addHandler(0, 3, new ImmutableExceptionHandler("LException2;", 6));
List<TryBlock> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock> expected = ImmutableList.of(
new ImmutableTryBlock(0, 3,
@ -173,10 +177,10 @@ public class TryListBuilderTest {
public void testOverlap_Start_End() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler("LException1;", 0, 10, 5);
tlb.addHandler("LException2;", 0, 10, 6);
tlb.addHandler(0, 10, new ImmutableExceptionHandler("LException1;", 5));
tlb.addHandler(0, 10, new ImmutableExceptionHandler("LException2;", 6));
List<TryBlock> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock> expected = ImmutableList.of(
new ImmutableTryBlock(0, 10,
@ -191,10 +195,10 @@ public class TryListBuilderTest {
public void testOverlap_Start_Middle() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler("LException1;", 0, 10, 5);
tlb.addHandler("LException2;", 0, 5, 6);
tlb.addHandler(0, 10, new ImmutableExceptionHandler("LException1;", 5));
tlb.addHandler(0, 5, new ImmutableExceptionHandler("LException2;", 6));
List<TryBlock> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock> expected = ImmutableList.of(
new ImmutableTryBlock(0, 5,
@ -212,10 +216,10 @@ public class TryListBuilderTest {
public void testOverlap_Middle_Middle() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler("LException1;", 0, 10, 5);
tlb.addHandler("LException2;", 2, 7, 6);
tlb.addHandler(0, 10, new ImmutableExceptionHandler("LException1;", 5));
tlb.addHandler(2, 7, new ImmutableExceptionHandler("LException2;", 6));
List<TryBlock> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock> expected = ImmutableList.of(
new ImmutableTryBlock(0, 2,
@ -236,10 +240,10 @@ public class TryListBuilderTest {
public void testOverlap_Middle_End() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler("LException1;", 0, 10, 5);
tlb.addHandler("LException2;", 5, 10, 6);
tlb.addHandler(0, 10, new ImmutableExceptionHandler("LException1;", 5));
tlb.addHandler(5, 10, new ImmutableExceptionHandler("LException2;", 6));
List<TryBlock> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock> expected = ImmutableList.of(
new ImmutableTryBlock(0, 5,
@ -257,10 +261,10 @@ public class TryListBuilderTest {
public void testOverlap_Beginning_After() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler("LException1;", 0, 10, 5);
tlb.addHandler("LException2;", 0, 15, 6);
tlb.addHandler(0, 10, new ImmutableExceptionHandler("LException1;", 5));
tlb.addHandler(0, 15, new ImmutableExceptionHandler("LException2;", 6));
List<TryBlock> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock> expected = ImmutableList.of(
new ImmutableTryBlock(0, 10,
@ -278,10 +282,10 @@ public class TryListBuilderTest {
public void testOverlap_Middle_After() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler("LException1;", 0, 10, 5);
tlb.addHandler("LException2;", 5, 15, 6);
tlb.addHandler(0, 10, new ImmutableExceptionHandler("LException1;", 5));
tlb.addHandler(5, 15, new ImmutableExceptionHandler("LException2;", 6));
List<TryBlock> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock> expected = ImmutableList.of(
new ImmutableTryBlock(0, 5,
@ -302,10 +306,10 @@ public class TryListBuilderTest {
public void testOverlap_Before_End() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler("LException1;", 5, 10, 5);
tlb.addHandler("LException2;", 0, 10, 6);
tlb.addHandler(5, 10, new ImmutableExceptionHandler("LException1;", 5));
tlb.addHandler(0, 10, new ImmutableExceptionHandler("LException2;", 6));
List<TryBlock> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock> expected = ImmutableList.of(
new ImmutableTryBlock(0, 5,
@ -323,10 +327,10 @@ public class TryListBuilderTest {
public void testOverlap_Before_Middle() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler("LException1;", 5, 10, 5);
tlb.addHandler("LException2;", 0, 7, 6);
tlb.addHandler(5, 10, new ImmutableExceptionHandler("LException1;", 5));
tlb.addHandler(0, 7, new ImmutableExceptionHandler("LException2;", 6));
List<TryBlock> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock> expected = ImmutableList.of(
new ImmutableTryBlock(0, 5,
@ -347,10 +351,10 @@ public class TryListBuilderTest {
public void testOverlap_Before_After() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler("LException1;", 5, 10, 5);
tlb.addHandler("LException2;", 0, 15, 6);
tlb.addHandler(5, 10, new ImmutableExceptionHandler("LException1;", 5));
tlb.addHandler(0, 15, new ImmutableExceptionHandler("LException2;", 6));
List<TryBlock> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock> expected = ImmutableList.of(
new ImmutableTryBlock(0, 5,
@ -371,11 +375,11 @@ public class TryListBuilderTest {
public void testOverlap_Hole() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler("LException1;", 1, 5, 5);
tlb.addHandler("LException1;", 10, 14, 5);
tlb.addHandler("LException2;", 0, 15, 6);
tlb.addHandler(1, 5, new ImmutableExceptionHandler("LException1;", 5));
tlb.addHandler(10, 14, new ImmutableExceptionHandler("LException1;", 5));
tlb.addHandler(0, 15, new ImmutableExceptionHandler("LException2;", 6));
List<TryBlock> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock> expected = ImmutableList.of(
new ImmutableTryBlock(0, 1,
@ -403,10 +407,10 @@ public class TryListBuilderTest {
public void testHandlerMerge_Same() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler("LException1;", 5, 10, 5);
tlb.addHandler("LException1;", 0, 15, 5);
tlb.addHandler(5, 10, new ImmutableExceptionHandler("LException1;", 5));
tlb.addHandler(0, 15, new ImmutableExceptionHandler("LException1;", 5));
List<TryBlock> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock> expected = ImmutableList.of(
new ImmutableTryBlock(0, 15,
@ -420,10 +424,10 @@ public class TryListBuilderTest {
public void testHandlerMerge_DifferentType() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler("LException1;", 5, 10, 5);
tlb.addHandler("LException2;", 0, 15, 6);
tlb.addHandler(5, 10, new ImmutableExceptionHandler("LException1;", 5));
tlb.addHandler(0, 15, new ImmutableExceptionHandler("LException2;", 6));
List<TryBlock> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock> expected = ImmutableList.of(
new ImmutableTryBlock(0, 5,
@ -444,9 +448,9 @@ public class TryListBuilderTest {
public void testHandlerMerge_DifferentAddress() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler("LException1;", 5, 10, 5);
tlb.addHandler(5, 10, new ImmutableExceptionHandler("LException1;", 5));
try {
tlb.addHandler("LException1;", 0, 15, 6);
tlb.addHandler(0, 15, new ImmutableExceptionHandler("LException1;", 6));
} catch (TryListBuilder.InvalidTryException ex) {
return;
}
@ -457,10 +461,10 @@ public class TryListBuilderTest {
public void testHandlerMerge_Exception_Catchall() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler("LException1;", 5, 10, 5);
tlb.addHandler(null, 0, 15, 6);
tlb.addHandler(5, 10, new ImmutableExceptionHandler("LException1;", 5));
tlb.addHandler(0, 15, new ImmutableExceptionHandler(null, 6));
List<TryBlock> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock> expected = ImmutableList.of(
new ImmutableTryBlock(0, 5,
@ -481,10 +485,10 @@ public class TryListBuilderTest {
public void testHandlerMerge_Catchall_Exception() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler(null, 5, 10, 5);
tlb.addHandler("LException1;", 0, 15, 6);
tlb.addHandler(5, 10, new ImmutableExceptionHandler(null, 5));
tlb.addHandler(0, 15, new ImmutableExceptionHandler("LException1;", 6));
List<TryBlock> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock> expected = ImmutableList.of(
new ImmutableTryBlock(0, 5,
@ -505,10 +509,10 @@ public class TryListBuilderTest {
public void testHandlerMerge_Catchall_Catchall() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler(null, 5, 10, 5);
tlb.addHandler(null, 0, 15, 5);
tlb.addHandler(5, 10, new ImmutableExceptionHandler(null, 5));
tlb.addHandler(0, 15, new ImmutableExceptionHandler(null, 5));
List<TryBlock> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock> expected = ImmutableList.of(
new ImmutableTryBlock(0, 15,
@ -522,9 +526,9 @@ public class TryListBuilderTest {
public void testHandlerMerge_Catchall_Catchall_DifferentAddress() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler(null, 5, 10, 5);
tlb.addHandler(5, 10, new ImmutableExceptionHandler(null, 5));
try {
tlb.addHandler(null, 0, 15, 6);
tlb.addHandler(0, 15, new ImmutableExceptionHandler(null, 6));
} catch (TryListBuilder.InvalidTryException ex) {
return;
}
@ -535,12 +539,12 @@ public class TryListBuilderTest {
public void testHandlerMerge_MergeSame() {
TryListBuilder tlb = new TryListBuilder();
tlb.addHandler(null, 0, 15, 6);
tlb.addHandler("LException1;", 10, 20, 5);
tlb.addHandler("LException1;", 20, 30, 5);
tlb.addHandler(null, 25, 40, 6);
tlb.addHandler(0, 15, new ImmutableExceptionHandler(null, 6));
tlb.addHandler(10, 20, new ImmutableExceptionHandler("LException1;", 5));
tlb.addHandler(20, 30, new ImmutableExceptionHandler("LException1;", 5));
tlb.addHandler(25, 40, new ImmutableExceptionHandler(null, 6));
List<TryBlock> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = tlb.getTryBlocks();
List<? extends TryBlock> expected = ImmutableList.of(
new ImmutableTryBlock(0, 10,

View File

@ -388,7 +388,7 @@ method returns[Method ret]
annotations
)
{
List<TryBlock> tryBlocks = $catches.tryBlocks;
List<TryBlock<? extends ExceptionHandler>> tryBlocks = $catches.tryBlocks;
List<DebugItem> debugItems = $ordered_debug_directives.debugItems;
MethodImplementation methodImplementation = null;
@ -568,12 +568,12 @@ sparse_switch_declaration
}
};
catches returns[List<TryBlock> tryBlocks]
catches returns[List<TryBlock<? extends ExceptionHandler>> tryBlocks]
@init {tryBlocks = Lists.newArrayList();}
: ^(I_CATCHES (catch_directive { tryBlocks.add($catch_directive.tryBlock); })*
(catchall_directive { tryBlocks.add($catchall_directive.tryBlock); })*);
catch_directive returns[TryBlock tryBlock]
catch_directive returns[TryBlock<? extends ExceptionHandler> tryBlock]
: ^(I_CATCH address nonvoid_type_descriptor from=offset_or_label_absolute[$address.address] to=offset_or_label_absolute[$address.address]
using=offset_or_label_absolute[$address.address])
{
@ -588,7 +588,7 @@ catch_directive returns[TryBlock tryBlock]
ImmutableList.of(new ImmutableExceptionHandler(type, handlerAddress)));
};
catchall_directive returns[TryBlock tryBlock]
catchall_directive returns[TryBlock<? extends ExceptionHandler> tryBlock]
: ^(I_CATCHALL address from=offset_or_label_absolute[$address.address] to=offset_or_label_absolute[$address.address]
using=offset_or_label_absolute[$address.address])
{

View File

@ -79,6 +79,7 @@ public class CollectionUtils {
for (T element1: it1) {
T element2;
try {
// TODO: would checking hasNext be more efficient?
element2 = elements2.next();
} catch (NoSuchElementException ex) {
return 1;