/* *------------------- * The BinaryDisplayConverter.java is part of ASH Viewer *------------------- * * ASH Viewer is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ASH Viewer is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ASH Viewer. If not, see <http://www.gnu.org/licenses/>. * * Copyright (c) 2009, Alex Kardapolov, All rights reserved. * */ package org.ash.util; public class BinaryDisplayConverter { // Use Hexidecimal representation public static final int HEX = 16; //Use decimal representation. public static final int DECIMAL = 10; //Use Octal representation. public static final int OCTAL = 8; //Use Binary representation. public static final int BINARY = 2; static ConversionConstants hex = new ConversionConstants(2, 16); static ConversionConstants decimal = new ConversionConstants(3, 10); private static ConversionConstants octal = new ConversionConstants(3, 8); private static ConversionConstants binary = new ConversionConstants(8, 2); //Conversion Constants static class ConversionConstants { int width; // number of chars used to represent byte int radix; // the base radix ConversionConstants(int w, int r) { width = w; radix = r; } } //List of characters considered "printable". private static String printable = "0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?"; /** * Do not allow any instances to be created. */ private BinaryDisplayConverter() {} /** * Convert from an array of Bytes into a string. */ public static String convertToString(Byte[] data, int base, boolean showAscii) { // handle null if (data == null) return null; StringBuffer buf = new StringBuffer(); ConversionConstants convConst = getConstants(base); // Convert each byte and put into string buffer for (int i=0; i < data.length; i++) { int value = data[i].byteValue(); String s = null; // if user wants to see ASCII chars as characters, // see if this is one that should be displayed that way if (showAscii) { if (printable.indexOf((char)value) > -1) { s = Character.valueOf((char)value) + " ".substring(10-(convConst.width - 1)); } } // if use is not looking for ASCII chars, or if this one is one that // is not printable, then convert it into numeric form if (s == null) { switch (base) { case DECIMAL: // convert signed to unsigned if (value < 0) value = 256 + value; s = Integer.toString(value); break; case OCTAL: s = Integer.toOctalString(value); break; case BINARY: s = Integer.toBinaryString(value); break; case HEX: // fall through to default default: s = Integer.toHexString(value); } // some formats (e.g. hex & octal) extend a negative number to multiple places // (e.g. FC becomes FFFC), so chop off extra stuff in front if (s.length() > convConst.width) s = s.substring(s.length() - convConst.width); // front pad with zeros and add to output if (s.length() < convConst.width) buf.append("00000000".substring(8-(convConst.width - s.length()))); } buf.append(s); buf.append(""); // always add spaces at end for consistancy } return buf.toString(); } /** * Convert a string into Bytes. The string is assumed to be in * the form generated by the convertToString function, with each * byte's data space separated from each other byte's. */ public static Byte[] convertToBytes(String data, int base, boolean showAscii) throws NumberFormatException { ConversionConstants convConst = getConstants(base); if (data == null) return null; if (data.length() == 0) return new Byte[0]; if (data.equals("<null>")) return null; int stringIndex = 0; int byteIndex = 0; Byte[] bytes = new Byte[(data.length()+2)/(convConst.width+2)]; while (stringIndex < data.length()) { // get the text to be converted String s = data.substring(stringIndex, stringIndex+convConst.width); // handle ASCII chars // Irrespective of the radix, the second byte will always // be a space when the data is displayed as a single ASCII character. if (showAscii && s.charAt(1) == ' ') { // convert the char into its numeric value bytes[byteIndex++] = Byte.valueOf((byte)s.charAt(0)); } else { // The following ugly conversion from text to Byte is necessary because // the Byte class is inconsistant. When asked to output as Hex, it does // so as an UNSIGNED byte, but when asked to read back the same thing // using the Hex radix, it insists that the input must be SIGNED. // To get around this, we up-size the conversion to Integer, then // truncate that to a byte, and finally convert the byte to a Byte. Yech. bytes[byteIndex++] = Byte.valueOf( (byte)(Integer.valueOf(s, convConst.radix)).intValue()); } stringIndex += convConst.width + 2; } return bytes; } /** * Get the constants to use for the given base. */ private static ConversionConstants getConstants(int base) { if (base == HEX) return hex; if (base == DECIMAL) return decimal; if (base == OCTAL) return octal; if (base == BINARY) return binary; return hex; // default to hex if unknown base passed in } }