mirror of
https://github.com/revanced/smali.git
synced 2025-05-30 20:40:11 +02:00
Implementation of new generificationified writer functionality
This commit is contained in:
parent
afc0a7d325
commit
1bf6f23245
@ -419,7 +419,7 @@ public class MethodDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void addTries(List<MethodItem> methodItems) {
|
private void addTries(List<MethodItem> methodItems) {
|
||||||
List<? extends TryBlock> tryBlocks = methodImpl.getTryBlocks();
|
List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks = methodImpl.getTryBlocks();
|
||||||
if (tryBlocks.size() == 0) {
|
if (tryBlocks.size() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -427,7 +427,7 @@ public class MethodDefinition {
|
|||||||
int lastInstructionAddress = instructionOffsetMap.getInstructionCodeOffset(instructions.size() - 1);
|
int lastInstructionAddress = instructionOffsetMap.getInstructionCodeOffset(instructions.size() - 1);
|
||||||
int codeSize = lastInstructionAddress + instructions.get(instructions.size() - 1).getCodeUnits();
|
int codeSize = lastInstructionAddress + instructions.get(instructions.size() - 1).getCodeUnits();
|
||||||
|
|
||||||
for (TryBlock tryBlock: tryBlocks) {
|
for (TryBlock<? extends ExceptionHandler> tryBlock: tryBlocks) {
|
||||||
int startAddress = tryBlock.getStartCodeAddress();
|
int startAddress = tryBlock.getStartCodeAddress();
|
||||||
int endAddress = startAddress + tryBlock.getCodeUnitCount();
|
int endAddress = startAddress + tryBlock.getCodeUnitCount();
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ public final class DexFileFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void writeDexFile(String path, DexFile dexFile) throws IOException {
|
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() {}
|
private DexFileFactory() {}
|
||||||
|
@ -1035,7 +1035,7 @@ public class MethodAnalyzer {
|
|||||||
|
|
||||||
RegisterType exceptionType = RegisterType.UNKNOWN_TYPE;
|
RegisterType exceptionType = RegisterType.UNKNOWN_TYPE;
|
||||||
|
|
||||||
for (TryBlock tryBlock: methodImpl.getTryBlocks()) {
|
for (TryBlock<? extends ExceptionHandler> tryBlock: methodImpl.getTryBlocks()) {
|
||||||
for (ExceptionHandler handler: tryBlock.getExceptionHandlers()) {
|
for (ExceptionHandler handler: tryBlock.getExceptionHandlers()) {
|
||||||
|
|
||||||
if (handler.getHandlerCodeAddress() == instructionAddress) {
|
if (handler.getHandlerCodeAddress() == instructionAddress) {
|
||||||
|
@ -65,7 +65,7 @@ public abstract class BaseAnnotation implements Annotation {
|
|||||||
return CollectionUtils.compareAsSet(getElements(), o.getElements());
|
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
|
@Override
|
||||||
public int compare(Annotation annotation1, Annotation annotation2) {
|
public int compare(Annotation annotation1, Annotation annotation2) {
|
||||||
return annotation1.getType().compareTo(annotation2.getType());
|
return annotation1.getType().compareTo(annotation2.getType());
|
||||||
|
@ -31,9 +31,10 @@
|
|||||||
|
|
||||||
package org.jf.dexlib2.base;
|
package org.jf.dexlib2.base;
|
||||||
|
|
||||||
|
import org.jf.dexlib2.iface.ExceptionHandler;
|
||||||
import org.jf.dexlib2.iface.TryBlock;
|
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) {
|
@Override public boolean equals(Object o) {
|
||||||
if (o instanceof TryBlock) {
|
if (o instanceof TryBlock) {
|
||||||
TryBlock other = (TryBlock)o;
|
TryBlock other = (TryBlock)o;
|
||||||
|
@ -37,7 +37,7 @@ import org.jf.dexlib2.iface.ExceptionHandler;
|
|||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class DexBackedCatchAllExceptionHandler extends BaseExceptionHandler implements ExceptionHandler {
|
public class DexBackedCatchAllExceptionHandler extends DexBackedExceptionHandler {
|
||||||
private final int handlerCodeAddress;
|
private final int handlerCodeAddress;
|
||||||
|
|
||||||
public DexBackedCatchAllExceptionHandler(@Nonnull DexReader reader) {
|
public DexBackedCatchAllExceptionHandler(@Nonnull DexReader reader) {
|
||||||
|
@ -32,22 +32,6 @@
|
|||||||
package org.jf.dexlib2.dexbacked;
|
package org.jf.dexlib2.dexbacked;
|
||||||
|
|
||||||
import org.jf.dexlib2.base.BaseExceptionHandler;
|
import org.jf.dexlib2.base.BaseExceptionHandler;
|
||||||
import org.jf.dexlib2.iface.ExceptionHandler;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
public abstract class DexBackedExceptionHandler extends BaseExceptionHandler {
|
||||||
|
|
||||||
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; }
|
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,6 @@ import org.jf.dexlib2.dexbacked.util.DebugInfo;
|
|||||||
import org.jf.dexlib2.dexbacked.util.FixedSizeList;
|
import org.jf.dexlib2.dexbacked.util.FixedSizeList;
|
||||||
import org.jf.dexlib2.dexbacked.util.VariableSizeLookaheadIterator;
|
import org.jf.dexlib2.dexbacked.util.VariableSizeLookaheadIterator;
|
||||||
import org.jf.dexlib2.iface.MethodImplementation;
|
import org.jf.dexlib2.iface.MethodImplementation;
|
||||||
import org.jf.dexlib2.iface.TryBlock;
|
|
||||||
import org.jf.dexlib2.iface.debug.DebugItem;
|
import org.jf.dexlib2.iface.debug.DebugItem;
|
||||||
import org.jf.dexlib2.iface.instruction.Instruction;
|
import org.jf.dexlib2.iface.instruction.Instruction;
|
||||||
import org.jf.util.AlignmentUtils;
|
import org.jf.util.AlignmentUtils;
|
||||||
@ -87,7 +86,7 @@ public class DexBackedMethodImplementation implements MethodImplementation {
|
|||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@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
|
// 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);
|
final int triesSize = dexFile.readUshort(codeOffset + CodeItem.TRIES_SIZE_OFFSET);
|
||||||
if (triesSize > 0) {
|
if (triesSize > 0) {
|
||||||
@ -96,10 +95,10 @@ public class DexBackedMethodImplementation implements MethodImplementation {
|
|||||||
codeOffset + CodeItem.INSTRUCTION_START_OFFSET + (instructionsSize*2), 4);
|
codeOffset + CodeItem.INSTRUCTION_START_OFFSET + (instructionsSize*2), 4);
|
||||||
final int handlersStartOffset = triesStartOffset + triesSize*CodeItem.TryItem.ITEM_SIZE;
|
final int handlersStartOffset = triesStartOffset + triesSize*CodeItem.TryItem.ITEM_SIZE;
|
||||||
|
|
||||||
return new FixedSizeList<TryBlock>() {
|
return new FixedSizeList<DexBackedTryBlock>() {
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public TryBlock readItem(int index) {
|
public DexBackedTryBlock readItem(int index) {
|
||||||
return new DexBackedTryBlock(dexFile,
|
return new DexBackedTryBlock(dexFile,
|
||||||
triesStartOffset + index*CodeItem.TryItem.ITEM_SIZE,
|
triesStartOffset + index*CodeItem.TryItem.ITEM_SIZE,
|
||||||
handlersStartOffset);
|
handlersStartOffset);
|
||||||
|
@ -34,19 +34,15 @@ package org.jf.dexlib2.dexbacked;
|
|||||||
import org.jf.dexlib2.base.BaseTryBlock;
|
import org.jf.dexlib2.base.BaseTryBlock;
|
||||||
import org.jf.dexlib2.dexbacked.raw.CodeItem;
|
import org.jf.dexlib2.dexbacked.raw.CodeItem;
|
||||||
import org.jf.dexlib2.dexbacked.util.VariableSizeList;
|
import org.jf.dexlib2.dexbacked.util.VariableSizeList;
|
||||||
import org.jf.dexlib2.iface.ExceptionHandler;
|
|
||||||
import org.jf.dexlib2.iface.TryBlock;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class DexBackedTryBlock extends BaseTryBlock implements TryBlock {
|
public class DexBackedTryBlock extends BaseTryBlock<DexBackedExceptionHandler> {
|
||||||
@Nonnull public final DexBackedDexFile dexFile;
|
@Nonnull public final DexBackedDexFile dexFile;
|
||||||
private final int tryItemOffset;
|
private final int tryItemOffset;
|
||||||
private final int handlersStartOffset;
|
private final int handlersStartOffset;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public DexBackedTryBlock(@Nonnull DexBackedDexFile dexFile,
|
public DexBackedTryBlock(@Nonnull DexBackedDexFile dexFile,
|
||||||
int tryItemOffset,
|
int tryItemOffset,
|
||||||
int handlersStartOffset) {
|
int handlersStartOffset) {
|
||||||
@ -65,31 +61,31 @@ public class DexBackedTryBlock extends BaseTryBlock implements TryBlock {
|
|||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public List<? extends ExceptionHandler> getExceptionHandlers() {
|
public List<? extends DexBackedExceptionHandler> getExceptionHandlers() {
|
||||||
DexReader reader = dexFile.readerAt(
|
DexReader reader = dexFile.readerAt(
|
||||||
handlersStartOffset + dexFile.readUshort(tryItemOffset + CodeItem.TryItem.HANDLER_OFFSET));
|
handlersStartOffset + dexFile.readUshort(tryItemOffset + CodeItem.TryItem.HANDLER_OFFSET));
|
||||||
final int encodedSize = reader.readSleb128();
|
final int encodedSize = reader.readSleb128();
|
||||||
|
|
||||||
if (encodedSize > 0) {
|
if (encodedSize > 0) {
|
||||||
//no catch-all
|
//no catch-all
|
||||||
return new VariableSizeList<ExceptionHandler>(dexFile, reader.getOffset(), encodedSize) {
|
return new VariableSizeList<DexBackedTypedExceptionHandler>(dexFile, reader.getOffset(), encodedSize) {
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
protected ExceptionHandler readNextItem(@Nonnull DexReader reader, int index) {
|
protected DexBackedTypedExceptionHandler readNextItem(@Nonnull DexReader reader, int index) {
|
||||||
return new DexBackedExceptionHandler(reader);
|
return new DexBackedTypedExceptionHandler(reader);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
//with catch-all
|
//with catch-all
|
||||||
final int sizeWithCatchAll = (-1 * encodedSize) + 1;
|
final int sizeWithCatchAll = (-1 * encodedSize) + 1;
|
||||||
return new VariableSizeList<ExceptionHandler>(dexFile, reader.getOffset(), sizeWithCatchAll) {
|
return new VariableSizeList<DexBackedExceptionHandler>(dexFile, reader.getOffset(), sizeWithCatchAll) {
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
protected ExceptionHandler readNextItem(@Nonnull DexReader dexReader, int index) {
|
protected DexBackedExceptionHandler readNextItem(@Nonnull DexReader dexReader, int index) {
|
||||||
if (index == sizeWithCatchAll-1) {
|
if (index == sizeWithCatchAll-1) {
|
||||||
return new DexBackedCatchAllExceptionHandler(dexReader);
|
return new DexBackedCatchAllExceptionHandler(dexReader);
|
||||||
} else {
|
} else {
|
||||||
return new DexBackedExceptionHandler(dexReader);
|
return new DexBackedTypedExceptionHandler(dexReader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -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; }
|
||||||
|
}
|
@ -70,7 +70,7 @@ public interface MethodImplementation {
|
|||||||
*
|
*
|
||||||
* @return A list of the TryBlock items
|
* @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.
|
* Get a list of debug items for this method.
|
||||||
|
@ -38,7 +38,7 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* This class represents an individual try block and associated set of handlers.
|
* 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.
|
* Gets the code offset of the start of this try block.
|
||||||
*
|
*
|
||||||
@ -67,7 +67,7 @@ public interface TryBlock {
|
|||||||
*
|
*
|
||||||
* @return A list of ExceptionHandler objects
|
* @return A list of ExceptionHandler objects
|
||||||
*/
|
*/
|
||||||
@Nonnull List<? extends ExceptionHandler> getExceptionHandlers();
|
@Nonnull List<? extends EH> getExceptionHandlers();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares this TryBlock to another TryBlock for equality.
|
* Compares this TryBlock to another TryBlock for equality.
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
package org.jf.dexlib2.immutable;
|
package org.jf.dexlib2.immutable;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import org.jf.dexlib2.iface.ExceptionHandler;
|
||||||
import org.jf.dexlib2.iface.MethodImplementation;
|
import org.jf.dexlib2.iface.MethodImplementation;
|
||||||
import org.jf.dexlib2.iface.TryBlock;
|
import org.jf.dexlib2.iface.TryBlock;
|
||||||
import org.jf.dexlib2.iface.debug.DebugItem;
|
import org.jf.dexlib2.iface.debug.DebugItem;
|
||||||
@ -52,7 +53,7 @@ public class ImmutableMethodImplementation implements MethodImplementation {
|
|||||||
|
|
||||||
public ImmutableMethodImplementation(int registerCount,
|
public ImmutableMethodImplementation(int registerCount,
|
||||||
@Nullable Iterable<? extends Instruction> instructions,
|
@Nullable Iterable<? extends Instruction> instructions,
|
||||||
@Nullable List<? extends TryBlock> tryBlocks,
|
@Nullable List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks,
|
||||||
@Nullable Iterable<? extends DebugItem> debugItems) {
|
@Nullable Iterable<? extends DebugItem> debugItems) {
|
||||||
this.registerCount = registerCount;
|
this.registerCount = registerCount;
|
||||||
this.instructions = ImmutableInstruction.immutableListOf(instructions);
|
this.instructions = ImmutableInstruction.immutableListOf(instructions);
|
||||||
|
@ -42,7 +42,7 @@ import javax.annotation.Nonnull;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ImmutableTryBlock extends BaseTryBlock implements TryBlock {
|
public class ImmutableTryBlock extends BaseTryBlock<ImmutableExceptionHandler> {
|
||||||
protected final int startCodeAddress;
|
protected final int startCodeAddress;
|
||||||
protected final int codeUnitCount;
|
protected final int codeUnitCount;
|
||||||
@Nonnull protected final ImmutableList<? extends ImmutableExceptionHandler> exceptionHandlers;
|
@Nonnull protected final ImmutableList<? extends ImmutableExceptionHandler> exceptionHandlers;
|
||||||
@ -63,7 +63,7 @@ public class ImmutableTryBlock extends BaseTryBlock implements TryBlock {
|
|||||||
this.exceptionHandlers = ImmutableUtils.nullToEmptyList(exceptionHandlers);
|
this.exceptionHandlers = ImmutableUtils.nullToEmptyList(exceptionHandlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ImmutableTryBlock of(TryBlock tryBlock) {
|
public static ImmutableTryBlock of(TryBlock<? extends ExceptionHandler> tryBlock) {
|
||||||
if (tryBlock instanceof ImmutableTryBlock) {
|
if (tryBlock instanceof ImmutableTryBlock) {
|
||||||
return (ImmutableTryBlock)tryBlock;
|
return (ImmutableTryBlock)tryBlock;
|
||||||
}
|
}
|
||||||
@ -81,12 +81,13 @@ public class ImmutableTryBlock extends BaseTryBlock implements TryBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@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);
|
return CONVERTER.toList(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final ImmutableConverter<ImmutableTryBlock, TryBlock> CONVERTER =
|
private static final ImmutableConverter<ImmutableTryBlock, TryBlock<? extends ExceptionHandler>> CONVERTER =
|
||||||
new ImmutableConverter<ImmutableTryBlock, TryBlock>() {
|
new ImmutableConverter<ImmutableTryBlock, TryBlock<? extends ExceptionHandler>>() {
|
||||||
@Override
|
@Override
|
||||||
protected boolean isImmutable(@Nonnull TryBlock item) {
|
protected boolean isImmutable(@Nonnull TryBlock item) {
|
||||||
return item instanceof ImmutableTryBlock;
|
return item instanceof ImmutableTryBlock;
|
||||||
@ -94,7 +95,7 @@ public class ImmutableTryBlock extends BaseTryBlock implements TryBlock {
|
|||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
protected ImmutableTryBlock makeImmutable(@Nonnull TryBlock item) {
|
protected ImmutableTryBlock makeImmutable(@Nonnull TryBlock<? extends ExceptionHandler> item) {
|
||||||
return ImmutableTryBlock.of(item);
|
return ImmutableTryBlock.of(item);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -38,7 +38,7 @@ import org.jf.dexlib2.iface.reference.MethodReference;
|
|||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.List;
|
import java.util.Collection;
|
||||||
|
|
||||||
public final class MethodUtil {
|
public final class MethodUtil {
|
||||||
private static int directMask = AccessFlags.STATIC.getValue() | AccessFlags.PRIVATE.getValue() |
|
private static int directMask = AccessFlags.STATIC.getValue() | AccessFlags.PRIVATE.getValue() |
|
||||||
@ -76,7 +76,8 @@ public final class MethodUtil {
|
|||||||
return getParameterRegisterCount(methodRef.getParameterTypes(), isStatic);
|
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;
|
int regCount = 0;
|
||||||
for (CharSequence paramType: parameterTypes) {
|
for (CharSequence paramType: parameterTypes) {
|
||||||
int firstChar = paramType.charAt(0);
|
int firstChar = paramType.charAt(0);
|
||||||
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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);
|
||||||
|
}
|
@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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);
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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;
|
||||||
|
}
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
163
dexlib2/src/main/java/org/jf/dexlib2/writer/DebugWriter.java
Normal file
163
dexlib2/src/main/java/org/jf/dexlib2/writer/DebugWriter.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
282
dexlib2/src/main/java/org/jf/dexlib2/writer/DexDataWriter.java
Normal file
282
dexlib2/src/main/java/org/jf/dexlib2/writer/DexDataWriter.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
@ -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
@ -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);
|
||||||
|
}
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
@ -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()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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);
|
||||||
|
}
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012, Google Inc.
|
* Copyright 2013, Google Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -32,9 +32,10 @@
|
|||||||
package org.jf.dexlib2.writer;
|
package org.jf.dexlib2.writer;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class MockStringPool extends StringPool {
|
public interface IndexSection<Key> {
|
||||||
public void intern(@Nonnull CharSequence string, int index) {
|
int getItemIndex(@Nonnull Key key);
|
||||||
internedStringIdItems.put(string.toString(), index);
|
@Nonnull Collection<? extends Map.Entry<? extends Key, Integer>> getItems();
|
||||||
}
|
|
||||||
}
|
}
|
@ -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);
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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);
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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> {
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
41
dexlib2/src/main/java/org/jf/dexlib2/writer/TypeSection.java
Normal file
41
dexlib2/src/main/java/org/jf/dexlib2/writer/TypeSection.java
Normal 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);
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012, Google Inc.
|
* Copyright 2013, Google Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* 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.
|
* 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.Function;
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.collect.FluentIterable;
|
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.collect.Ordering;
|
||||||
import com.google.common.primitives.Ints;
|
import com.google.common.primitives.Ints;
|
||||||
import org.jf.dexlib2.iface.Annotation;
|
import org.jf.dexlib2.iface.Annotation;
|
||||||
import org.jf.dexlib2.iface.Method;
|
import org.jf.dexlib2.iface.Method;
|
||||||
import org.jf.dexlib2.iface.MethodParameter;
|
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.CollectionUtils;
|
||||||
import org.jf.util.ExceptionWithContext;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.io.IOException;
|
import java.util.AbstractCollection;
|
||||||
import java.util.*;
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class AnnotationSetRefPool {
|
public class AnnotationSetRefPool extends BaseNullableOffsetPool<Key>
|
||||||
@Nonnull private final Map<Key, Integer> internedAnnotationSetRefItems = Maps.newHashMap();
|
implements AnnotationSetRefSection<Set<? extends Annotation>, Key> {
|
||||||
@Nonnull private final DexFile dexFile;
|
@Nonnull private final AnnotationSetPool annotationSetPool;
|
||||||
private int sectionOffset = -1;
|
|
||||||
|
|
||||||
public AnnotationSetRefPool(@Nonnull DexFile dexFile) {
|
public AnnotationSetRefPool(@Nonnull AnnotationSetPool annotationSetPool) {
|
||||||
this.dexFile = dexFile;
|
this.annotationSetPool = annotationSetPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void intern(@Nonnull Method method) {
|
public void intern(@Nonnull Method method) {
|
||||||
Key annotationSetRefKey = new Key(method);
|
Key annotationSetRefKey = new Key(method);
|
||||||
Integer prev = internedAnnotationSetRefItems.put(annotationSetRefKey, 0);
|
Integer prev = internedItems.put(annotationSetRefKey, 0);
|
||||||
if (prev == null) {
|
if (prev == null) {
|
||||||
for (Set<? extends Annotation> annotationSet: annotationSetRefKey.getAnnotationSets()) {
|
for (Set<? extends Annotation> annotationSet: annotationSetRefKey.getAnnotationSets()) {
|
||||||
dexFile.annotationSetPool.intern(annotationSet);
|
annotationSetPool.intern(annotationSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getOffset(@Nonnull Method method) {
|
@Nonnull @Override public Collection<Set<? extends Annotation>> getAnnotationSets(@Nonnull Key key) {
|
||||||
Key annotationSetRefKey = new Key(method);
|
return key.getAnnotationSets();
|
||||||
Integer offset = internedAnnotationSetRefItems.get(annotationSetRefKey);
|
|
||||||
if (offset == null) {
|
|
||||||
throw new ExceptionWithContext("Annotation set ref not found.");
|
|
||||||
}
|
|
||||||
return offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNumItems() {
|
public static class Key implements Comparable<Key> {
|
||||||
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> {
|
|
||||||
@Nonnull private final Method method;
|
@Nonnull private final Method method;
|
||||||
private final int size;
|
private final int size;
|
||||||
|
|
||||||
@ -113,14 +80,18 @@ public class AnnotationSetRefPool {
|
|||||||
this.size = CollectionUtils.lastIndexOf(method.getParameters(), HAS_ANNOTATIONS) + 1;
|
this.size = CollectionUtils.lastIndexOf(method.getParameters(), HAS_ANNOTATIONS) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getAnnotationSetCount() {
|
public Collection<Set<? extends Annotation>> getAnnotationSets() {
|
||||||
return size;
|
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() {
|
@Override public int size() {
|
||||||
return FluentIterable.from(method.getParameters())
|
return size;
|
||||||
.limit(size)
|
}
|
||||||
.transform(PARAMETER_ANNOTATIONS);
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
480
dexlib2/src/main/java/org/jf/dexlib2/writer/pool/ClassPool.java
Normal file
480
dexlib2/src/main/java/org/jf/dexlib2/writer/pool/ClassPool.java
Normal 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();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
190
dexlib2/src/main/java/org/jf/dexlib2/writer/pool/DexPool.java
Normal file
190
dexlib2/src/main/java/org/jf/dexlib2/writer/pool/DexPool.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012, Google Inc.
|
* Copyright 2013, Google Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* 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.
|
* 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.Function;
|
||||||
import com.google.common.base.Predicate;
|
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 com.google.common.primitives.Ints;
|
||||||
import org.jf.dexlib2.iface.ClassDef;
|
import org.jf.dexlib2.iface.ClassDef;
|
||||||
import org.jf.dexlib2.iface.Field;
|
import org.jf.dexlib2.iface.Field;
|
||||||
import org.jf.dexlib2.iface.value.EncodedValue;
|
import org.jf.dexlib2.iface.value.EncodedValue;
|
||||||
import org.jf.dexlib2.immutable.value.ImmutableEncodedValueFactory;
|
import org.jf.dexlib2.immutable.value.ImmutableEncodedValueFactory;
|
||||||
import org.jf.dexlib2.util.EncodedValueUtils;
|
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.CollectionUtils;
|
||||||
import org.jf.util.ExceptionWithContext;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.io.IOException;
|
import java.util.AbstractCollection;
|
||||||
import java.util.*;
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class EncodedArrayPool {
|
public class EncodedArrayPool extends BaseNullableOffsetPool<Key>
|
||||||
@Nonnull private final Map<Key, Integer> internedEncodedArrayItems = Maps.newHashMap();
|
implements EncodedArraySection<Key, EncodedValue> {
|
||||||
@Nonnull private final DexFile dexFile;
|
@Nonnull private final StringPool stringPool;
|
||||||
private int sectionOffset = -1;
|
@Nonnull private final TypePool typePool;
|
||||||
|
@Nonnull private final FieldPool fieldPool;
|
||||||
|
@Nonnull private final MethodPool methodPool;
|
||||||
|
|
||||||
public EncodedArrayPool(@Nonnull DexFile dexFile) {
|
public EncodedArrayPool(@Nonnull StringPool stringPool,
|
||||||
this.dexFile = dexFile;
|
@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) {
|
public void intern(@Nonnull ClassDef classDef) {
|
||||||
Key key = Key.of(classDef);
|
Key key = Key.of(classDef);
|
||||||
if (key != null) {
|
if (key != null) {
|
||||||
Integer prev = internedEncodedArrayItems.put(key, 0);
|
Integer prev = internedItems.put(key, 0);
|
||||||
if (prev == null) {
|
if (prev == null) {
|
||||||
for (EncodedValue encodedValue: key.getElements()) {
|
for (EncodedValue encodedValue: key) {
|
||||||
dexFile.internEncodedValue(encodedValue);
|
DexPool.internEncodedValue(encodedValue, stringPool, typePool, fieldPool, methodPool);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getOffset(@Nonnull ClassDef classDef) {
|
@Nonnull @Override public Collection<EncodedValue> getElements(@Nonnull Key key) {
|
||||||
Key key = Key.of(classDef);
|
return key;
|
||||||
if (key != null) {
|
|
||||||
Integer offset = internedEncodedArrayItems.get(key);
|
|
||||||
if (offset == null) {
|
|
||||||
throw new ExceptionWithContext("Encoded array not found.");
|
|
||||||
}
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNumItems() {
|
public static class Key extends AbstractCollection<EncodedValue> implements Comparable<Key> {
|
||||||
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> {
|
|
||||||
private final List<? extends Field> fields;
|
private final List<? extends Field> fields;
|
||||||
private final int size;
|
private final int size;
|
||||||
|
|
||||||
@ -139,20 +119,9 @@ public class EncodedArrayPool {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getElementCount() {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
public Iterable<EncodedValue> getElements() {
|
|
||||||
return FluentIterable.from(fields)
|
|
||||||
.limit(size)
|
|
||||||
.transform(GET_INITIAL_VALUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return CollectionUtils.listHashCode(getElements());
|
return CollectionUtils.listHashCode(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -162,7 +131,7 @@ public class EncodedArrayPool {
|
|||||||
if (size != other.size) {
|
if (size != other.size) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return Iterables.elementsEqual(getElements(), other.getElements());
|
return Iterables.elementsEqual(this, other);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -181,8 +150,8 @@ public class EncodedArrayPool {
|
|||||||
if (res != 0) {
|
if (res != 0) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
Iterator<EncodedValue> otherElements = o.getElements().iterator();
|
Iterator<EncodedValue> otherElements = o.iterator();
|
||||||
for (EncodedValue element: getElements()) {
|
for (EncodedValue element: this) {
|
||||||
res = element.compareTo(otherElements.next());
|
res = element.compareTo(otherElements.next());
|
||||||
if (res != 0) {
|
if (res != 0) {
|
||||||
return res;
|
return res;
|
||||||
@ -190,5 +159,15 @@ public class EncodedArrayPool {
|
|||||||
}
|
}
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012, Google Inc.
|
* Copyright 2013, Google Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* 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.
|
* 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 com.google.common.collect.Ordering;
|
||||||
import org.jf.dexlib2.iface.reference.MethodReference;
|
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.CharSequenceUtils;
|
||||||
import org.jf.util.CollectionUtils;
|
import org.jf.util.CollectionUtils;
|
||||||
import org.jf.util.ExceptionWithContext;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class ProtoPool {
|
public class ProtoPool extends BaseIndexPool<Key>
|
||||||
public final static int PROTO_ID_ITEM_SIZE = 0x0C;
|
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();
|
public ProtoPool(@Nonnull StringPool stringPool, @Nonnull TypePool typePool,
|
||||||
@Nonnull private final DexFile dexFile;
|
@Nonnull TypeListPool typeListPool) {
|
||||||
private int sectionOffset = -1;
|
this.stringPool = stringPool;
|
||||||
|
this.typePool = typePool;
|
||||||
public ProtoPool(@Nonnull DexFile dexFile) {
|
this.typeListPool = typeListPool;
|
||||||
this.dexFile = dexFile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void intern(@Nonnull MethodReference method) {
|
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
|
// 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
|
// hashCode and equals based only on the prototype fields
|
||||||
Key key = new Key(method);
|
Key key = new Key(method);
|
||||||
Integer prev = internedProtoIdItems.put(key, 0);
|
Integer prev = internedItems.put(key, 0);
|
||||||
if (prev == null) {
|
if (prev == null) {
|
||||||
dexFile.stringPool.intern(key.getShorty());
|
stringPool.intern(key.getShorty());
|
||||||
dexFile.typePool.intern(method.getReturnType());
|
typePool.intern(method.getReturnType());
|
||||||
dexFile.typeListPool.intern(method.getParameterTypes());
|
typeListPool.intern(method.getParameterTypes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getIndex(@Nonnull MethodReference method) {
|
@Nonnull @Override public CharSequence getShorty(@Nonnull Key key) {
|
||||||
Key key = new Key(method);
|
return key.getShorty();
|
||||||
Integer index = internedProtoIdItems.get(key);
|
}
|
||||||
if (index == null) {
|
|
||||||
throw new ExceptionWithContext("Prototype not found.: %s", key);
|
@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() {
|
private static String getShorty(Collection<? extends CharSequence> params, CharSequence returnType) {
|
||||||
return internedProtoIdItems.size() * PROTO_ID_ITEM_SIZE;
|
StringBuilder sb = new StringBuilder(params.size() + 1);
|
||||||
}
|
sb.append(getShortyType(returnType));
|
||||||
|
for (CharSequence typeRef: params) {
|
||||||
public int getNumItems() {
|
sb.append(getShortyType(typeRef));
|
||||||
return internedProtoIdItems.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSectionOffset() {
|
|
||||||
if (sectionOffset < 0) {
|
|
||||||
throw new ExceptionWithContext("Section offset has not been set yet!");
|
|
||||||
}
|
}
|
||||||
return sectionOffset;
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(@Nonnull DexWriter writer) throws IOException {
|
public static class Key implements Comparable<Key> {
|
||||||
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> {
|
|
||||||
@Nonnull private final MethodReference method;
|
@Nonnull private final MethodReference method;
|
||||||
|
|
||||||
public Key(@Nonnull MethodReference method) {
|
public Key(@Nonnull MethodReference method) {
|
||||||
@ -122,20 +109,7 @@ public class ProtoPool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getShorty() {
|
public String getShorty() {
|
||||||
Collection<? extends CharSequence> params = getParameters();
|
return ProtoPool.getShorty(method.getParameterTypes(), method.getReturnType());
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
@ -160,7 +134,7 @@ public class ProtoPool {
|
|||||||
if (o instanceof Key) {
|
if (o instanceof Key) {
|
||||||
Key other = (Key)o;
|
Key other = (Key)o;
|
||||||
return getReturnType().equals(other.getReturnType()) &&
|
return getReturnType().equals(other.getReturnType()) &&
|
||||||
CharSequenceUtils.listEquals(getParameters(), other.getParameters());
|
CharSequenceUtils.listEquals(getParameters(), other.getParameters());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012, Google Inc.
|
* Copyright 2013, Google Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* 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.
|
* 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.ImmutableList;
|
||||||
import com.google.common.collect.Maps;
|
import org.jf.dexlib2.writer.pool.TypeListPool.Key;
|
||||||
import org.jf.util.ExceptionWithContext;
|
import org.jf.dexlib2.writer.TypeListSection;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.io.IOException;
|
import java.util.Collection;
|
||||||
import java.util.*;
|
import java.util.Iterator;
|
||||||
|
|
||||||
public class TypeListPool {
|
public class TypeListPool extends BaseNullableOffsetPool<Key<? extends Collection<? extends CharSequence>>>
|
||||||
@Nonnull private final Map<Key, Integer> internedTypeListItems = Maps.newHashMap();
|
implements TypeListSection<CharSequence, Key<? extends Collection<? extends CharSequence>>> {
|
||||||
@Nonnull private final DexFile dexFile;
|
@Nonnull private final TypePool typePool;
|
||||||
private int sectionOffset = -1;
|
|
||||||
|
|
||||||
public TypeListPool(@Nonnull DexFile dexFile) {
|
public TypeListPool(@Nonnull TypePool typePool) {
|
||||||
this.dexFile = dexFile;
|
this.typePool = typePool;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void intern(@Nonnull Collection<? extends CharSequence> types) {
|
public void intern(@Nonnull Collection<? extends CharSequence> types) {
|
||||||
Key key = new Key(types);
|
Key<? extends Collection<? extends CharSequence>> key = new Key<Collection<? extends CharSequence>>(types);
|
||||||
Integer prev = internedTypeListItems.put(key, 0);
|
Integer prev = internedItems.put(key, 0);
|
||||||
if (prev == null) {
|
if (prev == null) {
|
||||||
for (CharSequence type: types) {
|
for (CharSequence type: types) {
|
||||||
dexFile.typePool.intern(type);
|
typePool.intern(type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getOffset(@Nonnull Collection<? extends CharSequence> types) {
|
@Nonnull @Override
|
||||||
Key key = new Key(types);
|
public Collection<? extends CharSequence> getTypes(Key<? extends Collection<? extends CharSequence>> typesKey) {
|
||||||
Integer offset = internedTypeListItems.get(key);
|
if (typesKey == null) {
|
||||||
if (offset == null) {
|
return ImmutableList.of();
|
||||||
throw new ExceptionWithContext("Type list not found.: %s", key);
|
|
||||||
}
|
}
|
||||||
return offset;
|
return typesKey.types;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNumItems() {
|
public static class Key<TypeCollection extends Collection<? extends CharSequence>>
|
||||||
return internedTypeListItems.size();
|
implements Comparable<Key<? extends Collection<? extends CharSequence>>> {
|
||||||
}
|
@Nonnull TypeCollection types;
|
||||||
|
|
||||||
public int getSectionOffset() {
|
public Key(@Nonnull TypeCollection types) {
|
||||||
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) {
|
|
||||||
this.types = types;
|
this.types = types;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +85,8 @@ public class TypeListPool {
|
|||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (o instanceof Key) {
|
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()) {
|
if (types.size() != other.types.size()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -138,13 +110,8 @@ public class TypeListPool {
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
public Collection<? extends CharSequence> getTypes() {
|
|
||||||
return types;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(Key o) {
|
public int compareTo(Key<? extends Collection<? extends CharSequence>> o) {
|
||||||
Iterator<? extends CharSequence> other = o.types.iterator();
|
Iterator<? extends CharSequence> other = o.types.iterator();
|
||||||
for (CharSequence type: types) {
|
for (CharSequence type: types) {
|
||||||
if (!other.hasNext()) {
|
if (!other.hasNext()) {
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -35,7 +35,6 @@ import com.google.common.collect.Lists;
|
|||||||
import org.jf.dexlib2.Format;
|
import org.jf.dexlib2.Format;
|
||||||
import org.jf.dexlib2.Opcode;
|
import org.jf.dexlib2.Opcode;
|
||||||
import org.jf.dexlib2.ReferenceType;
|
import org.jf.dexlib2.ReferenceType;
|
||||||
import org.jf.dexlib2.iface.MethodImplementation;
|
|
||||||
import org.jf.dexlib2.iface.instruction.Instruction;
|
import org.jf.dexlib2.iface.instruction.Instruction;
|
||||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
|
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
|
||||||
import org.jf.dexlib2.iface.instruction.SwitchElement;
|
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.immutable.instruction.*;
|
||||||
import org.jf.dexlib2.util.InstructionUtil;
|
import org.jf.dexlib2.util.InstructionUtil;
|
||||||
import org.jf.dexlib2.util.MethodUtil;
|
import org.jf.dexlib2.util.MethodUtil;
|
||||||
import org.jf.dexlib2.writer.StringPool;
|
import org.jf.dexlib2.writer.InstructionFactory;
|
||||||
import org.jf.util.ExceptionWithContext;
|
import org.jf.util.ExceptionWithContext;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@ -53,28 +52,35 @@ import java.util.ArrayList;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class InstructionWriteUtil {
|
public class InstructionWriteUtil<Insn extends Instruction, StringRef extends StringReference> {
|
||||||
private final StringPool stringPool;
|
private final StringIndexProvider<StringRef> stringIndexProvider;
|
||||||
MethodImplementation methodImplementation;
|
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 ArrayList<Integer> codeOffsetShifts;
|
||||||
private HashMap<Integer,Format> offsetToNewInstructionMap;
|
private HashMap<Integer,Format> offsetToNewInstructionMap;
|
||||||
|
|
||||||
private int codeUnitCount;
|
private int codeUnitCount;
|
||||||
private int outParamCount;
|
private int outParamCount;
|
||||||
|
|
||||||
public InstructionWriteUtil(@Nonnull MethodImplementation methodImpl, @Nonnull StringPool stringPool) {
|
public static interface StringIndexProvider<StringRef extends StringReference> {
|
||||||
this.stringPool = stringPool;
|
int getItemIndex(@Nonnull StringRef reference);
|
||||||
methodImplementation = methodImpl;
|
}
|
||||||
|
|
||||||
|
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();
|
calculateMaxOutParamCount();
|
||||||
findCodeOffsetShifts();
|
findCodeOffsetShifts();
|
||||||
modifyInstructions();
|
modifyInstructions();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void calculateMaxOutParamCount() {
|
private void calculateMaxOutParamCount() {
|
||||||
for (Instruction instruction: methodImplementation.getInstructions()) {
|
for (Insn instruction: originalInstructions) {
|
||||||
codeUnitCount += instruction.getCodeUnits();
|
codeUnitCount += instruction.getCodeUnits();
|
||||||
if (instruction.getOpcode().referenceType == ReferenceType.METHOD) {
|
if (instruction.getOpcode().referenceType == ReferenceType.METHOD) {
|
||||||
ReferenceInstruction refInsn = (ReferenceInstruction)instruction;
|
ReferenceInstruction refInsn = (ReferenceInstruction)instruction;
|
||||||
@ -86,12 +92,11 @@ public class InstructionWriteUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public Iterable<? extends Insn> getInstructions() {
|
||||||
public Iterable<? extends Instruction> getInstructions() {
|
|
||||||
if (instructions != null) {
|
if (instructions != null) {
|
||||||
return instructions;
|
return instructions;
|
||||||
} else {
|
} else {
|
||||||
return methodImplementation.getInstructions();
|
return originalInstructions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,16 +147,17 @@ public class InstructionWriteUtil {
|
|||||||
private void findCodeOffsetShifts() {
|
private void findCodeOffsetShifts() {
|
||||||
// first, process const-string to const-string/jumbo conversions
|
// first, process const-string to const-string/jumbo conversions
|
||||||
int currentCodeOffset = 0;
|
int currentCodeOffset = 0;
|
||||||
for (Instruction instruction: methodImplementation.getInstructions()) {
|
for (Instruction instruction: originalInstructions) {
|
||||||
if (instruction.getOpcode().equals(Opcode.CONST_STRING)) {
|
if (instruction.getOpcode().equals(Opcode.CONST_STRING)) {
|
||||||
ReferenceInstruction refInstr = (ReferenceInstruction) instruction;
|
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 (referenceIndex > 0xFFFF) {
|
||||||
if (codeOffsetShifts == null) {
|
if (codeOffsetShifts == null) {
|
||||||
codeOffsetShifts = new ArrayList<Integer>();
|
codeOffsetShifts = new ArrayList<Integer>();
|
||||||
}
|
}
|
||||||
if (offsetToNewInstructionMap == null) {
|
if (offsetToNewInstructionMap == null) {
|
||||||
offsetToNewInstructionMap = new HashMap<Integer,Format>();
|
offsetToNewInstructionMap = new HashMap<Integer,Format>();
|
||||||
}
|
}
|
||||||
codeOffsetShifts.add(currentCodeOffset+instruction.getCodeUnits());
|
codeOffsetShifts.add(currentCodeOffset+instruction.getCodeUnits());
|
||||||
offsetToNewInstructionMap.put(currentCodeOffset, Opcode.CONST_STRING_JUMBO.format);
|
offsetToNewInstructionMap.put(currentCodeOffset, Opcode.CONST_STRING_JUMBO.format);
|
||||||
@ -172,16 +178,16 @@ public class InstructionWriteUtil {
|
|||||||
do {
|
do {
|
||||||
currentCodeOffset = 0;
|
currentCodeOffset = 0;
|
||||||
shiftsInserted = false;
|
shiftsInserted = false;
|
||||||
for (Instruction instruction: methodImplementation.getInstructions()) {
|
for (Instruction instruction: originalInstructions) {
|
||||||
if (instruction.getOpcode().format.equals(Format.Format10t) && !offsetToNewInstructionMap.containsKey(currentCodeOffset)) {
|
if (instruction.getOpcode().format.equals(Format.Format10t) && !offsetToNewInstructionMap.containsKey(currentCodeOffset)) {
|
||||||
int targetOffset = ((Instruction10t)instruction).getCodeOffset();
|
int targetOffset = ((Instruction10t)instruction).getCodeOffset();
|
||||||
int codeOffsetDelta = codeOffsetShift(currentCodeOffset);
|
int codeOffsetDelta = codeOffsetShift(currentCodeOffset);
|
||||||
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
|
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
|
||||||
if ((byte)newTargetOffset != newTargetOffset) {
|
if ((byte)newTargetOffset != newTargetOffset) {
|
||||||
if ((short)newTargetOffset != newTargetOffset) {
|
if ((short)newTargetOffset != newTargetOffset) {
|
||||||
// handling very small (negligible) possibility of goto becoming goto/32
|
// handling very small (negligible) possibility of goto becoming goto/32
|
||||||
// we insert extra 1 code unit shift referring to the same position
|
// 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
|
// this will cause subsequent code offsets to be shifted by 2 code units
|
||||||
codeOffsetShifts.add(codeOffsetDelta, currentCodeOffset+instruction.getCodeUnits());
|
codeOffsetShifts.add(codeOffsetDelta, currentCodeOffset+instruction.getCodeUnits());
|
||||||
offsetToNewInstructionMap.put(currentCodeOffset, Format.Format30t);
|
offsetToNewInstructionMap.put(currentCodeOffset, Format.Format30t);
|
||||||
} else {
|
} else {
|
||||||
@ -228,8 +234,8 @@ public class InstructionWriteUtil {
|
|||||||
|
|
||||||
instructions = Lists.newArrayList();
|
instructions = Lists.newArrayList();
|
||||||
int currentCodeOffset = 0;
|
int currentCodeOffset = 0;
|
||||||
for (Instruction instruction: methodImplementation.getInstructions()) {
|
for (Insn instruction: originalInstructions) {
|
||||||
Instruction modifiedInstruction = null;
|
Insn modifiedInstruction = null;
|
||||||
switch (instruction.getOpcode().format) {
|
switch (instruction.getOpcode().format) {
|
||||||
case Format10t: {
|
case Format10t: {
|
||||||
Instruction10t instr = (Instruction10t)instruction;
|
Instruction10t instr = (Instruction10t)instruction;
|
||||||
@ -237,13 +243,13 @@ public class InstructionWriteUtil {
|
|||||||
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
|
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
|
||||||
Format newInstructionFormat = offsetToNewInstructionMap.get(currentCodeOffset);
|
Format newInstructionFormat = offsetToNewInstructionMap.get(currentCodeOffset);
|
||||||
if (newInstructionFormat != null) {
|
if (newInstructionFormat != null) {
|
||||||
if (newInstructionFormat.equals(Format.Format30t)) {
|
if (newInstructionFormat.equals(Format.Format30t)) {
|
||||||
modifiedInstruction = new ImmutableInstruction30t(Opcode.GOTO_32, newTargetOffset);
|
modifiedInstruction = instructionFactory.makeInstruction30t(Opcode.GOTO_32, newTargetOffset);
|
||||||
} else if (newInstructionFormat.equals(Format.Format20t)) {
|
} else if (newInstructionFormat.equals(Format.Format20t)) {
|
||||||
modifiedInstruction = new ImmutableInstruction20t(Opcode.GOTO_16, newTargetOffset);
|
modifiedInstruction = instructionFactory.makeInstruction20t(Opcode.GOTO_16, newTargetOffset);
|
||||||
}
|
}
|
||||||
} else if (newTargetOffset != targetOffset) {
|
} else if (newTargetOffset != targetOffset) {
|
||||||
modifiedInstruction = new ImmutableInstruction10t(instr.getOpcode(), newTargetOffset);
|
modifiedInstruction = instructionFactory.makeInstruction10t(instr.getOpcode(), newTargetOffset);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -253,18 +259,19 @@ public class InstructionWriteUtil {
|
|||||||
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
|
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
|
||||||
Format newInstructionFormat = offsetToNewInstructionMap.get(currentCodeOffset);
|
Format newInstructionFormat = offsetToNewInstructionMap.get(currentCodeOffset);
|
||||||
if (newInstructionFormat != null && newInstructionFormat.equals(Format.Format30t)) {
|
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) {
|
} else if (newTargetOffset != targetOffset) {
|
||||||
modifiedInstruction = new ImmutableInstruction20t(Opcode.GOTO_16, newTargetOffset);
|
modifiedInstruction = instructionFactory.makeInstruction20t(Opcode.GOTO_16, newTargetOffset);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Format21c: {
|
case Format21c: {
|
||||||
Instruction21c instr = (Instruction21c)instruction;
|
Instruction21c instr = (Instruction21c)instruction;
|
||||||
if (instr.getOpcode().equals(Opcode.CONST_STRING)) {
|
if (instr.getOpcode().equals(Opcode.CONST_STRING)) {
|
||||||
int referenceIndex = stringPool.getIndex((StringReference)instr.getReference());
|
int referenceIndex = stringIndexProvider.getItemIndex((StringRef)instr.getReference());
|
||||||
if (referenceIndex > 0xFFFF) {
|
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;
|
break;
|
||||||
@ -274,7 +281,8 @@ public class InstructionWriteUtil {
|
|||||||
int targetOffset = instr.getCodeOffset();
|
int targetOffset = instr.getCodeOffset();
|
||||||
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
|
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
|
||||||
if (newTargetOffset != targetOffset) {
|
if (newTargetOffset != targetOffset) {
|
||||||
modifiedInstruction = new ImmutableInstruction21t(instr.getOpcode(), instr.getRegisterA(), newTargetOffset);
|
modifiedInstruction = instructionFactory.makeInstruction21t(instr.getOpcode(),
|
||||||
|
instr.getRegisterA(), newTargetOffset);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -283,7 +291,8 @@ public class InstructionWriteUtil {
|
|||||||
int targetOffset = instr.getCodeOffset();
|
int targetOffset = instr.getCodeOffset();
|
||||||
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
|
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
|
||||||
if (newTargetOffset != 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;
|
break;
|
||||||
}
|
}
|
||||||
@ -292,7 +301,7 @@ public class InstructionWriteUtil {
|
|||||||
int targetOffset = instr.getCodeOffset();
|
int targetOffset = instr.getCodeOffset();
|
||||||
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
|
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
|
||||||
if (newTargetOffset != targetOffset) {
|
if (newTargetOffset != targetOffset) {
|
||||||
modifiedInstruction = new ImmutableInstruction30t(instr.getOpcode(), newTargetOffset);
|
modifiedInstruction = instructionFactory.makeInstruction30t(instr.getOpcode(), newTargetOffset);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -301,40 +310,41 @@ public class InstructionWriteUtil {
|
|||||||
int targetOffset = instr.getCodeOffset();
|
int targetOffset = instr.getCodeOffset();
|
||||||
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
|
int newTargetOffset = targetOffset + targetOffsetShift(currentCodeOffset, targetOffset);
|
||||||
if (newTargetOffset != targetOffset) {
|
if (newTargetOffset != targetOffset) {
|
||||||
modifiedInstruction = new ImmutableInstruction31t(instr.getOpcode(), instr.getRegisterA(), newTargetOffset);
|
modifiedInstruction = instructionFactory.makeInstruction31t(instr.getOpcode(),
|
||||||
|
instr.getRegisterA(), newTargetOffset);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SparseSwitchPayload: {
|
case SparseSwitchPayload: {
|
||||||
alignPayload(currentCodeOffset);
|
alignPayload(currentCodeOffset);
|
||||||
int switchInstructionOffset = findSwitchInstructionOffset(currentCodeOffset);
|
int switchInstructionOffset = findSwitchInstructionOffset(currentCodeOffset);
|
||||||
SwitchPayload payload = (SwitchPayload)instruction;
|
SwitchPayload payload = (SwitchPayload)instruction;
|
||||||
if (isSwitchTargetOffsetChanged(payload, switchInstructionOffset)) {
|
if (isSwitchTargetOffsetChanged(payload, switchInstructionOffset)) {
|
||||||
List<SwitchElement> newSwitchElements = modifySwitchElements(payload, switchInstructionOffset);
|
List<SwitchElement> newSwitchElements = modifySwitchElements(payload, switchInstructionOffset);
|
||||||
modifiedInstruction = new ImmutableSparseSwitchPayload(newSwitchElements);
|
modifiedInstruction = instructionFactory.makeSparseSwitchPayload(newSwitchElements);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PackedSwitchPayload: {
|
case PackedSwitchPayload: {
|
||||||
alignPayload(currentCodeOffset);
|
alignPayload(currentCodeOffset);
|
||||||
int switchInstructionOffset = findSwitchInstructionOffset(currentCodeOffset);
|
int switchInstructionOffset = findSwitchInstructionOffset(currentCodeOffset);
|
||||||
SwitchPayload payload = (SwitchPayload)instruction;
|
SwitchPayload payload = (SwitchPayload)instruction;
|
||||||
if (isSwitchTargetOffsetChanged(payload, switchInstructionOffset)) {
|
if (isSwitchTargetOffsetChanged(payload, switchInstructionOffset)) {
|
||||||
List<SwitchElement> newSwitchElements = modifySwitchElements(payload, switchInstructionOffset);
|
List<SwitchElement> newSwitchElements = modifySwitchElements(payload, switchInstructionOffset);
|
||||||
modifiedInstruction = new ImmutablePackedSwitchPayload(newSwitchElements);
|
modifiedInstruction = instructionFactory.makePackedSwitchPayload(newSwitchElements);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ArrayPayload: {
|
case ArrayPayload: {
|
||||||
alignPayload(currentCodeOffset);
|
alignPayload(currentCodeOffset);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modifiedInstruction != null) {
|
if (modifiedInstruction != null) {
|
||||||
instructions.add(modifiedInstruction);
|
instructions.add(modifiedInstruction);
|
||||||
} else {
|
} else {
|
||||||
instructions.add(instruction);
|
instructions.add(instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
currentCodeOffset += instruction.getCodeUnits();
|
currentCodeOffset += instruction.getCodeUnits();
|
||||||
@ -342,25 +352,25 @@ public class InstructionWriteUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void alignPayload(int codeOffset) {
|
private void alignPayload(int codeOffset) {
|
||||||
Format newInstructionFormat = offsetToNewInstructionMap.get(codeOffset);
|
Format newInstructionFormat = offsetToNewInstructionMap.get(codeOffset);
|
||||||
if (newInstructionFormat != null && newInstructionFormat.equals(Format.Format10x)) {
|
if (newInstructionFormat != null && newInstructionFormat.equals(Format.Format10x)) {
|
||||||
instructions.add(new ImmutableInstruction10x(Opcode.NOP));
|
instructions.add(instructionFactory.makeInstruction10x(Opcode.NOP));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int findSwitchInstructionOffset(int payloadOffset) {
|
private int findSwitchInstructionOffset(int payloadOffset) {
|
||||||
int currentCodeOffset = 0;
|
int currentCodeOffset = 0;
|
||||||
int switchInstructionOffset = -1;
|
int switchInstructionOffset = -1;
|
||||||
for (Instruction instruction: methodImplementation.getInstructions()) {
|
for (Instruction instruction: originalInstructions) {
|
||||||
if (instruction.getOpcode().equals(Opcode.PACKED_SWITCH)
|
if (instruction.getOpcode().equals(Opcode.PACKED_SWITCH)
|
||||||
|| instruction.getOpcode().equals(Opcode.SPARSE_SWITCH)) {
|
|| instruction.getOpcode().equals(Opcode.SPARSE_SWITCH)) {
|
||||||
int targetOffset = currentCodeOffset + ((Instruction31t)instruction).getCodeOffset();
|
int targetOffset = currentCodeOffset + ((Instruction31t)instruction).getCodeOffset();
|
||||||
if (targetOffset == payloadOffset) {
|
if (targetOffset == payloadOffset) {
|
||||||
if (switchInstructionOffset < 0) {
|
if (switchInstructionOffset < 0) {
|
||||||
switchInstructionOffset = currentCodeOffset;
|
switchInstructionOffset = currentCodeOffset;
|
||||||
} else {
|
} else {
|
||||||
throw new ExceptionWithContext("Multiple switch instructions refer to the same switch payload!");
|
throw new ExceptionWithContext("Multiple switch instructions refer to the same switch payload!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
currentCodeOffset += instruction.getCodeUnits();
|
currentCodeOffset += instruction.getCodeUnits();
|
||||||
|
@ -35,7 +35,6 @@ import com.google.common.collect.Lists;
|
|||||||
import org.jf.dexlib2.base.BaseTryBlock;
|
import org.jf.dexlib2.base.BaseTryBlock;
|
||||||
import org.jf.dexlib2.iface.ExceptionHandler;
|
import org.jf.dexlib2.iface.ExceptionHandler;
|
||||||
import org.jf.dexlib2.iface.TryBlock;
|
import org.jf.dexlib2.iface.TryBlock;
|
||||||
import org.jf.dexlib2.immutable.ImmutableExceptionHandler;
|
|
||||||
import org.jf.util.ExceptionWithContext;
|
import org.jf.util.ExceptionWithContext;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@ -44,43 +43,40 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.NoSuchElementException;
|
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
|
// Linked list sentinels that don't represent an actual try block
|
||||||
// Their values are never modified, only their links
|
// Their values are never modified, only their links
|
||||||
private final MutableTryBlock listStart;
|
private final MutableTryBlock<EH> listStart;
|
||||||
private final MutableTryBlock listEnd;
|
private final MutableTryBlock<EH> listEnd;
|
||||||
|
|
||||||
public TryListBuilder() {
|
public TryListBuilder() {
|
||||||
listStart = new MutableTryBlock(0, 0);
|
listStart = new MutableTryBlock<EH>(0, 0);
|
||||||
listEnd = new MutableTryBlock(0, 0);
|
listEnd = new MutableTryBlock<EH>(0, 0);
|
||||||
listStart.next = listEnd;
|
listStart.next = listEnd;
|
||||||
listEnd.prev = listStart;
|
listEnd.prev = listStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<TryBlock> massageTryBlocks(List<? extends TryBlock> tryBlocks) {
|
public static <EH extends ExceptionHandler> List<TryBlock<EH>> massageTryBlocks(
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
List<? extends TryBlock<? extends EH>> tryBlocks) {
|
||||||
for (TryBlock tryBlock: tryBlocks) {
|
TryListBuilder<EH> tlb = new TryListBuilder<EH>();
|
||||||
|
|
||||||
|
for (TryBlock<? extends EH> tryBlock: tryBlocks) {
|
||||||
int startAddress = tryBlock.getStartCodeAddress();
|
int startAddress = tryBlock.getStartCodeAddress();
|
||||||
int endAddress = startAddress + tryBlock.getCodeUnitCount();
|
int endAddress = startAddress + tryBlock.getCodeUnitCount();
|
||||||
|
|
||||||
for (ExceptionHandler exceptionHandler: tryBlock.getExceptionHandlers()) {
|
for (EH exceptionHandler: tryBlock.getExceptionHandlers()) {
|
||||||
tlb.addHandler(exceptionHandler.getExceptionType(), startAddress, endAddress,
|
tlb.addHandler(startAddress, endAddress, exceptionHandler);
|
||||||
exceptionHandler.getHandlerCodeAddress());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tlb.getTryBlocks();
|
return tlb.getTryBlocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class TryBounds {
|
private static class TryBounds<EH extends ExceptionHandler> {
|
||||||
@Nonnull public final MutableTryBlock start;
|
@Nonnull public final MutableTryBlock<EH> start;
|
||||||
@Nonnull public final MutableTryBlock end;
|
@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.start = start;
|
||||||
this.end = end;
|
this.end = end;
|
||||||
}
|
}
|
||||||
@ -100,13 +96,13 @@ public class TryListBuilder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class MutableTryBlock extends BaseTryBlock implements TryBlock {
|
private static class MutableTryBlock<EH extends ExceptionHandler> extends BaseTryBlock<EH> {
|
||||||
public MutableTryBlock prev = null;
|
public MutableTryBlock<EH> prev = null;
|
||||||
public MutableTryBlock next = null;
|
public MutableTryBlock<EH> next = null;
|
||||||
|
|
||||||
public int startCodeAddress;
|
public int startCodeAddress;
|
||||||
public int endCodeAddress;
|
public int endCodeAddress;
|
||||||
@Nonnull public List<ExceptionHandler> exceptionHandlers = Lists.newArrayList();
|
@Nonnull public List<EH> exceptionHandlers = Lists.newArrayList();
|
||||||
|
|
||||||
public MutableTryBlock(int startCodeAddress, int endCodeAddress) {
|
public MutableTryBlock(int startCodeAddress, int endCodeAddress) {
|
||||||
this.startCodeAddress = startCodeAddress;
|
this.startCodeAddress = startCodeAddress;
|
||||||
@ -114,7 +110,7 @@ public class TryListBuilder
|
|||||||
}
|
}
|
||||||
|
|
||||||
public MutableTryBlock(int startCodeAddress, int endCodeAddress,
|
public MutableTryBlock(int startCodeAddress, int endCodeAddress,
|
||||||
@Nonnull List<? extends ExceptionHandler> exceptionHandlers) {
|
@Nonnull List<EH> exceptionHandlers) {
|
||||||
this.startCodeAddress = startCodeAddress;
|
this.startCodeAddress = startCodeAddress;
|
||||||
this.endCodeAddress = endCodeAddress;
|
this.endCodeAddress = endCodeAddress;
|
||||||
this.exceptionHandlers = Lists.newArrayList(exceptionHandlers);
|
this.exceptionHandlers = Lists.newArrayList(exceptionHandlers);
|
||||||
@ -128,13 +124,13 @@ public class TryListBuilder
|
|||||||
return endCodeAddress - startCodeAddress;
|
return endCodeAddress - startCodeAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull @Override public List<? extends ExceptionHandler> getExceptionHandlers() {
|
@Nonnull @Override public List<EH> getExceptionHandlers() {
|
||||||
return exceptionHandlers;
|
return exceptionHandlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public MutableTryBlock split(int splitAddress) {
|
public MutableTryBlock<EH> split(int splitAddress) {
|
||||||
MutableTryBlock newTryBlock = new MutableTryBlock(splitAddress, endCodeAddress, exceptionHandlers);
|
MutableTryBlock<EH> newTryBlock = new MutableTryBlock<EH>(splitAddress, endCodeAddress, exceptionHandlers);
|
||||||
endCodeAddress = splitAddress;
|
endCodeAddress = splitAddress;
|
||||||
append(newTryBlock);
|
append(newTryBlock);
|
||||||
return newTryBlock;
|
return newTryBlock;
|
||||||
@ -151,21 +147,21 @@ public class TryListBuilder
|
|||||||
next.delete();
|
next.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void append(@Nonnull MutableTryBlock tryBlock) {
|
public void append(@Nonnull MutableTryBlock<EH> tryBlock) {
|
||||||
next.prev = tryBlock;
|
next.prev = tryBlock;
|
||||||
tryBlock.next = next;
|
tryBlock.next = next;
|
||||||
tryBlock.prev = this;
|
tryBlock.prev = this;
|
||||||
next = tryBlock;
|
next = tryBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void prepend(@Nonnull MutableTryBlock tryBlock) {
|
public void prepend(@Nonnull MutableTryBlock<EH> tryBlock) {
|
||||||
prev.next = tryBlock;
|
prev.next = tryBlock;
|
||||||
tryBlock.prev = prev;
|
tryBlock.prev = prev;
|
||||||
tryBlock.next = this;
|
tryBlock.next = this;
|
||||||
prev = tryBlock;
|
prev = tryBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addHandler(@Nonnull ExceptionHandler handler) {
|
public void addHandler(@Nonnull EH handler) {
|
||||||
for (ExceptionHandler existingHandler: exceptionHandlers) {
|
for (ExceptionHandler existingHandler: exceptionHandlers) {
|
||||||
String existingType = existingHandler.getExceptionType();
|
String existingType = existingHandler.getExceptionType();
|
||||||
String newType = handler.getExceptionType();
|
String newType = handler.getExceptionType();
|
||||||
@ -192,10 +188,10 @@ public class TryListBuilder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private TryBounds getBoundingRanges(int startAddress, int endAddress) {
|
private TryBounds<EH> getBoundingRanges(int startAddress, int endAddress) {
|
||||||
MutableTryBlock startBlock = null;
|
MutableTryBlock<EH> startBlock = null;
|
||||||
|
|
||||||
MutableTryBlock tryBlock = listStart.next;
|
MutableTryBlock<EH> tryBlock = listStart.next;
|
||||||
while (tryBlock != listEnd) {
|
while (tryBlock != listEnd) {
|
||||||
int currentStartAddress = tryBlock.startCodeAddress;
|
int currentStartAddress = tryBlock.startCodeAddress;
|
||||||
int currentEndAddress = tryBlock.endCodeAddress;
|
int currentEndAddress = tryBlock.endCodeAddress;
|
||||||
@ -220,16 +216,16 @@ public class TryListBuilder
|
|||||||
//^--^
|
//^--^
|
||||||
/*Oops, totally too far! The new range doesn't overlap any existing
|
/*Oops, totally too far! The new range doesn't overlap any existing
|
||||||
ones, so we just add it and return*/
|
ones, so we just add it and return*/
|
||||||
startBlock = new MutableTryBlock(startAddress, endAddress);
|
startBlock = new MutableTryBlock<EH>(startAddress, endAddress);
|
||||||
tryBlock.prepend(startBlock);
|
tryBlock.prepend(startBlock);
|
||||||
return new TryBounds(startBlock, startBlock);
|
return new TryBounds<EH>(startBlock, startBlock);
|
||||||
} else {
|
} else {
|
||||||
// |-----|
|
// |-----|
|
||||||
//^---------
|
//^---------
|
||||||
/*Oops, too far! We've passed the start of the range being added, but
|
/*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
|
the new range does overlap this one. We need to add a new range just
|
||||||
before this one*/
|
before this one*/
|
||||||
startBlock = new MutableTryBlock(startAddress, currentStartAddress);
|
startBlock = new MutableTryBlock<EH>(startAddress, currentStartAddress);
|
||||||
tryBlock.prepend(startBlock);
|
tryBlock.prepend(startBlock);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -244,9 +240,9 @@ public class TryListBuilder
|
|||||||
end before the range being added starts. In either case, we just need
|
end before the range being added starts. In either case, we just need
|
||||||
to add a new range at the end of the list*/
|
to add a new range at the end of the list*/
|
||||||
if (startBlock == null) {
|
if (startBlock == null) {
|
||||||
startBlock = new MutableTryBlock(startAddress, endAddress);
|
startBlock = new MutableTryBlock<EH>(startAddress, endAddress);
|
||||||
listEnd.prepend(startBlock);
|
listEnd.prepend(startBlock);
|
||||||
return new TryBounds(startBlock, startBlock);
|
return new TryBounds<EH>(startBlock, startBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
tryBlock = startBlock;
|
tryBlock = startBlock;
|
||||||
@ -258,7 +254,7 @@ public class TryListBuilder
|
|||||||
//|-----|
|
//|-----|
|
||||||
//------^
|
//------^
|
||||||
/*Bam! We hit the end right on the head... err, tail.*/
|
/*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) {
|
} else if (endAddress > currentStartAddress && endAddress < currentEndAddress) {
|
||||||
//|-----|
|
//|-----|
|
||||||
//--^
|
//--^
|
||||||
@ -266,16 +262,16 @@ public class TryListBuilder
|
|||||||
existing range. We need to split the existing range
|
existing range. We need to split the existing range
|
||||||
at the end of the range being added.*/
|
at the end of the range being added.*/
|
||||||
tryBlock.split(endAddress);
|
tryBlock.split(endAddress);
|
||||||
return new TryBounds(startBlock, tryBlock);
|
return new TryBounds<EH>(startBlock, tryBlock);
|
||||||
} else if (endAddress <= currentStartAddress) {
|
} else if (endAddress <= currentStartAddress) {
|
||||||
//|-----| |-----|
|
//|-----| |-----|
|
||||||
//-----------^
|
//-----------^
|
||||||
/*Oops, too far! The current range starts after the range being added
|
/*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
|
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*/
|
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);
|
tryBlock.prepend(endBlock);
|
||||||
return new TryBounds(startBlock, endBlock);
|
return new TryBounds<EH>(startBlock, endBlock);
|
||||||
}
|
}
|
||||||
tryBlock = tryBlock.next;
|
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.
|
/*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
|
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.*/
|
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);
|
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) {
|
public void addHandler(int startAddress, int endAddress, EH handler) {
|
||||||
TryBounds bounds = getBoundingRanges(startAddress, endAddress);
|
TryBounds<EH> bounds = getBoundingRanges(startAddress, endAddress);
|
||||||
|
|
||||||
MutableTryBlock startBlock = bounds.start;
|
MutableTryBlock<EH> startBlock = bounds.start;
|
||||||
MutableTryBlock endBlock = bounds.end;
|
MutableTryBlock<EH> endBlock = bounds.end;
|
||||||
|
|
||||||
ExceptionHandler handler = new ImmutableExceptionHandler(type, handlerAddress);
|
|
||||||
|
|
||||||
int previousEnd = startAddress;
|
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
|
/*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
|
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
|
//is there a hole? If so, add a new range to fill the hole
|
||||||
if (tryBlock.startCodeAddress > previousEnd) {
|
if (tryBlock.startCodeAddress > previousEnd) {
|
||||||
MutableTryBlock newBlock = new MutableTryBlock(previousEnd, tryBlock.startCodeAddress);
|
MutableTryBlock<EH> newBlock = new MutableTryBlock<EH>(previousEnd, tryBlock.startCodeAddress);
|
||||||
tryBlock.prepend(newBlock);
|
tryBlock.prepend(newBlock);
|
||||||
tryBlock = newBlock;
|
tryBlock = newBlock;
|
||||||
}
|
}
|
||||||
@ -320,10 +314,10 @@ public class TryListBuilder
|
|||||||
} while (tryBlock.prev != endBlock);
|
} while (tryBlock.prev != endBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TryBlock> getTryBlocks() {
|
public List<TryBlock<EH>> getTryBlocks() {
|
||||||
return Lists.newArrayList(new Iterator<TryBlock>() {
|
return Lists.newArrayList(new Iterator<TryBlock<EH>>() {
|
||||||
// The next TryBlock to return. This has already been merged, if needed.
|
// The next TryBlock to return. This has already been merged, if needed.
|
||||||
@Nullable private MutableTryBlock next;
|
@Nullable private MutableTryBlock<EH> next;
|
||||||
|
|
||||||
{
|
{
|
||||||
next = listStart;
|
next = listStart;
|
||||||
@ -334,9 +328,9 @@ public class TryListBuilder
|
|||||||
* Read the item that comes after the current value of the next field.
|
* 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
|
* @return The next item, or null if there is no next item
|
||||||
*/
|
*/
|
||||||
@Nullable protected MutableTryBlock readNextItem() {
|
@Nullable protected MutableTryBlock<EH> readNextItem() {
|
||||||
// We can assume that next is not null
|
// We can assume that next is not null, due to the way iteration happens
|
||||||
MutableTryBlock ret = next.next;
|
MutableTryBlock<EH> ret = next.next;
|
||||||
|
|
||||||
if (ret == listEnd) {
|
if (ret == listEnd) {
|
||||||
return null;
|
return null;
|
||||||
@ -357,12 +351,13 @@ public class TryListBuilder
|
|||||||
return next != null;
|
return next != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public TryBlock next() {
|
@Override @Nonnull public TryBlock<EH> next() {
|
||||||
if (!hasNext()) {
|
if (!hasNext()) {
|
||||||
throw new NoSuchElementException();
|
throw new NoSuchElementException();
|
||||||
}
|
}
|
||||||
TryBlock ret = next;
|
TryBlock<EH> ret = next;
|
||||||
next = readNextItem();
|
next = readNextItem();
|
||||||
|
// ret can't be null (ret=next and hasNext returned true)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,11 +42,11 @@ import java.io.IOException;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
public class DexWriterTest {
|
public class DexDataWriterTest {
|
||||||
private Random random;
|
private Random random;
|
||||||
private NakedByteArrayOutputStream output = new NakedByteArrayOutputStream();
|
private NakedByteArrayOutputStream output = new NakedByteArrayOutputStream();
|
||||||
private int startPosition;
|
private int startPosition;
|
||||||
private DexWriter writer;
|
private DexDataWriter writer;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() throws IOException {
|
public void setup() throws IOException {
|
||||||
@ -55,7 +55,7 @@ public class DexWriterTest {
|
|||||||
output.reset();
|
output.reset();
|
||||||
startPosition = 123;
|
startPosition = 123;
|
||||||
int bufferSize = 256;
|
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
|
// 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 {
|
public void testAlign() throws IOException {
|
||||||
// create a new writer so we can start at file position 0
|
// create a new writer so we can start at file position 0
|
||||||
startPosition = 0;
|
startPosition = 0;
|
||||||
writer = new DexWriter(output, startPosition, 256);
|
writer = new DexDataWriter(output, startPosition, 256);
|
||||||
|
|
||||||
writer.align();
|
writer.align();
|
||||||
writer.write(1);
|
writer.write(1);
|
@ -40,13 +40,13 @@ import java.io.IOException;
|
|||||||
public class DexWriterSleb128Test {
|
public class DexWriterSleb128Test {
|
||||||
private NakedByteArrayOutputStream output = new NakedByteArrayOutputStream();
|
private NakedByteArrayOutputStream output = new NakedByteArrayOutputStream();
|
||||||
private int startPosition;
|
private int startPosition;
|
||||||
private DexWriter writer;
|
private DexDataWriter writer;
|
||||||
|
|
||||||
public void setup() throws IOException {
|
public void setup() throws IOException {
|
||||||
output.reset();
|
output.reset();
|
||||||
startPosition = 123;
|
startPosition = 123;
|
||||||
int bufferSize = 256;
|
int bufferSize = 256;
|
||||||
writer = new DexWriter(output, startPosition, bufferSize);
|
writer = new DexDataWriter(output, startPosition, bufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -40,13 +40,13 @@ import java.io.IOException;
|
|||||||
public class DexWriterUleb128Test {
|
public class DexWriterUleb128Test {
|
||||||
private NakedByteArrayOutputStream output = new NakedByteArrayOutputStream();
|
private NakedByteArrayOutputStream output = new NakedByteArrayOutputStream();
|
||||||
private int startPosition;
|
private int startPosition;
|
||||||
private DexWriter writer;
|
private DexDataWriter writer;
|
||||||
|
|
||||||
public void setup() throws IOException {
|
public void setup() throws IOException {
|
||||||
output.reset();
|
output.reset();
|
||||||
startPosition = 123;
|
startPosition = 123;
|
||||||
int bufferSize = 256;
|
int bufferSize = 256;
|
||||||
writer = new DexWriter(output, startPosition, bufferSize);
|
writer = new DexDataWriter(output, startPosition, bufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -34,9 +34,11 @@ package org.jf.dexlib2.writer;
|
|||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
import org.jf.dexlib2.Opcode;
|
import org.jf.dexlib2.Opcode;
|
||||||
|
import org.jf.dexlib2.iface.MethodImplementation;
|
||||||
import org.jf.dexlib2.iface.instruction.Instruction;
|
import org.jf.dexlib2.iface.instruction.Instruction;
|
||||||
import org.jf.dexlib2.iface.instruction.SwitchElement;
|
import org.jf.dexlib2.iface.instruction.SwitchElement;
|
||||||
import org.jf.dexlib2.iface.instruction.formats.*;
|
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.ImmutableMethodImplementation;
|
||||||
import org.jf.dexlib2.immutable.instruction.*;
|
import org.jf.dexlib2.immutable.instruction.*;
|
||||||
import org.jf.dexlib2.immutable.reference.ImmutableStringReference;
|
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.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class JumboStringConversionTest {
|
public class JumboStringConversionTest {
|
||||||
private static final int MIN_NUM_JUMBO_STRINGS = 2;
|
private static final int MIN_NUM_JUMBO_STRINGS = 2;
|
||||||
|
|
||||||
private MockStringPool mStringPool;
|
private MockStringIndexProvider mockStringIndexProvider;
|
||||||
ArrayList<String> mJumboStrings;
|
ArrayList<String> mJumboStrings;
|
||||||
|
|
||||||
|
private class InsnWriteUtil extends InstructionWriteUtil<Instruction, StringReference> {
|
||||||
|
public InsnWriteUtil(@Nonnull MethodImplementation implementation) {
|
||||||
|
super(implementation.getInstructions(), mockStringIndexProvider, ImmutableInstructionFactory.INSTANCE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
mStringPool = new MockStringPool();
|
mockStringIndexProvider = new MockStringIndexProvider();
|
||||||
StringBuilder stringBuilder = new StringBuilder("a");
|
StringBuilder stringBuilder = new StringBuilder("a");
|
||||||
mJumboStrings = Lists.newArrayList();
|
mJumboStrings = Lists.newArrayList();
|
||||||
int index = 0;
|
int index = 0;
|
||||||
@ -64,8 +73,8 @@ public class JumboStringConversionTest {
|
|||||||
for (int pos=stringBuilder.length()-1;pos>=0;pos--) {
|
for (int pos=stringBuilder.length()-1;pos>=0;pos--) {
|
||||||
for (char ch='a';ch<='z';ch++) {
|
for (char ch='a';ch<='z';ch++) {
|
||||||
stringBuilder.setCharAt(pos, ch);
|
stringBuilder.setCharAt(pos, ch);
|
||||||
mStringPool.intern(stringBuilder.toString(), index++);
|
mockStringIndexProvider.intern(stringBuilder.toString(), index++);
|
||||||
if (mStringPool.getNumItems()>0xFFFF) {
|
if (mockStringIndexProvider.getNumItems()>0xFFFF) {
|
||||||
mJumboStrings.add(stringBuilder.toString());
|
mJumboStrings.add(stringBuilder.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,13 +90,16 @@ public class JumboStringConversionTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testInstruction21c() {
|
public void testInstruction21c() {
|
||||||
ArrayList<ImmutableInstruction> instructions = Lists.newArrayList();
|
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);
|
ImmutableMethodImplementation methodImplementation =
|
||||||
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
|
new ImmutableMethodImplementation(1, instructions, null, null);
|
||||||
|
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
|
||||||
|
|
||||||
for (Instruction instr: writeUtil.getInstructions()) {
|
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));
|
instructions.add(1, new ImmutableInstruction10t(Opcode.GOTO, 3));
|
||||||
|
|
||||||
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
|
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
|
||||||
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
|
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
|
||||||
|
|
||||||
for (Instruction instr: writeUtil.getInstructions()) {
|
for (Instruction instr: writeUtil.getInstructions()) {
|
||||||
if (instr instanceof Instruction10t) {
|
if (instr instanceof Instruction10t) {
|
||||||
@ -128,7 +140,7 @@ public class JumboStringConversionTest {
|
|||||||
instructions.add(1, new ImmutableInstruction20t(Opcode.GOTO_16, 4));
|
instructions.add(1, new ImmutableInstruction20t(Opcode.GOTO_16, 4));
|
||||||
|
|
||||||
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
|
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
|
||||||
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
|
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
|
||||||
|
|
||||||
for (Instruction instr: writeUtil.getInstructions()) {
|
for (Instruction instr: writeUtil.getInstructions()) {
|
||||||
if (instr instanceof Instruction20t) {
|
if (instr instanceof Instruction20t) {
|
||||||
@ -145,7 +157,7 @@ public class JumboStringConversionTest {
|
|||||||
instructions.add(1, new ImmutableInstruction30t(Opcode.GOTO_32, 5));
|
instructions.add(1, new ImmutableInstruction30t(Opcode.GOTO_32, 5));
|
||||||
|
|
||||||
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
|
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
|
||||||
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
|
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
|
||||||
|
|
||||||
for (Instruction instr: writeUtil.getInstructions()) {
|
for (Instruction instr: writeUtil.getInstructions()) {
|
||||||
if (instr instanceof Instruction30t) {
|
if (instr instanceof Instruction30t) {
|
||||||
@ -162,7 +174,7 @@ public class JumboStringConversionTest {
|
|||||||
instructions.add(1, new ImmutableInstruction21t(Opcode.IF_EQZ, 0, 4));
|
instructions.add(1, new ImmutableInstruction21t(Opcode.IF_EQZ, 0, 4));
|
||||||
|
|
||||||
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
|
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
|
||||||
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
|
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
|
||||||
|
|
||||||
for (Instruction instr: writeUtil.getInstructions()) {
|
for (Instruction instr: writeUtil.getInstructions()) {
|
||||||
if (instr instanceof Instruction21t) {
|
if (instr instanceof Instruction21t) {
|
||||||
@ -179,7 +191,7 @@ public class JumboStringConversionTest {
|
|||||||
instructions.add(1, new ImmutableInstruction22t(Opcode.IF_EQ, 0, 1, 4));
|
instructions.add(1, new ImmutableInstruction22t(Opcode.IF_EQ, 0, 1, 4));
|
||||||
|
|
||||||
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
|
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
|
||||||
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
|
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
|
||||||
|
|
||||||
for (Instruction instr: writeUtil.getInstructions()) {
|
for (Instruction instr: writeUtil.getInstructions()) {
|
||||||
if (instr instanceof Instruction22t) {
|
if (instr instanceof Instruction22t) {
|
||||||
@ -196,7 +208,7 @@ public class JumboStringConversionTest {
|
|||||||
instructions.add(1, new ImmutableInstruction31t(Opcode.PACKED_SWITCH, 0, 5));
|
instructions.add(1, new ImmutableInstruction31t(Opcode.PACKED_SWITCH, 0, 5));
|
||||||
|
|
||||||
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
|
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
|
||||||
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
|
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
|
||||||
|
|
||||||
for (Instruction instr: writeUtil.getInstructions()) {
|
for (Instruction instr: writeUtil.getInstructions()) {
|
||||||
if (instr instanceof Instruction31t) {
|
if (instr instanceof Instruction31t) {
|
||||||
@ -213,7 +225,7 @@ public class JumboStringConversionTest {
|
|||||||
instructions.add(1, new ImmutableInstruction31t(Opcode.PACKED_SWITCH, 0, 6));
|
instructions.add(1, new ImmutableInstruction31t(Opcode.PACKED_SWITCH, 0, 6));
|
||||||
|
|
||||||
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
|
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
|
||||||
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
|
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
|
||||||
|
|
||||||
for (Instruction instr: writeUtil.getInstructions()) {
|
for (Instruction instr: writeUtil.getInstructions()) {
|
||||||
if (instr instanceof PackedSwitchPayload) {
|
if (instr instanceof PackedSwitchPayload) {
|
||||||
@ -232,7 +244,7 @@ public class JumboStringConversionTest {
|
|||||||
instructions.add(1, new ImmutableInstruction31t(Opcode.SPARSE_SWITCH, 0, 12));
|
instructions.add(1, new ImmutableInstruction31t(Opcode.SPARSE_SWITCH, 0, 12));
|
||||||
|
|
||||||
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
|
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
|
||||||
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
|
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
|
||||||
|
|
||||||
for (Instruction instr: writeUtil.getInstructions()) {
|
for (Instruction instr: writeUtil.getInstructions()) {
|
||||||
if (instr instanceof SparseSwitchPayload) {
|
if (instr instanceof SparseSwitchPayload) {
|
||||||
@ -253,7 +265,7 @@ public class JumboStringConversionTest {
|
|||||||
instructions.add(new ImmutableArrayPayload(4, null));
|
instructions.add(new ImmutableArrayPayload(4, null));
|
||||||
|
|
||||||
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
|
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
|
||||||
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
|
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
|
||||||
|
|
||||||
int codeOffset = 0;
|
int codeOffset = 0;
|
||||||
for (Instruction instr: writeUtil.getInstructions()) {
|
for (Instruction instr: writeUtil.getInstructions()) {
|
||||||
@ -270,7 +282,7 @@ public class JumboStringConversionTest {
|
|||||||
// packed switch instruction is already misaligned
|
// packed switch instruction is already misaligned
|
||||||
|
|
||||||
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
|
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
|
||||||
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
|
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
|
||||||
|
|
||||||
int codeOffset = 0;
|
int codeOffset = 0;
|
||||||
for (Instruction instr: writeUtil.getInstructions()) {
|
for (Instruction instr: writeUtil.getInstructions()) {
|
||||||
@ -288,7 +300,7 @@ public class JumboStringConversionTest {
|
|||||||
instructions.add(4, new ImmutableInstruction10x(Opcode.NOP));
|
instructions.add(4, new ImmutableInstruction10x(Opcode.NOP));
|
||||||
|
|
||||||
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
|
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, null);
|
||||||
InstructionWriteUtil writeUtil = new InstructionWriteUtil(methodImplementation, mStringPool);
|
InsnWriteUtil writeUtil = new InsnWriteUtil(methodImplementation);
|
||||||
|
|
||||||
int codeOffset = 0;
|
int codeOffset = 0;
|
||||||
for (Instruction instr: writeUtil.getInstructions()) {
|
for (Instruction instr: writeUtil.getInstructions()) {
|
||||||
@ -309,7 +321,7 @@ public class JumboStringConversionTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, 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();
|
Instruction instr = writeUtil.getInstructions().iterator().next();
|
||||||
Assert.assertEquals("goto was not converted to goto/16 properly", instr.getOpcode(), Opcode.GOTO_16);
|
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);
|
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();
|
Instruction instr = writeUtil.getInstructions().iterator().next();
|
||||||
Assert.assertEquals("goto/16 was not converted to goto/32 properly", instr.getOpcode(), Opcode.GOTO_32);
|
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));
|
instructions.add(new ImmutableArrayPayload(4, null));
|
||||||
|
|
||||||
ImmutableMethodImplementation methodImplementation = new ImmutableMethodImplementation(1, instructions, null, 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();
|
Instruction instr = writeUtil.getInstructions().iterator().next();
|
||||||
Assert.assertEquals("goto was not converted to goto/16 properly", instr.getOpcode(), Opcode.GOTO_16);
|
Assert.assertEquals("goto was not converted to goto/16 properly", instr.getOpcode(), Opcode.GOTO_16);
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -33,6 +33,7 @@ package org.jf.dexlib2.writer.util;
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
|
import org.jf.dexlib2.iface.ExceptionHandler;
|
||||||
import org.jf.dexlib2.iface.TryBlock;
|
import org.jf.dexlib2.iface.TryBlock;
|
||||||
import org.jf.dexlib2.immutable.ImmutableExceptionHandler;
|
import org.jf.dexlib2.immutable.ImmutableExceptionHandler;
|
||||||
import org.jf.dexlib2.immutable.ImmutableTryBlock;
|
import org.jf.dexlib2.immutable.ImmutableTryBlock;
|
||||||
@ -41,13 +42,16 @@ import org.junit.Test;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class TryListBuilderTest {
|
public class TryListBuilderTest {
|
||||||
|
private static class TryListBuilder extends org.jf.dexlib2.writer.util.TryListBuilder<ExceptionHandler> {
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSingleCatchAll_Beginning() {
|
public void testSingleCatchAll_Beginning() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
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,
|
List<? extends TryBlock> expected = ImmutableList.of(new ImmutableTryBlock(0, 10,
|
||||||
ImmutableList.of(new ImmutableExceptionHandler(null, 5))));
|
ImmutableList.of(new ImmutableExceptionHandler(null, 5))));
|
||||||
@ -59,9 +63,9 @@ public class TryListBuilderTest {
|
|||||||
public void testSingleCatchAll_Middle() {
|
public void testSingleCatchAll_Middle() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
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,
|
List<? extends TryBlock> expected = ImmutableList.of(new ImmutableTryBlock(5, 5,
|
||||||
ImmutableList.of(new ImmutableExceptionHandler(null, 15))));
|
ImmutableList.of(new ImmutableExceptionHandler(null, 15))));
|
||||||
@ -73,9 +77,9 @@ public class TryListBuilderTest {
|
|||||||
public void testSingleCatch_Beginning() {
|
public void testSingleCatch_Beginning() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
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,
|
List<? extends TryBlock> expected = ImmutableList.of(new ImmutableTryBlock(0, 10,
|
||||||
ImmutableList.of(new ImmutableExceptionHandler("Ljava/lang/Exception;", 5))));
|
ImmutableList.of(new ImmutableExceptionHandler("Ljava/lang/Exception;", 5))));
|
||||||
@ -87,9 +91,9 @@ public class TryListBuilderTest {
|
|||||||
public void testSingleCatch_Middle() {
|
public void testSingleCatch_Middle() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
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,
|
List<? extends TryBlock> expected = ImmutableList.of(new ImmutableTryBlock(5, 5,
|
||||||
ImmutableList.of(new ImmutableExceptionHandler("Ljava/lang/Exception;", 15))));
|
ImmutableList.of(new ImmutableExceptionHandler("Ljava/lang/Exception;", 15))));
|
||||||
@ -101,10 +105,10 @@ public class TryListBuilderTest {
|
|||||||
public void testOverlap_End_After() {
|
public void testOverlap_End_After() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
TryListBuilder tlb = new TryListBuilder();
|
||||||
|
|
||||||
tlb.addHandler("LException1;", 0, 10, 5);
|
tlb.addHandler(0, 10, new ImmutableExceptionHandler("LException1;", 5));
|
||||||
tlb.addHandler("LException2;", 10, 20, 6);
|
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(
|
List<? extends TryBlock> expected = ImmutableList.of(
|
||||||
new ImmutableTryBlock(0, 10,
|
new ImmutableTryBlock(0, 10,
|
||||||
@ -119,10 +123,10 @@ public class TryListBuilderTest {
|
|||||||
public void testOverlap_After_After() {
|
public void testOverlap_After_After() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
TryListBuilder tlb = new TryListBuilder();
|
||||||
|
|
||||||
tlb.addHandler("LException1;", 0, 10, 5);
|
tlb.addHandler(0, 10, new ImmutableExceptionHandler("LException1;", 5));
|
||||||
tlb.addHandler("LException2;", 15, 20, 6);
|
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(
|
List<? extends TryBlock> expected = ImmutableList.of(
|
||||||
new ImmutableTryBlock(0, 10,
|
new ImmutableTryBlock(0, 10,
|
||||||
@ -137,10 +141,10 @@ public class TryListBuilderTest {
|
|||||||
public void testOverlap_Before_Start() {
|
public void testOverlap_Before_Start() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
TryListBuilder tlb = new TryListBuilder();
|
||||||
|
|
||||||
tlb.addHandler("LException1;", 5, 10, 5);
|
tlb.addHandler(5, 10, new ImmutableExceptionHandler("LException1;", 5));
|
||||||
tlb.addHandler("LException2;", 0, 5, 6);
|
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(
|
List<? extends TryBlock> expected = ImmutableList.of(
|
||||||
new ImmutableTryBlock(0, 5,
|
new ImmutableTryBlock(0, 5,
|
||||||
@ -155,10 +159,10 @@ public class TryListBuilderTest {
|
|||||||
public void testOverlap_Before_Before() {
|
public void testOverlap_Before_Before() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
TryListBuilder tlb = new TryListBuilder();
|
||||||
|
|
||||||
tlb.addHandler("LException1;", 5, 10, 5);
|
tlb.addHandler(5, 10, new ImmutableExceptionHandler("LException1;", 5));
|
||||||
tlb.addHandler("LException2;", 0, 3, 6);
|
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(
|
List<? extends TryBlock> expected = ImmutableList.of(
|
||||||
new ImmutableTryBlock(0, 3,
|
new ImmutableTryBlock(0, 3,
|
||||||
@ -173,10 +177,10 @@ public class TryListBuilderTest {
|
|||||||
public void testOverlap_Start_End() {
|
public void testOverlap_Start_End() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
TryListBuilder tlb = new TryListBuilder();
|
||||||
|
|
||||||
tlb.addHandler("LException1;", 0, 10, 5);
|
tlb.addHandler(0, 10, new ImmutableExceptionHandler("LException1;", 5));
|
||||||
tlb.addHandler("LException2;", 0, 10, 6);
|
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(
|
List<? extends TryBlock> expected = ImmutableList.of(
|
||||||
new ImmutableTryBlock(0, 10,
|
new ImmutableTryBlock(0, 10,
|
||||||
@ -191,10 +195,10 @@ public class TryListBuilderTest {
|
|||||||
public void testOverlap_Start_Middle() {
|
public void testOverlap_Start_Middle() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
TryListBuilder tlb = new TryListBuilder();
|
||||||
|
|
||||||
tlb.addHandler("LException1;", 0, 10, 5);
|
tlb.addHandler(0, 10, new ImmutableExceptionHandler("LException1;", 5));
|
||||||
tlb.addHandler("LException2;", 0, 5, 6);
|
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(
|
List<? extends TryBlock> expected = ImmutableList.of(
|
||||||
new ImmutableTryBlock(0, 5,
|
new ImmutableTryBlock(0, 5,
|
||||||
@ -212,10 +216,10 @@ public class TryListBuilderTest {
|
|||||||
public void testOverlap_Middle_Middle() {
|
public void testOverlap_Middle_Middle() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
TryListBuilder tlb = new TryListBuilder();
|
||||||
|
|
||||||
tlb.addHandler("LException1;", 0, 10, 5);
|
tlb.addHandler(0, 10, new ImmutableExceptionHandler("LException1;", 5));
|
||||||
tlb.addHandler("LException2;", 2, 7, 6);
|
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(
|
List<? extends TryBlock> expected = ImmutableList.of(
|
||||||
new ImmutableTryBlock(0, 2,
|
new ImmutableTryBlock(0, 2,
|
||||||
@ -236,10 +240,10 @@ public class TryListBuilderTest {
|
|||||||
public void testOverlap_Middle_End() {
|
public void testOverlap_Middle_End() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
TryListBuilder tlb = new TryListBuilder();
|
||||||
|
|
||||||
tlb.addHandler("LException1;", 0, 10, 5);
|
tlb.addHandler(0, 10, new ImmutableExceptionHandler("LException1;", 5));
|
||||||
tlb.addHandler("LException2;", 5, 10, 6);
|
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(
|
List<? extends TryBlock> expected = ImmutableList.of(
|
||||||
new ImmutableTryBlock(0, 5,
|
new ImmutableTryBlock(0, 5,
|
||||||
@ -257,10 +261,10 @@ public class TryListBuilderTest {
|
|||||||
public void testOverlap_Beginning_After() {
|
public void testOverlap_Beginning_After() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
TryListBuilder tlb = new TryListBuilder();
|
||||||
|
|
||||||
tlb.addHandler("LException1;", 0, 10, 5);
|
tlb.addHandler(0, 10, new ImmutableExceptionHandler("LException1;", 5));
|
||||||
tlb.addHandler("LException2;", 0, 15, 6);
|
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(
|
List<? extends TryBlock> expected = ImmutableList.of(
|
||||||
new ImmutableTryBlock(0, 10,
|
new ImmutableTryBlock(0, 10,
|
||||||
@ -278,10 +282,10 @@ public class TryListBuilderTest {
|
|||||||
public void testOverlap_Middle_After() {
|
public void testOverlap_Middle_After() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
TryListBuilder tlb = new TryListBuilder();
|
||||||
|
|
||||||
tlb.addHandler("LException1;", 0, 10, 5);
|
tlb.addHandler(0, 10, new ImmutableExceptionHandler("LException1;", 5));
|
||||||
tlb.addHandler("LException2;", 5, 15, 6);
|
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(
|
List<? extends TryBlock> expected = ImmutableList.of(
|
||||||
new ImmutableTryBlock(0, 5,
|
new ImmutableTryBlock(0, 5,
|
||||||
@ -302,10 +306,10 @@ public class TryListBuilderTest {
|
|||||||
public void testOverlap_Before_End() {
|
public void testOverlap_Before_End() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
TryListBuilder tlb = new TryListBuilder();
|
||||||
|
|
||||||
tlb.addHandler("LException1;", 5, 10, 5);
|
tlb.addHandler(5, 10, new ImmutableExceptionHandler("LException1;", 5));
|
||||||
tlb.addHandler("LException2;", 0, 10, 6);
|
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(
|
List<? extends TryBlock> expected = ImmutableList.of(
|
||||||
new ImmutableTryBlock(0, 5,
|
new ImmutableTryBlock(0, 5,
|
||||||
@ -323,10 +327,10 @@ public class TryListBuilderTest {
|
|||||||
public void testOverlap_Before_Middle() {
|
public void testOverlap_Before_Middle() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
TryListBuilder tlb = new TryListBuilder();
|
||||||
|
|
||||||
tlb.addHandler("LException1;", 5, 10, 5);
|
tlb.addHandler(5, 10, new ImmutableExceptionHandler("LException1;", 5));
|
||||||
tlb.addHandler("LException2;", 0, 7, 6);
|
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(
|
List<? extends TryBlock> expected = ImmutableList.of(
|
||||||
new ImmutableTryBlock(0, 5,
|
new ImmutableTryBlock(0, 5,
|
||||||
@ -347,10 +351,10 @@ public class TryListBuilderTest {
|
|||||||
public void testOverlap_Before_After() {
|
public void testOverlap_Before_After() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
TryListBuilder tlb = new TryListBuilder();
|
||||||
|
|
||||||
tlb.addHandler("LException1;", 5, 10, 5);
|
tlb.addHandler(5, 10, new ImmutableExceptionHandler("LException1;", 5));
|
||||||
tlb.addHandler("LException2;", 0, 15, 6);
|
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(
|
List<? extends TryBlock> expected = ImmutableList.of(
|
||||||
new ImmutableTryBlock(0, 5,
|
new ImmutableTryBlock(0, 5,
|
||||||
@ -371,11 +375,11 @@ public class TryListBuilderTest {
|
|||||||
public void testOverlap_Hole() {
|
public void testOverlap_Hole() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
TryListBuilder tlb = new TryListBuilder();
|
||||||
|
|
||||||
tlb.addHandler("LException1;", 1, 5, 5);
|
tlb.addHandler(1, 5, new ImmutableExceptionHandler("LException1;", 5));
|
||||||
tlb.addHandler("LException1;", 10, 14, 5);
|
tlb.addHandler(10, 14, new ImmutableExceptionHandler("LException1;", 5));
|
||||||
tlb.addHandler("LException2;", 0, 15, 6);
|
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(
|
List<? extends TryBlock> expected = ImmutableList.of(
|
||||||
new ImmutableTryBlock(0, 1,
|
new ImmutableTryBlock(0, 1,
|
||||||
@ -403,10 +407,10 @@ public class TryListBuilderTest {
|
|||||||
public void testHandlerMerge_Same() {
|
public void testHandlerMerge_Same() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
TryListBuilder tlb = new TryListBuilder();
|
||||||
|
|
||||||
tlb.addHandler("LException1;", 5, 10, 5);
|
tlb.addHandler(5, 10, new ImmutableExceptionHandler("LException1;", 5));
|
||||||
tlb.addHandler("LException1;", 0, 15, 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(
|
List<? extends TryBlock> expected = ImmutableList.of(
|
||||||
new ImmutableTryBlock(0, 15,
|
new ImmutableTryBlock(0, 15,
|
||||||
@ -420,10 +424,10 @@ public class TryListBuilderTest {
|
|||||||
public void testHandlerMerge_DifferentType() {
|
public void testHandlerMerge_DifferentType() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
TryListBuilder tlb = new TryListBuilder();
|
||||||
|
|
||||||
tlb.addHandler("LException1;", 5, 10, 5);
|
tlb.addHandler(5, 10, new ImmutableExceptionHandler("LException1;", 5));
|
||||||
tlb.addHandler("LException2;", 0, 15, 6);
|
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(
|
List<? extends TryBlock> expected = ImmutableList.of(
|
||||||
new ImmutableTryBlock(0, 5,
|
new ImmutableTryBlock(0, 5,
|
||||||
@ -444,9 +448,9 @@ public class TryListBuilderTest {
|
|||||||
public void testHandlerMerge_DifferentAddress() {
|
public void testHandlerMerge_DifferentAddress() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
TryListBuilder tlb = new TryListBuilder();
|
||||||
|
|
||||||
tlb.addHandler("LException1;", 5, 10, 5);
|
tlb.addHandler(5, 10, new ImmutableExceptionHandler("LException1;", 5));
|
||||||
try {
|
try {
|
||||||
tlb.addHandler("LException1;", 0, 15, 6);
|
tlb.addHandler(0, 15, new ImmutableExceptionHandler("LException1;", 6));
|
||||||
} catch (TryListBuilder.InvalidTryException ex) {
|
} catch (TryListBuilder.InvalidTryException ex) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -457,10 +461,10 @@ public class TryListBuilderTest {
|
|||||||
public void testHandlerMerge_Exception_Catchall() {
|
public void testHandlerMerge_Exception_Catchall() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
TryListBuilder tlb = new TryListBuilder();
|
||||||
|
|
||||||
tlb.addHandler("LException1;", 5, 10, 5);
|
tlb.addHandler(5, 10, new ImmutableExceptionHandler("LException1;", 5));
|
||||||
tlb.addHandler(null, 0, 15, 6);
|
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(
|
List<? extends TryBlock> expected = ImmutableList.of(
|
||||||
new ImmutableTryBlock(0, 5,
|
new ImmutableTryBlock(0, 5,
|
||||||
@ -481,10 +485,10 @@ public class TryListBuilderTest {
|
|||||||
public void testHandlerMerge_Catchall_Exception() {
|
public void testHandlerMerge_Catchall_Exception() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
TryListBuilder tlb = new TryListBuilder();
|
||||||
|
|
||||||
tlb.addHandler(null, 5, 10, 5);
|
tlb.addHandler(5, 10, new ImmutableExceptionHandler(null, 5));
|
||||||
tlb.addHandler("LException1;", 0, 15, 6);
|
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(
|
List<? extends TryBlock> expected = ImmutableList.of(
|
||||||
new ImmutableTryBlock(0, 5,
|
new ImmutableTryBlock(0, 5,
|
||||||
@ -505,10 +509,10 @@ public class TryListBuilderTest {
|
|||||||
public void testHandlerMerge_Catchall_Catchall() {
|
public void testHandlerMerge_Catchall_Catchall() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
TryListBuilder tlb = new TryListBuilder();
|
||||||
|
|
||||||
tlb.addHandler(null, 5, 10, 5);
|
tlb.addHandler(5, 10, new ImmutableExceptionHandler(null, 5));
|
||||||
tlb.addHandler(null, 0, 15, 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(
|
List<? extends TryBlock> expected = ImmutableList.of(
|
||||||
new ImmutableTryBlock(0, 15,
|
new ImmutableTryBlock(0, 15,
|
||||||
@ -522,9 +526,9 @@ public class TryListBuilderTest {
|
|||||||
public void testHandlerMerge_Catchall_Catchall_DifferentAddress() {
|
public void testHandlerMerge_Catchall_Catchall_DifferentAddress() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
TryListBuilder tlb = new TryListBuilder();
|
||||||
|
|
||||||
tlb.addHandler(null, 5, 10, 5);
|
tlb.addHandler(5, 10, new ImmutableExceptionHandler(null, 5));
|
||||||
try {
|
try {
|
||||||
tlb.addHandler(null, 0, 15, 6);
|
tlb.addHandler(0, 15, new ImmutableExceptionHandler(null, 6));
|
||||||
} catch (TryListBuilder.InvalidTryException ex) {
|
} catch (TryListBuilder.InvalidTryException ex) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -535,12 +539,12 @@ public class TryListBuilderTest {
|
|||||||
public void testHandlerMerge_MergeSame() {
|
public void testHandlerMerge_MergeSame() {
|
||||||
TryListBuilder tlb = new TryListBuilder();
|
TryListBuilder tlb = new TryListBuilder();
|
||||||
|
|
||||||
tlb.addHandler(null, 0, 15, 6);
|
tlb.addHandler(0, 15, new ImmutableExceptionHandler(null, 6));
|
||||||
tlb.addHandler("LException1;", 10, 20, 5);
|
tlb.addHandler(10, 20, new ImmutableExceptionHandler("LException1;", 5));
|
||||||
tlb.addHandler("LException1;", 20, 30, 5);
|
tlb.addHandler(20, 30, new ImmutableExceptionHandler("LException1;", 5));
|
||||||
tlb.addHandler(null, 25, 40, 6);
|
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(
|
List<? extends TryBlock> expected = ImmutableList.of(
|
||||||
new ImmutableTryBlock(0, 10,
|
new ImmutableTryBlock(0, 10,
|
||||||
|
@ -388,7 +388,7 @@ method returns[Method ret]
|
|||||||
annotations
|
annotations
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
List<TryBlock> tryBlocks = $catches.tryBlocks;
|
List<TryBlock<? extends ExceptionHandler>> tryBlocks = $catches.tryBlocks;
|
||||||
List<DebugItem> debugItems = $ordered_debug_directives.debugItems;
|
List<DebugItem> debugItems = $ordered_debug_directives.debugItems;
|
||||||
|
|
||||||
MethodImplementation methodImplementation = null;
|
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();}
|
@init {tryBlocks = Lists.newArrayList();}
|
||||||
: ^(I_CATCHES (catch_directive { tryBlocks.add($catch_directive.tryBlock); })*
|
: ^(I_CATCHES (catch_directive { tryBlocks.add($catch_directive.tryBlock); })*
|
||||||
(catchall_directive { tryBlocks.add($catchall_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]
|
: ^(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])
|
using=offset_or_label_absolute[$address.address])
|
||||||
{
|
{
|
||||||
@ -588,7 +588,7 @@ catch_directive returns[TryBlock tryBlock]
|
|||||||
ImmutableList.of(new ImmutableExceptionHandler(type, handlerAddress)));
|
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]
|
: ^(I_CATCHALL address from=offset_or_label_absolute[$address.address] to=offset_or_label_absolute[$address.address]
|
||||||
using=offset_or_label_absolute[$address.address])
|
using=offset_or_label_absolute[$address.address])
|
||||||
{
|
{
|
||||||
|
@ -79,6 +79,7 @@ public class CollectionUtils {
|
|||||||
for (T element1: it1) {
|
for (T element1: it1) {
|
||||||
T element2;
|
T element2;
|
||||||
try {
|
try {
|
||||||
|
// TODO: would checking hasNext be more efficient?
|
||||||
element2 = elements2.next();
|
element2 = elements2.next();
|
||||||
} catch (NoSuchElementException ex) {
|
} catch (NoSuchElementException ex) {
|
||||||
return 1;
|
return 1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user