mirror of
https://github.com/revanced/smali.git
synced 2025-05-09 10:54:29 +02:00
Merged in TryListBuilder.java from the prior dexlib, and fixed it up to work with the new dexlib
git-svn-id: https://smali.googlecode.com/svn/trunk@406 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
parent
1877b664de
commit
3080fb1bfc
40
dexlib/src/main/java/org/jf/dexlib/Util/Pair.java
Normal file
40
dexlib/src/main/java/org/jf/dexlib/Util/Pair.java
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.jf.dexlib.Util;
|
||||
|
||||
public class Pair<A, B> {
|
||||
public final A first;
|
||||
public final B second;
|
||||
|
||||
public Pair(A first, B second) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
}
|
||||
|
347
dexlib/src/main/java/org/jf/dexlib/Util/TryListBuilder.java
Normal file
347
dexlib/src/main/java/org/jf/dexlib/Util/TryListBuilder.java
Normal file
@ -0,0 +1,347 @@
|
||||
/*
|
||||
* [The "BSD licence"]
|
||||
* Copyright (c) 2009 Ben Gruver
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.jf.dexlib.Util;
|
||||
|
||||
import org.jf.dexlib.CodeItem;
|
||||
import org.jf.dexlib.TypeIdItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class TryListBuilder
|
||||
{
|
||||
/*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)*/
|
||||
|
||||
|
||||
private TryRange firstTryRange = new TryRange(0,0);
|
||||
private TryRange lastTryRange = new TryRange(0,0);
|
||||
|
||||
public TryListBuilder() {
|
||||
firstTryRange.next = lastTryRange;
|
||||
lastTryRange.previous = firstTryRange;
|
||||
}
|
||||
|
||||
private class TryRange
|
||||
{
|
||||
public TryRange previous = null;
|
||||
public TryRange next = null;
|
||||
|
||||
public int startAddress;
|
||||
public int endAddress;
|
||||
public LinkedList<Handler> handlers;
|
||||
|
||||
public int catchAllHandlerAddress;
|
||||
|
||||
public TryRange(int startAddress, int endAddress) {
|
||||
this.startAddress = startAddress;
|
||||
this.endAddress = endAddress;
|
||||
this.handlers = new LinkedList<Handler>();
|
||||
this.previous = null;
|
||||
this.next = null;
|
||||
catchAllHandlerAddress = -1;
|
||||
}
|
||||
|
||||
public void append(TryRange tryRange) {
|
||||
/*we use a dummy last item, so this.next will always
|
||||
have a value*/
|
||||
this.next.previous = tryRange;
|
||||
tryRange.next = this.next;
|
||||
|
||||
this.next = tryRange;
|
||||
tryRange.previous = this;
|
||||
}
|
||||
|
||||
public void prepend(TryRange tryRange){
|
||||
/*we use a dummy first item, so this.previous will always
|
||||
have a value*/
|
||||
this.previous.next = tryRange;
|
||||
tryRange.previous = this.previous;
|
||||
|
||||
this.previous = tryRange;
|
||||
tryRange.next = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This splits the current range into two ranges at the given
|
||||
* address. The existing range will be shortened to the first
|
||||
* half, and a new range will be created and returned for the
|
||||
* 2nd half.
|
||||
* @param address The address to split at
|
||||
* @return The 2nd half of the
|
||||
*/
|
||||
public TryRange split(int address) {
|
||||
//this is a private class, so address is assumed
|
||||
//to be valid
|
||||
|
||||
TryRange tryRange = new TryRange(address, endAddress);
|
||||
tryRange.catchAllHandlerAddress = this.catchAllHandlerAddress;
|
||||
tryRange.handlers.addAll(this.handlers);
|
||||
append(tryRange);
|
||||
|
||||
this.endAddress = address;
|
||||
|
||||
return tryRange;
|
||||
}
|
||||
|
||||
public void appendHandler(Handler handler) {
|
||||
handlers.addLast(handler);
|
||||
}
|
||||
|
||||
public void prependHandler(Handler handler) {
|
||||
handlers.addFirst(handler);
|
||||
}
|
||||
}
|
||||
|
||||
private class Handler
|
||||
{
|
||||
public final TypeIdItem type;
|
||||
public final int handlerAddress;
|
||||
|
||||
public Handler(TypeIdItem type, int handlerAddress) {
|
||||
this.type = type;
|
||||
this.handlerAddress = handlerAddress;
|
||||
}
|
||||
}
|
||||
|
||||
public Pair<List<CodeItem.TryItem>, List<CodeItem.EncodedCatchHandler>> encodeTries() {
|
||||
if (firstTryRange.next == lastTryRange) {
|
||||
return new Pair<List<CodeItem.TryItem>, List<CodeItem.EncodedCatchHandler>>(null, null);
|
||||
}
|
||||
|
||||
ArrayList<CodeItem.TryItem> tries = new ArrayList<CodeItem.TryItem>();
|
||||
ArrayList<CodeItem.EncodedCatchHandler> handlers = new ArrayList<CodeItem.EncodedCatchHandler>();
|
||||
|
||||
HashMap<CodeItem.EncodedCatchHandler, CodeItem.EncodedCatchHandler> handlerDict =
|
||||
new HashMap<CodeItem.EncodedCatchHandler, CodeItem.EncodedCatchHandler>();
|
||||
|
||||
TryRange tryRange = firstTryRange.next;
|
||||
|
||||
while (tryRange != lastTryRange) {
|
||||
CodeItem.EncodedTypeAddrPair[] encodedTypeAddrPairs =
|
||||
new CodeItem.EncodedTypeAddrPair[tryRange.handlers.size()];
|
||||
|
||||
int index = 0;
|
||||
for (Handler handler: tryRange.handlers) {
|
||||
CodeItem.EncodedTypeAddrPair encodedTypeAddrPair = new CodeItem.EncodedTypeAddrPair(
|
||||
handler.type,
|
||||
handler.handlerAddress);
|
||||
encodedTypeAddrPairs[index++] = encodedTypeAddrPair;
|
||||
}
|
||||
|
||||
CodeItem.EncodedCatchHandler encodedCatchHandler = new CodeItem.EncodedCatchHandler(
|
||||
encodedTypeAddrPairs,
|
||||
tryRange.catchAllHandlerAddress);
|
||||
CodeItem.EncodedCatchHandler internedEncodedCatchHandler = handlerDict.get(encodedCatchHandler);
|
||||
if (internedEncodedCatchHandler == null) {
|
||||
handlerDict.put(encodedCatchHandler, encodedCatchHandler);
|
||||
handlers.add(encodedCatchHandler);
|
||||
} else {
|
||||
encodedCatchHandler = internedEncodedCatchHandler;
|
||||
}
|
||||
|
||||
CodeItem.TryItem tryItem = new CodeItem.TryItem(
|
||||
tryRange.startAddress,
|
||||
tryRange.endAddress - tryRange.startAddress,
|
||||
encodedCatchHandler);
|
||||
tries.add(tryItem);
|
||||
|
||||
tryRange = tryRange.next;
|
||||
}
|
||||
|
||||
return new Pair<List<CodeItem.TryItem>, List<CodeItem.EncodedCatchHandler>>(tries, handlers);
|
||||
}
|
||||
|
||||
public void addCatchAllHandler(int startAddress, int endAddress, int handlerAddress) {
|
||||
TryRange startRange;
|
||||
TryRange endRange;
|
||||
|
||||
Pair<TryRange, TryRange> ranges = getBoundingRanges(startAddress, endAddress);
|
||||
startRange = ranges.first;
|
||||
endRange = ranges.second;
|
||||
|
||||
int previousEnd = startAddress;
|
||||
TryRange tryRange = startRange;
|
||||
|
||||
/*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
|
||||
to end range inclusively, and append the handler to the end of each range's handler
|
||||
list. We also need to create a new range for any "holes" in the existing ranges*/
|
||||
do
|
||||
{
|
||||
//is there a hole? If so, add a new range to fill the hole
|
||||
if (tryRange.startAddress > previousEnd) {
|
||||
TryRange newRange = new TryRange(previousEnd, tryRange.startAddress);
|
||||
tryRange.prepend(newRange);
|
||||
tryRange = newRange;
|
||||
}
|
||||
|
||||
if (tryRange.catchAllHandlerAddress == -1) {
|
||||
tryRange.catchAllHandlerAddress = handlerAddress;
|
||||
}
|
||||
|
||||
previousEnd = tryRange.endAddress;
|
||||
tryRange = tryRange.next;
|
||||
} while (tryRange.previous != endRange);
|
||||
}
|
||||
|
||||
public Pair<TryRange, TryRange> getBoundingRanges(int startAddress, int endAddress) {
|
||||
TryRange startRange = null;
|
||||
TryRange endRange = null;
|
||||
|
||||
TryRange tryRange = firstTryRange.next;
|
||||
while (tryRange != lastTryRange) {
|
||||
if (startAddress == tryRange.startAddress) {
|
||||
//|-----|
|
||||
//^------
|
||||
/*Bam. We hit the start of the range right on the head*/
|
||||
startRange = tryRange;
|
||||
break;
|
||||
} else if (startAddress > tryRange.startAddress && startAddress < tryRange.endAddress) {
|
||||
//|-----|
|
||||
// ^----
|
||||
/*Almost. The start of the range being added is in the middle
|
||||
of an existing try range. We need to split the existing range
|
||||
at the start address of the range being added*/
|
||||
startRange = tryRange.split(startAddress);
|
||||
break;
|
||||
}else if (startAddress < tryRange.startAddress) {
|
||||
if (endAddress <= tryRange.startAddress) {
|
||||
// |-----|
|
||||
//^--^
|
||||
/*Oops, totally too far! The new range doesn't overlap any existing
|
||||
ones, so we just add it and return*/
|
||||
startRange = new TryRange(startAddress, endAddress);
|
||||
tryRange.prepend(startRange);
|
||||
return new Pair<TryRange, TryRange>(startRange, startRange);
|
||||
} else {
|
||||
// |-----|
|
||||
//^---------
|
||||
/*Oops, too far! We've passed the start of the range being added, but
|
||||
the new range does overlap this one. We need to add a new range just
|
||||
before this one*/
|
||||
startRange = new TryRange(startAddress, tryRange.startAddress);
|
||||
tryRange.prepend(startRange);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tryRange = tryRange.next;
|
||||
}
|
||||
|
||||
//|-----|
|
||||
// ^-----
|
||||
/*Either the list of tries is blank, or all the tries in the list
|
||||
end before the range being added starts. In either case, we just need
|
||||
to add a new range at the end of the list*/
|
||||
if (startRange == null) {
|
||||
startRange = new TryRange(startAddress, endAddress);
|
||||
lastTryRange.prepend(startRange);
|
||||
return new Pair<TryRange, TryRange>(startRange, startRange);
|
||||
}
|
||||
|
||||
tryRange = startRange;
|
||||
while (tryRange != lastTryRange) {
|
||||
if (tryRange.endAddress == endAddress) {
|
||||
//|-----|
|
||||
//------^
|
||||
/*Bam! We hit the end right on the head.*/
|
||||
endRange = tryRange;
|
||||
break;
|
||||
} else if (tryRange.startAddress < endAddress && tryRange.endAddress > endAddress) {
|
||||
//|-----|
|
||||
//--^
|
||||
/*Almost. The range being added ends in the middle of an
|
||||
existing range. We need to split the existing range
|
||||
at the end of the range being added.*/
|
||||
tryRange.split(endAddress);
|
||||
endRange = tryRange;
|
||||
break;
|
||||
} else if (tryRange.startAddress >= endAddress) {
|
||||
//|-----| |-----|
|
||||
//-----------^
|
||||
/*Oops, too far! The current range starts after the range being added
|
||||
ends. We need to create a new range that starts at the end of the
|
||||
previous range, and ends at the end of the range being added*/
|
||||
endRange = new TryRange(tryRange.previous.endAddress, endAddress);
|
||||
tryRange.prepend(endRange);
|
||||
break;
|
||||
}
|
||||
tryRange = tryRange.next;
|
||||
}
|
||||
|
||||
//|-----|
|
||||
//--------^
|
||||
/*The last range in the list ended before the end of the range being added.
|
||||
We need to add a new range that starts at the end of the last range in the
|
||||
list, and ends at the end of the range being added.*/
|
||||
if (endRange == null) {
|
||||
endRange = new TryRange(lastTryRange.previous.endAddress, endAddress);
|
||||
lastTryRange.prepend(endRange);
|
||||
}
|
||||
|
||||
return new Pair<TryRange, TryRange>(startRange, endRange);
|
||||
}
|
||||
|
||||
public void addHandler(TypeIdItem type, int startAddress, int endAddress, int handlerAddress) {
|
||||
TryRange startRange;
|
||||
TryRange endRange;
|
||||
|
||||
//TODO: need to check for pre-existing exception types in the handler list?
|
||||
|
||||
Pair<TryRange, TryRange> ranges = getBoundingRanges(startAddress, endAddress);
|
||||
startRange = ranges.first;
|
||||
endRange = ranges.second;
|
||||
Handler handler = new Handler(type, handlerAddress);
|
||||
|
||||
int previousEnd = startAddress;
|
||||
TryRange tryRange = startRange;
|
||||
|
||||
/*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
|
||||
to end range inclusively, and append the handler to the end of each range's handler
|
||||
list. We also need to create a new range for any "holes" in the existing ranges*/
|
||||
do
|
||||
{
|
||||
//is there a hole? If so, add a new range to fill the hole
|
||||
if (tryRange.startAddress > previousEnd) {
|
||||
TryRange newRange = new TryRange(previousEnd, tryRange.startAddress);
|
||||
tryRange.prepend(newRange);
|
||||
tryRange = newRange;
|
||||
}
|
||||
|
||||
tryRange.appendHandler(handler);
|
||||
previousEnd = tryRange.endAddress;
|
||||
tryRange = tryRange.next;
|
||||
} while (tryRange.previous != endRange);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user