Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright 2012, Google Inc.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are
      7  * met:
      8  *
      9  *     * Redistributions of source code must retain the above copyright
     10  * notice, this list of conditions and the following disclaimer.
     11  *     * Redistributions in binary form must reproduce the above
     12  * copyright notice, this list of conditions and the following disclaimer
     13  * in the documentation and/or other materials provided with the
     14  * distribution.
     15  *     * Neither the name of Google Inc. nor the names of its
     16  * contributors may be used to endorse or promote products derived from
     17  * this software without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 package org.jf.dexlib2.util;
     33 
     34 import org.jf.dexlib2.iface.instruction.Instruction;
     35 import org.jf.util.ExceptionWithContext;
     36 
     37 import javax.annotation.Nonnull;
     38 import java.util.Arrays;
     39 import java.util.List;
     40 
     41 public class InstructionOffsetMap {
     42     @Nonnull private final int[] instructionCodeOffsets;
     43 
     44     public InstructionOffsetMap(@Nonnull List<? extends Instruction> instructions) {
     45         this.instructionCodeOffsets = new int[instructions.size()];
     46 
     47         int codeOffset = 0;
     48         for (int i=0; i<instructions.size(); i++) {
     49             instructionCodeOffsets[i] = codeOffset;
     50             codeOffset += instructions.get(i).getCodeUnits();
     51         }
     52     }
     53 
     54     public int getInstructionIndexAtCodeOffset(int codeOffset) {
     55         return getInstructionIndexAtCodeOffset(codeOffset, true);
     56     }
     57 
     58     public int getInstructionIndexAtCodeOffset(int codeOffset, boolean exact) {
     59         int index = Arrays.binarySearch(instructionCodeOffsets, codeOffset);
     60         if (index < 0) {
     61             if (exact) {
     62                 throw new InvalidInstructionOffset(codeOffset);
     63             } else {
     64                 // This calculation would be incorrect if index was -1 (i.e. insertion point of 0). Luckily, we can
     65                 // ignore this case, because codeOffset will always be non-negative, and the code offset of the first
     66                 // instruction will always be 0.
     67                 return (~index) - 1;
     68             }
     69         }
     70         return index;
     71     }
     72 
     73     public int getInstructionCodeOffset(int index) {
     74         if (index < 0 || index >= instructionCodeOffsets.length) {
     75             throw new InvalidInstructionIndex(index);
     76         }
     77         return instructionCodeOffsets[index];
     78     }
     79 
     80     public static class InvalidInstructionOffset extends ExceptionWithContext {
     81         private final int instructionOffset;
     82 
     83         public InvalidInstructionOffset(int instructionOffset) {
     84             super("No instruction at offset %d", instructionOffset);
     85             this.instructionOffset = instructionOffset;
     86         }
     87 
     88         public int getInstructionOffset() {
     89             return instructionOffset;
     90         }
     91     }
     92 
     93     public static class InvalidInstructionIndex extends ExceptionWithContext {
     94         private final int instructionIndex;
     95 
     96         public InvalidInstructionIndex(int instructionIndex) {
     97             super("Instruction index out of bounds: %d", instructionIndex);
     98             this.instructionIndex = instructionIndex;
     99         }
    100 
    101         public int getInstructionIndex() {
    102             return instructionIndex;
    103         }
    104     }
    105 }
    106