1959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle/*
2959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Copyright (C) 2014 The Android Open Source Project
3959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle *
4959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Licensed under the Apache License, Version 2.0 (the "License");
5959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * you may not use this file except in compliance with the License.
6959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * You may obtain a copy of the License at
7959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle *
8959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle *      http://www.apache.org/licenses/LICENSE-2.0
9959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle *
10959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Unless required by applicable law or agreed to in writing, software
11959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * distributed under the License is distributed on an "AS IS" BASIS,
12959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * See the License for the specific language governing permissions and
14959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * limitations under the License.
15959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */
16959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
17959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kylepackage dexfuzz.rawdex;
18959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
19959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.Log;
20959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
21959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.io.FileNotFoundException;
22959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.io.IOException;
23959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.io.RandomAccessFile;
24959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
25959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle/**
26959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * An extension to RandomAccessFile that allows reading/writing
27959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * DEX files in little-endian form, the variable-length LEB format
28959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * and also provides word-alignment functions.
29959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */
30959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kylepublic class DexRandomAccessFile extends RandomAccessFile {
31959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  private OffsetTracker offsetTracker;
32959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
33959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public OffsetTracker getOffsetTracker() {
34959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    return offsetTracker;
35959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
36959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
37959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public void setOffsetTracker(OffsetTracker offsetTracker) {
38959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    this.offsetTracker = offsetTracker;
39959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
40959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
41959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
42959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * Constructor, passes straight on to RandomAccessFile currently.
43959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * @param filename The file to open.
44959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * @param mode Strings "r" or "rw" work best.
45959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
46959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public DexRandomAccessFile(String filename, String mode)
47959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      throws FileNotFoundException {
48959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    super(filename, mode);
49959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
50959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
51959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
52959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * @return A 16-bit number, read from the file as little-endian.
53959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
54959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public short readUShort() throws IOException {
55959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int b1 = readUnsignedByte();
56959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int b2 = readUnsignedByte();
57959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    return (short) ((b2 << 8) | b1);
58959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
59959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
60959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
61959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * @param value A 16-bit number to be written to the file in little-endian.
62959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
63959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public void writeUShort(short value) throws IOException {
64959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int b1 = value & 0xff;
65959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int b2 = (value & 0xff00) >> 8;
66959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    writeByte(b1);
67959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    writeByte(b2);
68959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
69959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
70959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
71959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * @return A 32-bit number, read from the file as little-endian.
72959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
73959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public int readUInt() throws IOException {
74959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int b1 = readUnsignedByte();
75959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int b2 = readUnsignedByte();
76959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int b3 = readUnsignedByte();
77959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int b4 = readUnsignedByte();
78959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    return (b4 << 24) | (b3 << 16) | (b2 << 8) | b1;
79959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
80959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
81959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
82959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * @param value A 32-bit number to be written to the file in little-endian.
83959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
84959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public void writeUInt(int value) throws IOException {
85959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int b1 = value & 0xff;
86959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    writeByte(b1);
87959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int b2 = (value & 0xff00) >> 8;
88959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    writeByte(b2);
89959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int b3 = (value & 0xff0000) >> 16;
90959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    writeByte(b3);
91959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int b4 = (value & 0xff000000) >> 24;
92959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    writeByte(b4);
93959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
94959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
95959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
96959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * @return An up to 32-bit number, read from the file in ULEB128 form.
97959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
98959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public int readUleb128() throws IOException {
99959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int shift = 0;
100959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int value = 0;
101959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int rawByte = readUnsignedByte();
102959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    boolean done = false;
103959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    while (!done) {
104959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Get the lower seven bits.
105959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // 0x7f = 0111 1111
106959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      value |= ((rawByte & 0x7f) << shift);
107959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      shift += 7;
108959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Check the 8th bit - if it's 0, we're done.
109959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // 0x80 = 1000 0000
110959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      if ((rawByte & 0x80) == 0) {
111959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        done = true;
112959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      } else {
113959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        rawByte = readUnsignedByte();
114959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
115959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
116959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    return value;
117959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
118959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
119959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
120959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * @param value A 32-bit number to be written to the file in ULEB128 form.
121959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
122959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public void writeUleb128(int value) throws IOException {
123959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if (value == 0) {
124959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      writeByte(0);
125959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      return;
126959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
127959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
128959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    while (value != 0) {
129959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      int marker = 1;
130959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // If we're down to the last 7 bits, the marker will be 0.
131959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      if ((value & 0xffffff80) == 0) {
132959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        marker = 0;
133959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
134959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Get the lowest 7 bits, add on the marker in the high bit.
135959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      int nextByte = value & 0x7f | (marker << 7);
136959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      writeByte(nextByte);
137959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      value >>>= 7;
138959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
139959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
140959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
141959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
142959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * Write out ULEB128 value always using 5 bytes.
143959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * A version of ULEB128 that will always write out 5 bytes, because this
144959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * value will be patched later, and if we used a smaller encoding, the new value
145959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * may overflow the previously selected encoding size.
146959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * The largest encoding for 0 in ULEB128 would be:
147959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   *   0x80 0x80 0x80 0x80 0x00
148959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * and for 1 would be:
149959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   *   0x81 0x80 0x80 0x80 0x00
150959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
151959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public void writeLargestUleb128(int value) throws IOException {
152959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    Log.debug("Writing " + value + " using the largest possible ULEB128 encoding.");
153959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if (value == 0) {
154959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      writeByte(0x80);
155959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      writeByte(0x80);
156959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      writeByte(0x80);
157959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      writeByte(0x80);
158959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      writeByte(0x0);
159959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      return;
160959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
161959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
162959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (int i = 0; i < 5; i++) {
163959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      int marker = 1;
164959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // If we're writing the 5th byte, the marker is 0.
165959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      if (i == 4) {
166959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        marker = 0;
167959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
168959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Get the lowest 7 bits, add on the marker in the high bit.
169959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      int nextByte = value & 0x7f | (marker << 7);
170959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      writeByte(nextByte);
171959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      value >>>= 7;
172959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
173959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
174959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
175959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
176959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * @return An up to 32-bit number, read from the file in SLEB128 form.
177959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
178959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public int readSleb128() throws IOException {
179959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int shift = 0;
180959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int value = 0;
181959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int rawByte = readUnsignedByte();
182959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    boolean done = false;
183959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    boolean mustSignExtend = false;
184959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    while (!done) {
185959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Get the lower seven bits.
186959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // 0x7f = 0111 1111
187959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      value |= ((rawByte & 0x7f) << shift);
188959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      shift += 7;
189959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Check the 8th bit - if it's 0, we're done.
190959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // 0x80 = 1000 0000
191959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      if ((rawByte & 0x80) == 0) {
192959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        // Check the 7th bit - if it's a 1, we need to sign extend.
193959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        if ((rawByte & 0x60) != 0) {
194959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle          mustSignExtend = true;
195959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        }
196959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        done = true;
197959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      } else {
198959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        rawByte = readUnsignedByte();
199959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
200959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
201959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if (mustSignExtend) {
202959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Example:
203959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // say we shifted 7 bits, we need
204959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // to make all the upper 25 bits 1s.
205959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // load a 1...
206959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // 00000000 00000000 00000000 00000001
207959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // << 7
208959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // 00000000 00000000 00000000 10000000
209959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // - 1
210959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // 00000000 00000000 00000000 01111111
211959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // ~
212959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // 11111111 11111111 11111111 10000000
213959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      int upperOnes = ~((1 << shift) - 1);
214959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      value |= (upperOnes);
215959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
216959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    return value;
217959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
218959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
219959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
220959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * @param value A 32-bit number to be written to the file in SLEB128 form.
221959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
222959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public void writeSleb128(int value) throws IOException {
223959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if (value == 0) {
224959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      writeByte(0);
225959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      return;
226959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
227959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if (value > 0) {
228959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      writeUleb128(value);
229959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      return;
230959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
231959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if (value == -1) {
232959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      writeByte(0x7f);
233959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
234959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
235959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // When it's all 1s (0xffffffff), we're done!
236959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    while (value != 0xffffffff) {
237959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      int marker = 1;
238959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // If we're down to the last 7 bits (i.e., shifting a further 7 is all 1s),
239959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // the marker will be 0.
240959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      if ((value >> 7) == 0xffffffff) {
241959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle        marker = 0;
242959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      }
243959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      // Get the lowest 7 bits, add on the marker in the high bit.
244959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      int nextByte = value & 0x7f | (marker << 7);
245959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      writeByte(nextByte);
246959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      value >>= 7;
247959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
248959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
249959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
250959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
251959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * In DEX format, strings are in MUTF-8 format, the first ULEB128 value is the decoded size
252959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * (i.e., string.length), and then follows a null-terminated series of characters.
253959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * @param decodedSize The ULEB128 value that should have been read just before this.
254959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * @return The raw bytes of the string, not including the null character.
255959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
256959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public byte[] readDexUtf(int decodedSize) throws IOException {
257959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // In the dex MUTF-8, the encoded size can never be larger than 3 times
258959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // the actual string's length (which is the ULEB128 value just before this
259959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // string, the "decoded size")
260959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
261959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Therefore, allocate as much space as we might need.
262959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    byte[] str = new byte[decodedSize * 3];
263959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
264959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Get our first byte.
265959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    int encodedSize = 0;
266959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    byte rawByte = readByte();
267959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
268959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Keep reading until we find the end marker.
269959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    while (rawByte != 0) {
270959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      str[encodedSize++] = rawByte;
271959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      rawByte = readByte();
272959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
273959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
274959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Copy everything we read into str into the correctly-sized actual string.
275959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    byte[] actualString = new byte[encodedSize];
276959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    for (int i = 0; i < encodedSize; i++) {
277959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      actualString[i] = str[i];
278959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
279959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
280959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    return actualString;
281959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
282959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
283959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
284959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * Writes out raw bytes that would have been read by readDexUTF().
285959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * Will automatically write out the null-byte at the end.
286959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * @param data Bytes to be written out.
287959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
288959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public void writeDexUtf(byte[] data) throws IOException {
289959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    write(data);
290959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    // Remember to add the end marker.
291959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    writeByte(0);
292959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
293959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
294959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
295959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * Align the file handle's seek pointer to the next N bytes.
296959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * @param alignment N to align to.
297959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
298959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public void alignForwards(int alignment) throws IOException {
299959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    long offset = getFilePointer();
300959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    long mask = alignment - 1;
301959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if ((offset & mask) != 0) {
302959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      int extra = alignment - (int) (offset & mask);
303959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      seek(offset + extra);
304959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
305959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
306959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle
307959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  /**
308959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * Align the file handle's seek pointer backwards to the previous N bytes.
309959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   * @param alignment N to align to.
310959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle   */
311959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  public void alignBackwards(int alignment) throws IOException {
312959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    long offset = getFilePointer();
313959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    long mask = alignment - 1;
314959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    if ((offset & mask) != 0) {
315959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      offset &= (~mask);
316959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle      seek(offset);
317959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle    }
318959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle  }
319959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle}
320