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 
17 package dexfuzz.rawdex;
18 
19 /**
20  * Tracks the original and updated positions of a RawDexObject when it is
21  * parsed in from a DEX file, and written out to a mutated DEX file.
22  */
23 public class Offsettable {
24   /**
25    * The position of this Offsettable's item when it was read in.
26    */
27   private int originalPosition;
28 
29   /**
30    * Set as we write out any Offsettable, so the Offset knows what its
31    * new value should be.
32    */
33   private int newPosition;
34 
35   /**
36    * The actual Item this Offsettable contains.
37    */
38   private RawDexObject item;
39 
40   /**
41    *  Set either when getOriginalPosition() is called by the OffsetTracker
42    *  to put the location in the offsettable map, so when Offsets are being
43    *  associated, they know which Offsettable to point at.
44    *  Or when an Offsettable is created that is marked as new, so we don't
45    *  need to know its original position, because an Offset will be directly
46    *  associated with it.
47    */
48   private boolean originalPositionKnown;
49 
50   /**
51    * Set when we calculate the new position of this Offsettable as the file is
52    * being output.
53    */
54   private boolean updated;
55 
56   /**
57    * Only the OffsetTracker should be able to create a new Offsettable.
58    */
Offsettable(RawDexObject item, boolean isNew)59   public Offsettable(RawDexObject item, boolean isNew) {
60     this.item = item;
61     if (isNew) {
62       // We no longer care about the original position of the Offsettable, because
63       // we are at the stage where we manually point Offsets at Offsettables, and
64       // don't need to use the OffsetTracker's offsettable map.
65       // So just lie and say we know it now.
66       originalPositionKnown = true;
67     }
68   }
69 
getItem()70   public RawDexObject getItem() {
71     return item;
72   }
73 
74   /**
75    * Gets the offset from the beginning of the file to the RawDexObject this Offsettable
76    * contains, when the file was originally read.
77    * Called when we're associating Offsets with Offsettables using the OffsetTracker's
78    * offsettable map.
79    */
getOriginalPosition()80   public int getOriginalPosition() {
81     if (!originalPositionKnown) {
82       throw new Error("Cannot get the original position of an Offsettable when not yet set.");
83     }
84     return originalPosition;
85   }
86 
setOriginalPosition(int pos)87   public void setOriginalPosition(int pos) {
88     originalPosition = pos;
89     originalPositionKnown = true;
90   }
91 
92   /**
93    * Get the new position of this Offsettable, once it's been written out to the output file.
94    */
getNewPosition()95   public int getNewPosition() {
96     if (!updated) {
97       throw new Error("Cannot request new position before it has been set!");
98     }
99     return newPosition;
100   }
101 
102   /**
103    * Record the new position of this Offsettable, as it is written out to the output file.
104    */
setNewPosition(int pos)105   public void setNewPosition(int pos) {
106     if (!updated) {
107       newPosition = pos;
108       updated = true;
109     } else {
110       throw new Error("Cannot update an Offsettable twice!");
111     }
112   }
113 
readyForFinalOffsetToBeWritten()114   public boolean readyForFinalOffsetToBeWritten() {
115     return (originalPositionKnown && updated);
116   }
117 }
118