xref: /aosp_15_r20/external/google-smali/third_party/smali/src/main/java/com/android/tools/smali/smali/LiteralTools.java (revision 37f5703ca959d1ce24046e7595880d209e15c133)
1 /*
2  * [The "BSD licence"]
3  * Copyright (c) 2010 Ben Gruver (JesusFreke)
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 package com.android.tools.smali.smali;
29 
30 import java.util.regex.Matcher;
31 import java.util.regex.Pattern;
32 
33 public class LiteralTools
34 {
parseByte(String byteLiteral)35     public static byte parseByte(String byteLiteral)
36             throws NumberFormatException {
37         if (byteLiteral == null) {
38             throw new NumberFormatException("string is null");
39         }
40         if (byteLiteral.length() == 0) {
41             throw new NumberFormatException("string is blank");
42         }
43 
44         char[] byteChars;
45         if (byteLiteral.toUpperCase().endsWith("T")) {
46             byteChars = byteLiteral.substring(0, byteLiteral.length()-1).toCharArray();
47         } else {
48             byteChars = byteLiteral.toCharArray();
49         }
50 
51         int position = 0;
52         int radix = 10;
53         boolean negative = false;
54         if (byteChars[position] == '-') {
55             position++;
56             negative = true;
57         }
58 
59         if (byteChars[position] == '0') {
60             position++;
61             if (position == byteChars.length) {
62                 return 0;
63             } else if (byteChars[position] == 'x' || byteChars[position] == 'X') {
64                 radix = 16;
65                 position++;
66             } else if (Character.digit(byteChars[position], 8) >= 0) {
67                 radix = 8;
68             }
69         }
70 
71         byte result = 0;
72         byte shiftedResult;
73         int digit;
74         byte maxValue = (byte)(Byte.MAX_VALUE / (radix / 2));
75 
76         while (position < byteChars.length) {
77             digit = Character.digit(byteChars[position], radix);
78             if (digit < 0) {
79                 throw new NumberFormatException("The string contains invalid an digit - '" + byteChars[position] + "'");
80             }
81             shiftedResult = (byte)(result * radix);
82             if (result > maxValue) {
83                 throw new NumberFormatException(byteLiteral + " cannot fit into a byte");
84             }
85             if (shiftedResult < 0 && shiftedResult >= -digit) {
86                 throw new NumberFormatException(byteLiteral + " cannot fit into a byte");
87             }
88             result = (byte)(shiftedResult + digit);
89             position++;
90         }
91 
92         if (negative) {
93             //allow -0x80, which is = 0x80
94             if (result == Byte.MIN_VALUE) {
95                 return result;
96             } else if (result < 0) {
97                 throw new NumberFormatException(byteLiteral + " cannot fit into a byte");
98             }
99             return (byte)(result * -1);
100         } else {
101             return result;
102         }
103     }
104 
parseShort(String shortLiteral)105     public static short parseShort(String shortLiteral)
106             throws NumberFormatException {
107         if (shortLiteral == null) {
108             throw new NumberFormatException("string is null");
109         }
110         if (shortLiteral.length() == 0) {
111             throw new NumberFormatException("string is blank");
112         }
113 
114         char[] shortChars;
115         if (shortLiteral.toUpperCase().endsWith("S")) {
116             shortChars = shortLiteral.substring(0, shortLiteral.length()-1).toCharArray();
117         } else {
118             shortChars = shortLiteral.toCharArray();
119         }
120 
121         int position = 0;
122         int radix = 10;
123         boolean negative = false;
124         if (shortChars[position] == '-') {
125             position++;
126             negative = true;
127         }
128 
129         if (shortChars[position] == '0') {
130             position++;
131             if (position == shortChars.length) {
132                 return 0;
133             } else if (shortChars[position] == 'x' || shortChars[position] == 'X') {
134                 radix = 16;
135                 position++;
136             } else if (Character.digit(shortChars[position], 8) >= 0) {
137                 radix = 8;
138             }
139         }
140 
141         short result = 0;
142         short shiftedResult;
143         int digit;
144         short maxValue = (short)(Short.MAX_VALUE / (radix / 2));
145 
146         while (position < shortChars.length) {
147             digit = Character.digit(shortChars[position], radix);
148             if (digit < 0) {
149                 throw new NumberFormatException("The string contains invalid an digit - '" + shortChars[position] + "'");
150             }
151             shiftedResult = (short)(result * radix);
152             if (result > maxValue) {
153                 throw new NumberFormatException(shortLiteral + " cannot fit into a short");
154             }
155             if (shiftedResult < 0 && shiftedResult >= -digit) {
156                 throw new NumberFormatException(shortLiteral + " cannot fit into a short");
157             }
158             result = (short)(shiftedResult + digit);
159             position++;
160         }
161 
162         if (negative) {
163             //allow -0x8000, which is = 0x8000
164             if (result == Short.MIN_VALUE) {
165                 return result;
166             } else if (result < 0) {
167                 throw new NumberFormatException(shortLiteral + " cannot fit into a short");
168             }
169             return (short)(result * -1);
170         } else {
171             return result;
172         }
173     }
174 
parseInt(String intLiteral)175     public static int parseInt(String intLiteral)
176             throws NumberFormatException {
177         if (intLiteral == null) {
178             throw new NumberFormatException("string is null");
179         }
180         if (intLiteral.length() == 0) {
181             throw new NumberFormatException("string is blank");
182         }
183 
184         char[] intChars = intLiteral.toCharArray();
185         int position = 0;
186         int radix = 10;
187         boolean negative = false;
188         if (intChars[position] == '-') {
189             position++;
190             negative = true;
191         }
192 
193         if (intChars[position] == '0') {
194             position++;
195             if (position == intChars.length) {
196                 return 0;
197             } else if (intChars[position] == 'x' || intChars[position] == 'X') {
198                 radix = 16;
199                 position++;
200             } else if (Character.digit(intChars[position], 8) >= 0) {
201                 radix = 8;
202             }
203         }
204 
205         int result = 0;
206         int shiftedResult;
207         int digit;
208         int maxValue = Integer.MAX_VALUE / (radix / 2);
209 
210         while (position < intChars.length) {
211             digit = Character.digit(intChars[position], radix);
212             if (digit < 0) {
213                 throw new NumberFormatException("The string contains an invalid digit - '" + intChars[position] + "'");
214             }
215             shiftedResult = result * radix;
216             if (result > maxValue) {
217                 throw new NumberFormatException(intLiteral + " cannot fit into an int");
218             }
219             if (shiftedResult < 0 && shiftedResult >= -digit) {
220                 throw new NumberFormatException(intLiteral + " cannot fit into an int");
221             }
222             result = shiftedResult + digit;
223             position++;
224         }
225 
226         if (negative) {
227             //allow -0x80000000, which is = 0x80000000
228             if (result == Integer.MIN_VALUE) {
229                 return result;
230             } else if (result < 0) {
231                 throw new NumberFormatException(intLiteral + " cannot fit into an int");
232             }
233             return result * -1;
234         } else {
235             return result;
236         }
237     }
238 
parseLong(String longLiteral)239     public static long parseLong(String longLiteral)
240             throws NumberFormatException {
241         if (longLiteral == null) {
242             throw new NumberFormatException("string is null");
243         }
244         if (longLiteral.length() == 0) {
245             throw new NumberFormatException("string is blank");
246         }
247 
248         char[] longChars;
249         if (longLiteral.toUpperCase().endsWith("L")) {
250             longChars = longLiteral.substring(0, longLiteral.length()-1).toCharArray();
251         } else {
252             longChars = longLiteral.toCharArray();
253         }
254 
255         int position = 0;
256         int radix = 10;
257         boolean negative = false;
258         if (longChars[position] == '-') {
259             position++;
260             negative = true;
261         }
262 
263         if (longChars[position] == '0') {
264             position++;
265             if (position == longChars.length) {
266                 return 0;
267             } else if (longChars[position] == 'x' || longChars[position] == 'X') {
268                 radix = 16;
269                 position++;
270             } else if (Character.digit(longChars[position], 8) >= 0) {
271                 radix = 8;
272             }
273         }
274 
275         long result = 0;
276         long shiftedResult;
277         int digit;
278         long maxValue = Long.MAX_VALUE / (radix / 2);
279 
280         while (position < longChars.length) {
281             digit = Character.digit(longChars[position], radix);
282             if (digit < 0) {
283                 throw new NumberFormatException("The string contains an invalid digit - '" + longChars[position] + "'");
284             }
285             shiftedResult = result * radix;
286             if (result > maxValue) {
287                 throw new NumberFormatException(longLiteral + " cannot fit into a long");
288             }
289             if (shiftedResult < 0 && shiftedResult >= -digit) {
290                 throw new NumberFormatException(longLiteral + " cannot fit into a long");
291             }
292             result = shiftedResult + digit;
293             position++;
294         }
295 
296         if (negative) {
297             //allow -0x8000000000000000, which is = 0x8000000000000000
298             if (result == Long.MIN_VALUE) {
299                 return result;
300             } else if (result < 0) {
301                 throw new NumberFormatException(longLiteral + " cannot fit into a long");
302             }
303             return result * -1;
304         } else {
305             return result;
306         }
307     }
308 
309     private static Pattern specialFloatRegex = Pattern.compile("((-)?infinityf)|(nanf)", Pattern.CASE_INSENSITIVE);
parseFloat(String floatString)310     public static float parseFloat(String floatString) {
311         Matcher m = specialFloatRegex.matcher(floatString);
312         if (m.matches()) {
313             //got an infinity
314             if (m.start(1) != -1) {
315                 if (m.start(2) != -1) {
316                     return Float.NEGATIVE_INFINITY;
317                 } else {
318                     return Float.POSITIVE_INFINITY;
319                 }
320             } else {
321                 return Float.NaN;
322             }
323         }
324         return Float.parseFloat(floatString);
325     }
326 
327     private static Pattern specialDoubleRegex = Pattern.compile("((-)?infinityd?)|(nand?)", Pattern.CASE_INSENSITIVE);
parseDouble(String doubleString)328     public static double parseDouble(String doubleString) {
329         Matcher m = specialDoubleRegex.matcher(doubleString);
330         if (m.matches()) {
331             //got an infinity
332             if (m.start(1) != -1) {
333                 if (m.start(2) != -1) {
334                     return Double.NEGATIVE_INFINITY;
335                 } else {
336                     return Double.POSITIVE_INFINITY;
337                 }
338             } else {
339                 return Double.NaN;
340             }
341         }
342         return Double.parseDouble(doubleString);
343     }
344 
longToBytes(long value)345     public static byte[] longToBytes(long value) {
346         byte[] bytes = new byte[8];
347 
348         for (int i=0; value != 0; i++) {
349             bytes[i] = (byte)value;
350             value = value >>> 8;
351         }
352         return bytes;
353     }
354 
intToBytes(int value)355     public static byte[] intToBytes(int value) {
356         byte[] bytes = new byte[4];
357 
358         for (int i=0; value != 0; i++) {
359             bytes[i] = (byte)value;
360             value = value >>> 8;
361         }
362         return bytes;
363     }
364 
shortToBytes(short value)365     public static byte[] shortToBytes(short value) {
366         byte[] bytes = new byte[2];
367 
368         bytes[0] = (byte)value;
369         bytes[1] = (byte)(value >>> 8);
370         return bytes;
371     }
372 
floatToBytes(float value)373     public static byte[] floatToBytes(float value) {
374         return intToBytes(Float.floatToRawIntBits(value));
375     }
376 
doubleToBytes(double value)377     public static byte[] doubleToBytes(double value) {
378         return longToBytes(Double.doubleToRawLongBits(value));
379     }
380 
charToBytes(char value)381     public static byte[] charToBytes(char value) {
382         return shortToBytes((short)value);
383     }
384 
boolToBytes(boolean value)385     public static byte[] boolToBytes(boolean value) {
386         if (value) {
387             return new byte[] { 0x01 };
388         } else {
389             return new byte[] { 0x00 };
390         }
391     }
392 
checkInt(long value)393     public static void checkInt(long value) {
394         if (value > 0xFFFFFFFF || value < -0x80000000) {
395             throw new NumberFormatException(Long.toString(value) + " cannot fit into an int");
396         }
397     }
398 
checkShort(long value)399     public static void checkShort(long value) {
400         if (value > 0xFFFF | value < -0x8000) {
401             throw new NumberFormatException(Long.toString(value) + " cannot fit into a short");
402         }
403     }
404 
checkByte(long value)405     public static void checkByte(long value) {
406         if (value > 0xFF | value < -0x80) {
407             throw new NumberFormatException(Long.toString(value) + " cannot fit into a byte");
408         }
409     }
410 
checkNibble(long value)411     public static void checkNibble(long value) {
412         if (value > 0x0F | value < -0x08) {
413             throw new NumberFormatException(Long.toString(value) + " cannot fit into a nibble");
414         }
415     }
416 }
417