1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/* 2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Copyright (C) 2007 The Android Open Source Project 3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License"); 5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * you may not use this file except in compliance with the License. 6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * You may obtain a copy of the License at 7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * http://www.apache.org/licenses/LICENSE-2.0 9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Unless required by applicable law or agreed to in writing, software 11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS, 12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * See the License for the specific language governing permissions and 14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * limitations under the License. 15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 17579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpackage com.android.dx.util; 18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 19579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/** 20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Utilities for parsing hexadecimal text. 21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpublic final class HexParser { 23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** 24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * This class is uninstantiable. 25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson private HexParser() { 27579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson // This space intentionally left blank. 28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** 31579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Parses the given text as hex, returning a {@code byte[]} 32579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * corresponding to the text. The format is simple: Each line may 33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * start with a hex offset followed by a colon (which is verified 34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * and presumably used just as a comment), and then consists of 35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * hex digits freely interspersed with whitespace. If a pound sign 36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * is encountered, it and the rest of the line are ignored as a 37579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * comment. If a double quote is encountered, then the ASCII value 38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * of the subsequent characters is used, until the next double 39579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * quote. Quoted strings may not span multiple lines. 40579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 41579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @param src {@code non-null;} the source string 42579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @return {@code non-null;} the parsed form 43579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 44579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public static byte[] parse(String src) { 45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int len = src.length(); 46579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson byte[] result = new byte[len / 2]; 47579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int at = 0; 48579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int outAt = 0; 49579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 50579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson while (at < len) { 51579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int nlAt = src.indexOf('\n', at); 52579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (nlAt < 0) { 53579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson nlAt = len; 54579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 55579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int poundAt = src.indexOf('#', at); 56579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson String line; 58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if ((poundAt >= 0) && (poundAt < nlAt)) { 59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson line = src.substring(at, poundAt); 60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } else { 61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson line = src.substring(at, nlAt); 62579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 63579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson at = nlAt + 1; 64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int colonAt = line.indexOf(':'); 66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 67579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson atCheck: 68579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (colonAt != -1) { 69579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int quoteAt = line.indexOf('\"'); 70579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if ((quoteAt != -1) && (quoteAt < colonAt)) { 71579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson break atCheck; 72579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 73579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 74579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson String atStr = line.substring(0, colonAt).trim(); 75579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson line = line.substring(colonAt + 1); 76579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int alleged = Integer.parseInt(atStr, 16); 77579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (alleged != outAt) { 78579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new RuntimeException("bogus offset marker: " + 79579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson atStr); 80579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 81579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 83579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int lineLen = line.length(); 84579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int value = -1; 85579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson boolean quoteMode = false; 86579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 87579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson for (int i = 0; i < lineLen; i++) { 88579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson char c = line.charAt(i); 89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (quoteMode) { 91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (c == '\"') { 92579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson quoteMode = false; 93579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } else { 94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson result[outAt] = (byte) c; 95579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson outAt++; 96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson continue; 98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (c <= ' ') { 101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson continue; 102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (c == '\"') { 104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (value != -1) { 105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new RuntimeException("spare digit around " + 106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson "offset " + Hex.u4(outAt)); 107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson quoteMode = true; 109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson continue; 110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int digVal = Character.digit(c, 16); 113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (digVal == -1) { 114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new RuntimeException("bogus digit character: \"" + 115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson c + "\""); 116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (value == -1) { 118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson value = digVal; 119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } else { 120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson result[outAt] = (byte) ((value << 4) | digVal); 121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson outAt++; 122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson value = -1; 123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (value != -1) { 127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new RuntimeException("spare digit around offset " + 128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson Hex.u4(outAt)); 129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (quoteMode) { 132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new RuntimeException("unterminated quote around " + 133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson "offset " + Hex.u4(outAt)); 134579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (outAt < result.length) { 138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson byte[] newr = new byte[outAt]; 139579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson System.arraycopy(result, 0, newr, 0, outAt); 140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson result = newr; 141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return result; 144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson} 146