Home | History | Annotate | Download | only in smali
      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