• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.writer;
33 
34 import org.jf.util.ExceptionWithContext;
35 
36 import javax.annotation.Nonnull;
37 import java.io.BufferedOutputStream;
38 import java.io.IOException;
39 import java.io.OutputStream;
40 
41 public class DexDataWriter extends BufferedOutputStream {
42     /**
43      * The position within the file that we will write to next. This is only updated when the buffer is flushed to the
44      * outputStream.
45      */
46     private int filePosition;
47 
48     /**
49      * A temporary buffer that can be used for larger writes. Can be replaced with a larger buffer if needed.
50      * Must be at least 8 bytes
51      */
52     private byte[] tempBuf = new byte[8];
53 
54     /** A buffer of 0s to use for writing alignment values */
55     private byte[] zeroBuf = new byte[3];
56 
57     /**
58      * Construct a new DexWriter instance that writes to output.
59      *
60      * @param output An OutputStream to write the data to.
61      * @param filePosition The position within the file that OutputStream will write to.
62      */
DexDataWriter(@onnull OutputStream output, int filePosition)63     public DexDataWriter(@Nonnull OutputStream output, int filePosition) {
64         this(output, filePosition, 256 * 1024);
65     }
66 
DexDataWriter(@onnull OutputStream output, int filePosition, int bufferSize)67     public DexDataWriter(@Nonnull OutputStream output, int filePosition, int bufferSize) {
68         super(output, bufferSize);
69 
70         this.filePosition = filePosition;
71     }
72 
73     @Override
write(int b)74     public void write(int b) throws IOException {
75         filePosition++;
76         super.write(b);
77     }
78 
79     @Override
write(byte[] b)80     public void write(byte[] b) throws IOException {
81         write(b, 0, b.length);
82     }
83 
84     @Override
write(byte[] b, int off, int len)85     public void write(byte[] b, int off, int len) throws IOException {
86         filePosition += len;
87         super.write(b, off, len);
88     }
89 
writeLong(long value)90     public void writeLong(long value) throws IOException {
91         writeInt((int)value);
92         writeInt((int)(value >> 32));
93     }
94 
writeInt(OutputStream out, int value)95     public static void writeInt(OutputStream out, int value) throws IOException {
96         out.write(value);
97         out.write(value >> 8);
98         out.write(value >> 16);
99         out.write(value >> 24);
100     }
101 
writeInt(int value)102     public void writeInt(int value) throws IOException {
103         writeInt(this, value);
104     }
105 
writeShort(int value)106     public void writeShort(int value) throws IOException {
107         if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
108             throw new ExceptionWithContext("Short value out of range: %d", value);
109         }
110         write(value);
111         write(value >> 8);
112     }
113 
writeUshort(int value)114     public void writeUshort(int value) throws IOException {
115         if (value < 0 || value > 0xFFFF) {
116             throw new ExceptionWithContext("Unsigned short value out of range: %d", value);
117         }
118         write(value);
119         write(value >> 8);
120     }
121 
writeUbyte(int value)122     public void writeUbyte(int value) throws IOException {
123         if (value < 0 || value > 0xFF) {
124             throw new ExceptionWithContext("Unsigned byte value out of range: %d", value);
125         }
126         write(value);
127     }
128 
writeUleb128(OutputStream out, int value)129     public static void writeUleb128(OutputStream out, int value) throws IOException {
130         while ((value & 0xffffffffL) > 0x7f) {
131             out.write((value & 0x7f) | 0x80);
132             value >>>= 7;
133         }
134         out.write(value);
135     }
136 
writeUleb128(int value)137     public void writeUleb128(int value) throws IOException {
138         writeUleb128(this, value);
139     }
140 
writeSleb128(OutputStream out, int value)141     public static void writeSleb128(OutputStream out, int value) throws IOException {
142         if (value >= 0) {
143             while (value > 0x3f) {
144                 out.write((value & 0x7f) | 0x80);
145                 value >>>= 7;
146             }
147             out.write(value & 0x7f);
148         } else {
149             while (value < -0x40) {
150                 out.write((value & 0x7f) | 0x80);
151                 value >>= 7;
152             }
153             out.write(value & 0x7f);
154         }
155     }
156 
writeSleb128(int value)157     public void writeSleb128(int value) throws IOException {
158         writeSleb128(this, value);
159     }
160 
writeEncodedValueHeader(int valueType, int valueArg)161     public void writeEncodedValueHeader(int valueType, int valueArg) throws IOException {
162         write(valueType | (valueArg << 5));
163     }
164 
writeEncodedInt(int valueType, int value)165     public void writeEncodedInt(int valueType, int value) throws IOException {
166         int index = 0;
167         if (value >= 0) {
168             while (value > 0x7f) {
169                 tempBuf[index++] = (byte)value;
170                 value >>= 8;
171             }
172         } else {
173             while (value < -0x80) {
174                 tempBuf[index++] = (byte)value;
175                 value >>= 8;
176             }
177         }
178         tempBuf[index++] = (byte)value;
179         writeEncodedValueHeader(valueType, index-1);
180         write(tempBuf, 0, index);
181     }
182 
writeEncodedLong(int valueType, long value)183     public void writeEncodedLong(int valueType, long value) throws IOException {
184         int index = 0;
185         if (value >= 0) {
186             while (value > 0x7f) {
187                 tempBuf[index++] = (byte)value;
188                 value >>= 8;
189             }
190         } else {
191             while (value < -0x80) {
192                 tempBuf[index++] = (byte)value;
193                 value >>= 8;
194             }
195         }
196         tempBuf[index++] = (byte)value;
197         writeEncodedValueHeader(valueType, index-1);
198         write(tempBuf, 0, index);
199     }
200 
writeEncodedUint(int valueType, int value)201     public void writeEncodedUint(int valueType, int value) throws IOException {
202         int index = 0;
203         do {
204             tempBuf[index++] = (byte)value;
205             value >>>= 8;
206         } while (value != 0);
207         writeEncodedValueHeader(valueType, index-1);
208         write(tempBuf, 0, index);
209     }
210 
writeEncodedFloat(int valueType, float value)211     public void writeEncodedFloat(int valueType, float value) throws IOException {
212         writeRightZeroExtendedInt(valueType, Float.floatToRawIntBits(value));
213     }
214 
writeRightZeroExtendedInt(int valueType, int value)215     protected void writeRightZeroExtendedInt(int valueType, int value) throws IOException {
216         int index = 3;
217         do {
218             tempBuf[index--] = (byte)((value & 0xFF000000) >>> 24);
219             value <<= 8;
220         } while (value != 0);
221 
222         int firstElement = index+1;
223         int encodedLength = 4-firstElement;
224         writeEncodedValueHeader(valueType, encodedLength - 1);
225         write(tempBuf, firstElement, encodedLength);
226     }
227 
writeEncodedDouble(int valueType, double value)228     public void writeEncodedDouble(int valueType, double value) throws IOException {
229         writeRightZeroExtendedLong(valueType, Double.doubleToRawLongBits(value));
230     }
231 
writeRightZeroExtendedLong(int valueType, long value)232     protected void writeRightZeroExtendedLong(int valueType, long value) throws IOException {
233         int index = 7;
234         do {
235             tempBuf[index--] = (byte)((value & 0xFF00000000000000L) >>> 56);
236             value <<= 8;
237         } while (value != 0);
238 
239         int firstElement = index+1;
240         int encodedLength = 8-firstElement;
241         writeEncodedValueHeader(valueType, encodedLength - 1);
242         write(tempBuf, firstElement, encodedLength);
243     }
244 
writeString(String string)245     public void writeString(String string) throws IOException {
246         int len = string.length();
247 
248         // make sure we have enough room in the temporary buffer
249         if (tempBuf.length <= string.length()*3) {
250             tempBuf = new byte[string.length()*3];
251         }
252 
253         final byte[] buf = tempBuf;
254 
255         int bufPos = 0;
256         for (int i = 0; i < len; i++) {
257             char c = string.charAt(i);
258             if ((c != 0) && (c < 0x80)) {
259                 buf[bufPos++] = (byte)c;
260             } else if (c < 0x800) {
261                 buf[bufPos++] = (byte)(((c >> 6) & 0x1f) | 0xc0);
262                 buf[bufPos++] = (byte)((c & 0x3f) | 0x80);
263             } else {
264                 buf[bufPos++] = (byte)(((c >> 12) & 0x0f) | 0xe0);
265                 buf[bufPos++] = (byte)(((c >> 6) & 0x3f) | 0x80);
266                 buf[bufPos++] = (byte)((c & 0x3f) | 0x80);
267             }
268         }
269         write(buf, 0, bufPos);
270     }
271 
align()272     public void align() throws IOException {
273         int zeros = (-getPosition()) & 3;
274         if (zeros > 0) {
275             write(zeroBuf, 0, zeros);
276         }
277     }
278 
getPosition()279     public int getPosition() {
280         return filePosition;
281     }
282 }
283