package com.bytezone.diskbrowser.utilities; import java.math.BigDecimal; import java.math.MathContext; import java.util.GregorianCalendar; public class HexFormatter { private static String[] hex = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" }; private static MathContext mathContext = new MathContext (9); public static String format (byte[] buffer) { return format (buffer, 0, buffer.length); } public static String format (byte[] buffer, int offset, int length) { return format (buffer, offset, length, true, 0); } public static String format (byte[] buffer, int offset, int length, int startingAddress) { return format (buffer, offset, length, true, startingAddress); } public static String formatNoHeader (byte[] buffer, int offset, int length) { return format (buffer, offset, length, false, 0); } public static String formatNoHeader (byte[] buffer, int offset, int length, int startingAddress) { return format (buffer, offset, length, false, startingAddress); } public static String format (byte[] buffer, int offset, int length, boolean header, int startingAddress) { StringBuffer line = new StringBuffer (); int[] freq = new int[256]; boolean startedOnBoundary = offset % 0x100 == 0; if (header) { line.append (" "); for (int i = 0; i < 16; i++) line.append (" " + hex[i]); if (offset == 0) line.append ("\n"); } for (int i = offset; i < offset + length; i += 16) { if (line.length () > 0 && i > 0) line.append ("\n"); if (i > offset && startedOnBoundary && (i % 0x200) == 0) line.append ("\n"); // print offset for (int temp = i + startingAddress, max = 65536; max > 0; max /= 16) { if (temp >= max) { line.append (hex[temp / max]); temp %= max; } else line.append ("0"); } // print hex values line.append (" : "); StringBuffer trans = new StringBuffer (); StringBuffer hexLine = new StringBuffer (); for (int j = i; (j < i + 16) && (j < offset + length); j++) { int c = buffer[j] & 0xFF; freq[c]++; hexLine.append (String.format ("%02X ", c)); if (c > 127) { if (c < 160) c -= 64; else c -= 128; } if (c < 32 || c == 127) // non-printable trans.append ("."); else // standard ascii trans.append ((char) c); } while (hexLine.length () < 48) hexLine.append (" "); line.append (hexLine.toString () + ": " + trans.toString ()); } if (false) { line.append ("\n\n"); int totalBits = 0; for (int i = 0; i < freq.length; i++) if (freq[i] > 0) { totalBits += (Integer.bitCount (i) * freq[i]); line.append ( String.format ("%02X %3d %d%n", i, freq[i], Integer.bitCount (i))); } line.append (String.format ("%nTotal bits : %d%n", totalBits)); } return line.toString (); } public static String sanitiseString (byte[] buffer, int offset, int length) { StringBuilder trans = new StringBuilder (); for (int j = offset; j < offset + length; j++) { int c = buffer[j] & 0xFF; if (c > 127) { if (c < 160) c -= 64; else c -= 128; } if (c < 32 || c == 127) // non-printable trans.append ("."); else trans.append ((char) c); // standard ascii } return trans.toString (); } public static String getString (byte[] buffer) { return getString (buffer, 0, buffer.length); } public static String getString (byte[] buffer, int offset, int length) { StringBuffer text = new StringBuffer (); for (int i = offset; i < offset + length; i++) { int c = intValue (buffer[i]); if (c > 127) { if (c < 160) c -= 64; else c -= 128; } if (c == 13) text.append ("\n"); else if (c < 32) // non-printable text.append ("."); else // standard ascii text.append ((char) c); } return text.toString (); } public static String getString2 (byte[] buffer, int offset, int length) { StringBuffer text = new StringBuffer (); for (int i = offset; i < offset + length; i++) { int c = intValue (buffer[i]); if (c == 136 && text.length () > 0) { System.out.println (text.toString ()); text.deleteCharAt (text.length () - 1); System.out.println ("deleted"); continue; } if (c > 127) { if (c < 160) c -= 64; else c -= 128; } if (c < 32) // non-printable text.append ((char) (c + 64)); else // standard ascii text.append ((char) c); } return text.toString (); } public static String getHexString (byte[] buffer, int offset, int length) { return getHexString (buffer, offset, length, true); } public static String getHexString (byte[] buffer) { return getHexString (buffer, 0, buffer.length); } public static String getHexString (byte[] buffer, int offset, int length, boolean space) { StringBuilder hex = new StringBuilder (); for (int i = 0; i < length; i++) { hex.append (String.format ("%02X", buffer[offset + i])); if (space) hex.append (' '); } if (length > 0 && space) hex.deleteCharAt (hex.length () - 1); return hex.toString (); } public static String getHexStringReversed (byte[] buffer, int offset, int length, boolean space) { StringBuilder hex = new StringBuilder (); for (int i = length - 1; i >= 0; i--) { hex.append (String.format ("%02X", buffer[offset + i])); if (space) hex.append (' '); } if (length > 0 && space) hex.deleteCharAt (hex.length () - 1); return hex.toString (); } public static char byteValue (byte b) { int c = intValue (b); if (c > 127) c -= 128; if (c > 95) c -= 64; if (c < 32) // non-printable return '.'; return (char) c; // standard ascii } public static String format4 (int value) { if (value < 0) return "***err**"; StringBuffer text = new StringBuffer (); for (int i = 0, weight = 4096; i < 4; i++) { int digit = value / weight; if (digit < 0 || digit > 15) return "***err**"; text.append (hex[digit]); value %= weight; weight /= 16; } return text.toString (); } public static String format3 (int value) { return format4 (value).substring (1); } public static String format2 (int value) { if (value < 0) value += 256; String text = hex[value / 16] + hex[value % 16]; return text; } public static String format1 (int value) { String text = hex[value]; return text; } public static int intValue (byte b1) { // int i1 = b1; // if (i1 < 0) // i1 += 256; // return i1; return b1 & 0xFF; } public static int intValue (byte b1, byte b2) { return intValue (b1) + intValue (b2) * 256; } public static int intValue (byte b1, byte b2, byte b3) { return intValue (b1) + intValue (b2) * 256 + intValue (b3) * 65536; } public static int getLong (byte[] buffer, int ptr) { int val = 0; for (int i = 3; i >= 0; i--) { val <<= 8; val += buffer[ptr + i] & 0xFF; } return val; } public static int getLongBigEndian (byte[] buffer, int ptr) { int val = 0; for (int i = 0; i < 4; i++) { val <<= 8; val += buffer[ptr + i] & 0xFF; } return val; } public static int getShortBigEndian (byte[] buffer, int ptr) { int val = 0; for (int i = 0; i < 2; i++) { val <<= 8; val += buffer[ptr + i] & 0xFF; } return val; } public static double getSANEDouble (byte[] buffer, int offset) { long bits = 0; for (int i = 7; i >= 0; i--) { bits <<= 8; bits |= buffer[offset + i] & 0xFF; } return Double.longBitsToDouble (bits); } public static int getWord (byte[] buffer, int ptr) { int val = 0; for (int i = 1; i >= 0; i--) { val <<= 8; val += buffer[ptr + i] & 0xFF; } return val; } public static int getSignedWord (byte b1, byte b2) { return (b2 << 8) | (b1 & 0xFF); } // public static int getSignedWord (byte[] buffer, int ptr) // { // short val = buffer[ptr] << 8; // return buffer[ptr] * 256 + buffer[ptr + 1]; // } public static double floatValueOld (byte[] buffer, int offset) { double val = 0; int exponent = HexFormatter.intValue (buffer[offset]) - 0x80; int mantissa = (buffer[offset + 1] & 0x7F) * 0x1000000 + intValue (buffer[offset + 2]) * 0x10000 + intValue (buffer[offset + 3]) * 0x100 + intValue (buffer[offset + 4]); int weight1 = 1; long weight2 = 2147483648L; double multiplier = 0; for (int i = 0; i < 32; i++) { if ((mantissa & weight2) > 0) multiplier += (1.0 / weight1); weight2 /= 2; weight1 *= 2; } val = Math.pow (2, exponent - 1) * (multiplier + 1); return val; } public static double floatValue (byte[] buffer, int ptr) { int exponent = buffer[ptr] & 0x7F; // biased 128 if (exponent == 0) return 0.0; int mantissa = (buffer[ptr + 1] & 0x7F) << 24 | (buffer[ptr + 2] & 0xFF) << 16 | (buffer[ptr + 3] & 0xFF) << 8 | (buffer[ptr + 4] & 0xFF); boolean negative = (buffer[ptr + 1] & 0x80) > 0; double value = 0.5; for (int i = 2, weight = 0x40000000; i <= 32; i++, weight >>>= 1) if ((mantissa & weight) > 0) value += Math.pow (0.5, i); value *= Math.pow (2, exponent); BigDecimal bd = new BigDecimal (value); double rounded = bd.round (mathContext).doubleValue (); return negative ? rounded * -1 : rounded; } public static GregorianCalendar getAppleDate (byte[] buffer, int offset) { int date = HexFormatter.intValue (buffer[offset], buffer[offset + 1]); if (date > 0) { int year = (date & 0xFE00) >> 9; int month = (date & 0x01E0) >> 5; int day = date & 0x001F; int hour = HexFormatter.intValue (buffer[offset + 3]) & 0x1F; int minute = HexFormatter.intValue (buffer[offset + 2]) & 0x3F; if (year < 70) year += 2000; else year += 1900; return new GregorianCalendar (year, month - 1, day, hour, minute); } return null; } public static GregorianCalendar getPascalDate (byte[] buffer, int offset) { int year = intValue (buffer[offset + 1]); int day = (buffer[offset] & 0xF0) >> 4; int month = buffer[offset] & 0x0F; if (day == 0 || month == 0) return null; if (year % 2 > 0) day += 16; year /= 2; if (year < 70) year += 2000; else year += 1900; return new GregorianCalendar (year, month - 1, day); } public static String getPascalString (byte[] buffer, int offset) { int length = HexFormatter.intValue (buffer[offset]); return HexFormatter.getString (buffer, offset + 1, length); } }