15867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com/*
25867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * [The "BSD licence"]
300fc68adf2e39aeb9fed35293f2576bbe729ec4bJesusFreke@JesusFreke.com * Copyright (c) 2010 Ben Gruver (JesusFreke)
45867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * All rights reserved.
55867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com *
65867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * Redistribution and use in source and binary forms, with or without
75867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * modification, are permitted provided that the following conditions
85867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * are met:
95867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * 1. Redistributions of source code must retain the above copyright
105867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com *    notice, this list of conditions and the following disclaimer.
115867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * 2. Redistributions in binary form must reproduce the above copyright
125867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com *    notice, this list of conditions and the following disclaimer in the
135867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com *    documentation and/or other materials provided with the distribution.
145867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * 3. The name of the author may not be used to endorse or promote products
155867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com *    derived from this software without specific prior written permission.
165867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com *
175867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
185867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
195867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
205867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
215867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
225867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
235867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
265867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com */
285867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
295867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.compackage org.jf.dexlib.Util;
305867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
315867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.comimport org.jf.dexlib.CodeItem;
325867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.comimport org.jf.dexlib.TypeIdItem;
335867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
345867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.comimport java.util.ArrayList;
355867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.comimport java.util.HashMap;
365867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.comimport java.util.LinkedList;
375867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.comimport java.util.List;
385867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
395867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.compublic class TryListBuilder
405867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com{
415867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com    /*TODO: add logic to merge adjacent, identical try blocks, and remove superflous handlers
425867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com      Also provide a "strict" mode, where the above isn't performed, which will be useful to be able to
435867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com      exactly reproduce the original .dex file (for testing/verification purposes)*/
445867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
455867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
465867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com    private TryRange firstTryRange = new TryRange(0,0);
475867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com    private TryRange lastTryRange = new TryRange(0,0);
485867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
495867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com    public TryListBuilder() {
505867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        firstTryRange.next = lastTryRange;
515867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        lastTryRange.previous = firstTryRange;
525867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com    }
535867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
545867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com    private class TryRange
555867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com    {
565867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        public TryRange previous = null;
575867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        public TryRange next = null;
585867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
595867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        public int startAddress;
605867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        public int endAddress;
615867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        public LinkedList<Handler> handlers;
625867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
635867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        public int catchAllHandlerAddress;
645867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
655867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        public TryRange(int startAddress, int endAddress) {
665867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            this.startAddress = startAddress;
675867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            this.endAddress = endAddress;
685867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            this.handlers = new LinkedList<Handler>();
695867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            this.previous = null;
705867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            this.next = null;
715867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            catchAllHandlerAddress = -1;
725867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        }
735867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
745867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        public void append(TryRange tryRange) {
755867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            /*we use a dummy last item, so this.next will always
765867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            have a value*/
775867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            this.next.previous = tryRange;
785867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            tryRange.next = this.next;
795867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
805867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            this.next = tryRange;
815867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            tryRange.previous = this;
825867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        }
835867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
845867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        public void prepend(TryRange tryRange){
855867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            /*we use a dummy first item, so this.previous will always
865867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            have a value*/
875867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            this.previous.next = tryRange;
885867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            tryRange.previous = this.previous;
895867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
905867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            this.previous = tryRange;
915867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            tryRange.next = this;
925867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        }
935867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
945867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        /**
955867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com         * This splits the current range into two ranges at the given
965867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com         * address. The existing range will be shortened to the first
975867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com         * half, and a new range will be created and returned for the
985867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com         * 2nd half.
995867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com         * @param address The address to split at
1005867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com         * @return The 2nd half of the
1015867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com         */
1025867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        public TryRange split(int address) {
1035867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            //this is a private class, so address is assumed
1045867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            //to be valid
1055867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
1065867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            TryRange tryRange = new TryRange(address, endAddress);
1075867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            tryRange.catchAllHandlerAddress = this.catchAllHandlerAddress;
1085867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            tryRange.handlers.addAll(this.handlers);
1095867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            append(tryRange);
1105867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
1115867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            this.endAddress = address;
1125867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
1135867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            return tryRange;
1145867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        }
1155867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
1165867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        public void appendHandler(Handler handler) {
1175867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            handlers.addLast(handler);
1185867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        }
1195867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
1205867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        public void prependHandler(Handler handler) {
1215867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            handlers.addFirst(handler);
1225867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        }
1235867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com    }
1245867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
1255867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com    private class Handler
1265867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com    {
1275867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        public final TypeIdItem type;
1285867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        public final int handlerAddress;
1295867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
1305867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        public Handler(TypeIdItem type, int handlerAddress) {
1315867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            this.type = type;
1325867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            this.handlerAddress = handlerAddress;
1335867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        }
1345867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com    }
1355867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
1365867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com    public Pair<List<CodeItem.TryItem>, List<CodeItem.EncodedCatchHandler>> encodeTries() {
1375867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        if (firstTryRange.next == lastTryRange) {
1385867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            return new Pair<List<CodeItem.TryItem>, List<CodeItem.EncodedCatchHandler>>(null, null);
1395867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        }
1405867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
1415867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        ArrayList<CodeItem.TryItem> tries = new ArrayList<CodeItem.TryItem>();
1425867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        ArrayList<CodeItem.EncodedCatchHandler> handlers = new ArrayList<CodeItem.EncodedCatchHandler>();
1435867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
1445867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        HashMap<CodeItem.EncodedCatchHandler, CodeItem.EncodedCatchHandler> handlerDict =
1455867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com	                    new HashMap<CodeItem.EncodedCatchHandler, CodeItem.EncodedCatchHandler>();
1465867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
1475867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        TryRange tryRange = firstTryRange.next;
1485867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
1495867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        while (tryRange != lastTryRange) {
1505867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            CodeItem.EncodedTypeAddrPair[] encodedTypeAddrPairs =
1515867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                    new CodeItem.EncodedTypeAddrPair[tryRange.handlers.size()];
1525867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
1535867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            int index = 0;
1545867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            for (Handler handler: tryRange.handlers) {
1555867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                CodeItem.EncodedTypeAddrPair encodedTypeAddrPair = new CodeItem.EncodedTypeAddrPair(
1565867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                        handler.type,
1575867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                        handler.handlerAddress);
1585867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                encodedTypeAddrPairs[index++] = encodedTypeAddrPair;
1595867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            }
1605867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
1615867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            CodeItem.EncodedCatchHandler encodedCatchHandler = new CodeItem.EncodedCatchHandler(
1625867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                                                                    encodedTypeAddrPairs,
1635867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                                                                    tryRange.catchAllHandlerAddress);
1645867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            CodeItem.EncodedCatchHandler internedEncodedCatchHandler = handlerDict.get(encodedCatchHandler);
1655867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            if (internedEncodedCatchHandler == null) {
1665867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                handlerDict.put(encodedCatchHandler, encodedCatchHandler);
1675867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                handlers.add(encodedCatchHandler);
1685867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            } else {
1695867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                encodedCatchHandler = internedEncodedCatchHandler;
1705867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            }
1715867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
1725867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            CodeItem.TryItem tryItem = new CodeItem.TryItem(
1735867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                    tryRange.startAddress,
1745867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                    tryRange.endAddress - tryRange.startAddress,
1755867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                    encodedCatchHandler);
1765867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            tries.add(tryItem);
1775867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
1785867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            tryRange = tryRange.next;
1795867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        }
1805867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
1815867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        return new Pair<List<CodeItem.TryItem>, List<CodeItem.EncodedCatchHandler>>(tries, handlers);
1825867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com    }
1835867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
1845867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com    public void addCatchAllHandler(int startAddress, int endAddress, int handlerAddress) {
1855867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        TryRange startRange;
1865867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        TryRange endRange;
1875867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
1885867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        Pair<TryRange, TryRange> ranges = getBoundingRanges(startAddress, endAddress);
1895867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        startRange = ranges.first;
1905867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        endRange = ranges.second;
1915867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
1925867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        int previousEnd = startAddress;
1935867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        TryRange tryRange = startRange;
1945867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
1955867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        /*Now we have the start and end ranges that exactly match the start and end
1965867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        of the range being added. We need to iterate over all the ranges from the start
1975867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        to end range inclusively, and append the handler to the end of each range's handler
1985867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        list. We also need to create a new range for any "holes" in the existing ranges*/
1995867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        do
2005867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        {
2015867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            //is there a hole? If so, add a new range to fill the hole
2025867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            if (tryRange.startAddress > previousEnd) {
2035867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                TryRange newRange = new TryRange(previousEnd, tryRange.startAddress);
2045867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                tryRange.prepend(newRange);
2055867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                tryRange = newRange;
2065867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            }
2075867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
2085867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            if (tryRange.catchAllHandlerAddress == -1) {
2095867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                tryRange.catchAllHandlerAddress = handlerAddress;
2105867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            }
2115867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
2125867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            previousEnd = tryRange.endAddress;
2135867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            tryRange = tryRange.next;
2145867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        } while (tryRange.previous != endRange);
2155867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com    }
2165867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
2175867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com    public Pair<TryRange, TryRange> getBoundingRanges(int startAddress, int endAddress) {
2185867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        TryRange startRange = null;
2195867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        TryRange endRange = null;
2205867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
2215867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        TryRange tryRange = firstTryRange.next;
2225867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        while (tryRange != lastTryRange) {
2235867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            if (startAddress == tryRange.startAddress) {
2245867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                //|-----|
2255867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                //^------
2265867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                /*Bam. We hit the start of the range right on the head*/
2275867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                startRange = tryRange;
2285867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                break;
2295867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            } else if (startAddress > tryRange.startAddress && startAddress < tryRange.endAddress) {
2305867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                //|-----|
2315867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                //  ^----
2325867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                /*Almost. The start of the range being added is in the middle
2335867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                of an existing try range. We need to split the existing range
2345867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                at the start address of the range being added*/
2355867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                startRange = tryRange.split(startAddress);
2365867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                break;
2375867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            }else if (startAddress < tryRange.startAddress) {
2385867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                if (endAddress <= tryRange.startAddress) {
2395867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                    //      |-----|
2405867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                    //^--^
2415867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                    /*Oops, totally too far! The new range doesn't overlap any existing
2425867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                    ones, so we just add it and return*/
2435867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                    startRange = new TryRange(startAddress, endAddress);
2445867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                    tryRange.prepend(startRange);
2455867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                    return new Pair<TryRange, TryRange>(startRange, startRange);
2465867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                } else {
2475867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                    //   |-----|
2485867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                    //^---------
2495867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                    /*Oops, too far! We've passed the start of the range being added, but
2505867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                     the new range does overlap this one. We need to add a new range just
2515867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                     before this one*/
2525867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                    startRange = new TryRange(startAddress, tryRange.startAddress);
2535867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                    tryRange.prepend(startRange);
2545867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                    break;
2555867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                }
2565867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            }
2575867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
2585867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            tryRange = tryRange.next;
2595867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        }
2605867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
2615867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        //|-----|
2625867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        //        ^-----
2635867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        /*Either the list of tries is blank, or all the tries in the list
2645867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        end before the range being added starts. In either case, we just need
2655867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        to add a new range at the end of the list*/
2665867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        if (startRange == null) {
2675867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            startRange = new TryRange(startAddress, endAddress);
2685867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            lastTryRange.prepend(startRange);
2695867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            return new Pair<TryRange, TryRange>(startRange, startRange);
2705867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        }
2715867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
2725867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        tryRange = startRange;
2735867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        while (tryRange != lastTryRange) {
2745867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            if (tryRange.endAddress == endAddress) {
2755867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                //|-----|
2765867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                //------^
2775867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                /*Bam! We hit the end right on the head.*/
2785867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                endRange = tryRange;
2795867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                break;
2805867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            } else if (tryRange.startAddress < endAddress && tryRange.endAddress > endAddress) {
2815867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                //|-----|
2825867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                //--^
2835867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                /*Almost. The range being added ends in the middle of an
2845867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                existing range. We need to split the existing range
2855867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                at the end of the range being added.*/
2865867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                tryRange.split(endAddress);
2875867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                endRange = tryRange;
2885867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                break;
2895867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            } else if (tryRange.startAddress >= endAddress) {
2905867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                //|-----|       |-----|
2915867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                //-----------^
2925867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                /*Oops, too far! The current range starts after the range being added
2935867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                ends. We need to create a new range that starts at the end of the
2945867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                previous range, and ends at the end of the range being added*/
2955867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                endRange = new TryRange(tryRange.previous.endAddress, endAddress);
2965867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                tryRange.prepend(endRange);
2975867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                break;
2985867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            }
2995867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            tryRange = tryRange.next;
3005867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        }
3015867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
3025867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        //|-----|
3035867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        //--------^
3045867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        /*The last range in the list ended before the end of the range being added.
3055867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        We need to add a new range that starts at the end of the last range in the
3065867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        list, and ends at the end of the range being added.*/
3075867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        if (endRange == null) {
3085867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            endRange = new TryRange(lastTryRange.previous.endAddress, endAddress);
3095867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            lastTryRange.prepend(endRange);
3105867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        }
3115867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
3125867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        return new Pair<TryRange, TryRange>(startRange, endRange);
3135867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com    }
3145867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
3155867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com    public void addHandler(TypeIdItem type, int startAddress, int endAddress, int handlerAddress) {
3165867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        TryRange startRange;
3175867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        TryRange endRange;
3185867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
3195867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        //TODO: need to check for pre-existing exception types in the handler list?
3205867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
3215867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        Pair<TryRange, TryRange> ranges = getBoundingRanges(startAddress, endAddress);
3225867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        startRange = ranges.first;
3235867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        endRange = ranges.second;
3245867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        Handler handler = new Handler(type, handlerAddress);
3255867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
3265867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        int previousEnd = startAddress;
3275867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        TryRange tryRange = startRange;
3285867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
3295867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        /*Now we have the start and end ranges that exactly match the start and end
3305867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        of the range being added. We need to iterate over all the ranges from the start
3315867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        to end range inclusively, and append the handler to the end of each range's handler
3325867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        list. We also need to create a new range for any "holes" in the existing ranges*/
3335867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        do
3345867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        {
3355867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            //is there a hole? If so, add a new range to fill the hole
3365867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            if (tryRange.startAddress > previousEnd) {
3375867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                TryRange newRange = new TryRange(previousEnd, tryRange.startAddress);
3385867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                tryRange.prepend(newRange);
3395867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com                tryRange = newRange;
3405867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            }
3415867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com
3425867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            tryRange.appendHandler(handler);
3435867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            previousEnd = tryRange.endAddress;
3445867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com            tryRange = tryRange.next;
3455867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com        } while (tryRange.previous != endRange);
3465867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com    }
3475867263eb588f4671400895d1e6b01c01535061bJesusFreke@JesusFreke.com}
348