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