1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package dexfuzz.rawdex; 18 19import dexfuzz.Log; 20 21public class Offset { 22 /** 23 * The absolute value of this offset as it was originally read. 24 */ 25 private int originalOffset; 26 27 /** 28 * The Offsettable that this Offset points to. 29 */ 30 private Offsettable offsettable; 31 32 /** 33 * The location of this Offset in the new file, ONLY SET IF the Offset 34 * couldn't be written because what it points to hasn't been written 35 * yet. 36 */ 37 private int outputLocation; 38 39 /** 40 * Was the output location for this Offset set?. 41 */ 42 private boolean outputLocationSet; 43 44 /** 45 * Does this Offset need to be written out using ULEB128?. 46 */ 47 private boolean useUleb128; 48 49 /** 50 * Was this Offset created after reading, during mutation?. 51 */ 52 private boolean isNewOffset; 53 54 /** 55 * Only one Offset should have this flag set, the MapItem that points 56 * to the HeaderItem. 57 */ 58 private boolean pointsAtHeader; 59 60 /** 61 * If an Offset pointed at 0 (because it is not actually a valid Offset), 62 * and it's not pointing at the header, then this is set. 63 */ 64 private boolean pointsAtNull; 65 66 public Offset(boolean header) { 67 pointsAtHeader = header; 68 } 69 70 public RawDexObject getPointedToItem() { 71 return offsettable.getItem(); 72 } 73 74 public boolean pointsToSomething() { 75 return offsettable != null; 76 } 77 78 public boolean pointsAtNull() { 79 return pointsAtNull; 80 } 81 82 public boolean pointsAtHeader() { 83 return pointsAtHeader; 84 } 85 86 /** 87 * Returns true if this Offset points at the provided RawDexObject. 88 */ 89 public boolean pointsToThisItem(RawDexObject thisItem) { 90 if (!pointsToSomething()) { 91 return false; 92 } 93 return (offsettable.getItem().equals(thisItem)); 94 } 95 96 /** 97 * Returns true if this Offset points at the provided Offsettable. 98 */ 99 public boolean pointsToThisOffsettable(Offsettable thisOffsettable) { 100 if (!pointsToSomething()) { 101 return false; 102 } 103 return (offsettable.equals(thisOffsettable)); 104 } 105 106 /** 107 * Makes this Offset point at a new Offsettable. 108 */ 109 public void pointTo(Offsettable offsettableItem) { 110 if (offsettable != null) { 111 Log.debug("Updating what an Offset points to..."); 112 } 113 offsettable = offsettableItem; 114 } 115 116 /** 117 * Call this to make an Offset that pointed at null before now point at something. 118 * An Offset may have previously pointed at null before... 119 * Example: if there are no fields referred to in a DEX file, then header.field_ids_off 120 * will point at null. We distinguish when Offsets point at null, and are not pointing 121 * at the header (only the header MapItem should do this) with a flag. Therefore, this 122 * method is needed to indicate that this Offset now points at something. 123 */ 124 public void unsetNullAndPointTo(Offsettable offsettableItem) { 125 pointsAtNull = false; 126 if (offsettable != null) { 127 Log.debug("Updating what an Offset points to..."); 128 } 129 offsettable = offsettableItem; 130 } 131 132 public void pointToNew(Offsettable offsettableItem) { 133 offsettable = offsettableItem; 134 isNewOffset = true; 135 } 136 137 public int getNewPositionOfItem() { 138 return offsettable.getNewPosition(); 139 } 140 141 public boolean usesUleb128() { 142 return useUleb128; 143 } 144 145 /** 146 * Mark this Offset as using the ULEB128 encoding. 147 */ 148 public void setUsesUleb128() { 149 if (useUleb128) { 150 throw new Error("Offset is already marked as using ULEB128!"); 151 } 152 useUleb128 = true; 153 } 154 155 public boolean isNewOffset() { 156 return isNewOffset; 157 } 158 159 public void setPointsAtNull() { 160 pointsAtNull = true; 161 } 162 163 public void setOutputLocation(int loc) { 164 outputLocation = loc; 165 outputLocationSet = true; 166 } 167 168 /** 169 * Get the location in the output DEX file where this offset has been written. 170 * (This is used when patching Offsets when the Offsettable position was not 171 * known at the time of writing out the Offset.) 172 */ 173 public int getOutputLocation() { 174 if (!outputLocationSet) { 175 throw new Error("Output location was not set yet!"); 176 } 177 return outputLocation; 178 } 179 180 public void setOriginalOffset(int offset) { 181 originalOffset = offset; 182 } 183 184 public int getOriginalOffset() { 185 return originalOffset; 186 } 187 188 public boolean readyForWriting() { 189 return offsettable.readyForFinalOffsetToBeWritten(); 190 } 191} 192