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