Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.dx.util;
     18 
     19 /**
     20  * Utilities for parsing hexadecimal text.
     21  */
     22 public final class HexParser {
     23     /**
     24      * This class is uninstantiable.
     25      */
     26     private HexParser() {
     27         // This space intentionally left blank.
     28     }
     29 
     30     /**
     31      * Parses the given text as hex, returning a {@code byte[]}
     32      * corresponding to the text. The format is simple: Each line may
     33      * start with a hex offset followed by a colon (which is verified
     34      * and presumably used just as a comment), and then consists of
     35      * hex digits freely interspersed with whitespace. If a pound sign
     36      * is encountered, it and the rest of the line are ignored as a
     37      * comment. If a double quote is encountered, then the ASCII value
     38      * of the subsequent characters is used, until the next double
     39      * quote. Quoted strings may not span multiple lines.
     40      *
     41      * @param src {@code non-null;} the source string
     42      * @return {@code non-null;} the parsed form
     43      */
     44     public static byte[] parse(String src) {
     45         int len = src.length();
     46         byte[] result = new byte[len / 2];
     47         int at = 0;
     48         int outAt = 0;
     49 
     50         while (at < len) {
     51             int nlAt = src.indexOf('\n', at);
     52             if (nlAt < 0) {
     53                 nlAt = len;
     54             }
     55             int poundAt = src.indexOf('#', at);
     56 
     57             String line;
     58             if ((poundAt >= 0) && (poundAt < nlAt)) {
     59                 line = src.substring(at, poundAt);
     60             } else {
     61                 line = src.substring(at, nlAt);
     62             }
     63             at = nlAt + 1;
     64 
     65             int colonAt = line.indexOf(':');
     66 
     67             atCheck:
     68             if (colonAt != -1) {
     69                 int quoteAt = line.indexOf('\"');
     70                 if ((quoteAt != -1) && (quoteAt < colonAt)) {
     71                     break atCheck;
     72                 }
     73 
     74                 String atStr = line.substring(0, colonAt).trim();
     75                 line = line.substring(colonAt + 1);
     76                 int alleged = Integer.parseInt(atStr, 16);
     77                 if (alleged != outAt) {
     78                     throw new RuntimeException("bogus offset marker: " +
     79                                                atStr);
     80                 }
     81             }
     82 
     83             int lineLen = line.length();
     84             int value = -1;
     85             boolean quoteMode = false;
     86 
     87             for (int i = 0; i < lineLen; i++) {
     88                 char c = line.charAt(i);
     89 
     90                 if (quoteMode) {
     91                     if (c == '\"') {
     92                         quoteMode = false;
     93                     } else {
     94                         result[outAt] = (byte) c;
     95                         outAt++;
     96                     }
     97                     continue;
     98                 }
     99 
    100                 if (c <= ' ') {
    101                     continue;
    102                 }
    103                 if (c == '\"') {
    104                     if (value != -1) {
    105                         throw new RuntimeException("spare digit around " +
    106                                                    "offset " + Hex.u4(outAt));
    107                     }
    108                     quoteMode = true;
    109                     continue;
    110                 }
    111 
    112                 int digVal = Character.digit(c, 16);
    113                 if (digVal == -1) {
    114                     throw new RuntimeException("bogus digit character: \"" +
    115                                                c + "\"");
    116                 }
    117                 if (value == -1) {
    118                     value = digVal;
    119                 } else {
    120                     result[outAt] = (byte) ((value << 4) | digVal);
    121                     outAt++;
    122                     value = -1;
    123                 }
    124             }
    125 
    126             if (value != -1) {
    127                 throw new RuntimeException("spare digit around offset " +
    128                                            Hex.u4(outAt));
    129             }
    130 
    131             if (quoteMode) {
    132                 throw new RuntimeException("unterminated quote around " +
    133                                            "offset " + Hex.u4(outAt));
    134             }
    135         }
    136 
    137         if (outAt < result.length) {
    138             byte[] newr = new byte[outAt];
    139             System.arraycopy(result, 0, newr, 0, outAt);
    140             result = newr;
    141         }
    142 
    143         return result;
    144     }
    145 }
    146