Java tutorial
/* * Copyright (C) 1999 Jesse E. Peterson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * */ //package com.jpeterson.util; import java.text.CharacterIterator; import java.text.FieldPosition; import java.text.Format; import java.text.ParseException; import java.text.ParsePosition; import java.text.StringCharacterIterator; /** * This class allows a number to be easily formatted as a hexadecimal number. * The representation uses 0-f. * * @author Jesse Peterson <jesse@jpeterson.com> * * @version 1.0 */ public class HexFormat extends Format { /** * should upper case letters be used */ private boolean upperCase; private String hexDigits = "0123456789abcdefABCDEF"; /** * Create a new HexFormat object. By default the lower case letters 'a'-'f' * are used. * * @since 1.0 */ public HexFormat() { upperCase = false; } /** * Format an object in a hexadecimal representation. The object * <CODE>number</CODE> must be an integer Number; Byte, Short, Integer, or * Long. If the parameter <CODE>number</CODE> is not one of these, this * method will throw a <CODE>IllegalArgumentException</CODE>. * * @param number * the number to format * @param toAppendTo * where the text is to be appended * @param pos * not used * @return the formatted hex number * * @since 1.0 */ public StringBuffer format(Object number, StringBuffer toAppendTo, FieldPosition pos) { if (number instanceof Byte) { format(((Number) number).byteValue(), toAppendTo, pos); } else if (number instanceof Short) { format(((Number) number).shortValue(), toAppendTo, pos); } else if (number instanceof Integer) { format(((Number) number).intValue(), toAppendTo, pos); } else if (number instanceof Long) { format(((Number) number).longValue(), toAppendTo, pos); } else { throw new IllegalArgumentException("Cannot format given Object as a Byte, Short, Integer, or Long"); } return (toAppendTo); } /** * Format a byte, returning an 8 bit hex number. (2 digits, with leading * zeros) * * @param number * the byte to format * @return the formatted hex number * * @since 1.0 */ public final String format(byte number) { return (format(number, new StringBuffer(), new FieldPosition(0)).toString()); } /** * Format a byte, returning an 8 bit hex number. (2 digits, with leading * zeros) * * @param number * the number to format * @param toAppendTo * where the text is to be appended * @param pos * not used * @return the formatted binary number */ public StringBuffer format(byte number, StringBuffer toAppendTo, FieldPosition pos) { int hiNibble, loNibble; String hiDigit, loDigit; hiNibble = (number >>> 4) & 0x0f; loNibble = number & 0x0f; hiDigit = Integer.toHexString(hiNibble); loDigit = Integer.toHexString(loNibble); if (upperCase) { hiDigit = hiDigit.toUpperCase(); loDigit = loDigit.toUpperCase(); } else { hiDigit = hiDigit.toLowerCase(); loDigit = loDigit.toLowerCase(); } toAppendTo.append(hiDigit).append(loDigit); return (toAppendTo); } /** * Format an array of bytes, returning 8 bits per byte. (2 digits with * leading zeros, per byte) The byte at index zero is the most significant * byte, making it possible to enter a stream of bytes received from a * serial connection very easily. * * @param number * the bytes to format * @return the formatted binary number * * @since 1.0 */ public final String format(byte[] number) { return (format(number, new StringBuffer(), new FieldPosition(0)).toString()); } /** * Format an array of bytes, returning 8 bits per bytes. (2 digits with * leading zeros, per byte) The byte at index zero is the most significant * byte, making it possible to enter a stream of bytes received from a * serial connection very easily. * * @param number * the number to format * @param toAppendTo * where the text is to be appended * @param pos * not used * @return the formatted binary number * * @since 1.0 */ public StringBuffer format(byte[] number, StringBuffer toAppendTo, FieldPosition pos) { for (int i = 0; i < number.length; i++) { format(number[i], toAppendTo, pos); } return (toAppendTo); } /** * Format a short value, returning a 16 bit hexadecimal number. (4 digits * with leading zeros) * * @param number * the short to format * @return the formatted binary number * * @since 1.0 */ public String format(short number) { return (format(number, new StringBuffer(), new FieldPosition(0)).toString()); } /** * Format a short value, returning a 16 bit hexadecimal number. (4 digits * with leading zeros) * * @param number * the number to format * @param toAppendTo * where the text is to be appended * @param pos * not used * @return the formatted binary number * * @since 1.0 */ public StringBuffer format(short number, StringBuffer toAppendTo, FieldPosition pos) { byte[] array = new byte[2]; array[0] = (byte) ((number >>> 8) & 0xff); array[1] = (byte) (number & 0xff); return (format(array, toAppendTo, pos)); } /** * Format an int value, returning a 32 bit hexadecimal number. (8 digits * with leading zeros) * * @param number * the int to format * @return the formatted binary number * * @since 1.0 */ public String format(int number) { return (format(number, new StringBuffer(), new FieldPosition(0)).toString()); } /** * Format an int value, returning a 32 bit hexadecimal number. (8 digits * with leading zeros) * * @param number * the number to format * @param toAppendTo * where the text is to be appended * @param pos * not used * @return the formatted binary number * * @since 1.0 */ public StringBuffer format(int number, StringBuffer toAppendTo, FieldPosition pos) { byte[] array = new byte[4]; array[0] = (byte) ((number >>> 24) & 0xff); array[1] = (byte) ((number >>> 16) & 0xff); array[2] = (byte) ((number >>> 8) & 0xff); array[3] = (byte) (number & 0xff); return (format(array, toAppendTo, pos)); } /** * Format a long value, returning a 64 bit hexadecimal number. (16 digits * with leading zeros) * * @param number * the long to format * @return the formatted binary number * * @since 1.0 */ public String format(long number) { return (format(number, new StringBuffer(), new FieldPosition(0)).toString()); } /** * Format a long value, returning a 64 bit hexadecimal number. (16 digits * with leading zeros) * * @param number * the number to format * @param toAppendTo * where the text is to be appended * @param pos * not used * @return the formatted binary number * * @since 1.0 */ public StringBuffer format(long number, StringBuffer toAppendTo, FieldPosition pos) { byte[] array = new byte[8]; array[0] = (byte) ((number >>> 56) & 0xff); array[1] = (byte) ((number >>> 48) & 0xff); array[2] = (byte) ((number >>> 40) & 0xff); array[3] = (byte) ((number >>> 32) & 0xff); array[4] = (byte) ((number >>> 24) & 0xff); array[5] = (byte) ((number >>> 16) & 0xff); array[6] = (byte) ((number >>> 8) & 0xff); array[7] = (byte) (number & 0xff); return (format(array, toAppendTo, pos)); } /** * Parse a hex number into a Number object. Hexadecimal numbers may be * indicated with a leading character designation of '0x'. If up to 1 byte * is parsed, returns a Byte. If more than 1 and up to 2 bytes are parsed, * return a Short. If more than 2 and up to 4 bytes are parsed, return an * Integer. If more than 4 and up to 8 bytes are parsed, return a Long. * * @param source * a binary number * @return return an integer form of Number object if parse is successful * @exception ParseException * thrown if source is cannot be converted to a Byte, Short, * Int, or Long. * * @since 1.0 */ public Number parse(String source) throws ParseException { int startIndex = 0; Number result; ParsePosition parsePosition = new ParsePosition(startIndex); result = parse(source, parsePosition); if (result == null) { throw new ParseException("Unable to parse " + source + " using HexFormat", parsePosition.getIndex()); } return (result); } /** * Parse a hex number into a Number object. Hexadecimal numbers may be * indicated with a leading character designation of '0x'. If up to 1 byte * is parsed, returns a Byte. If more than 1 and up to 2 bytes are parsed, * return a Short. If more than 2 and up to 4 bytes are parsed, return an * Integer. If more than 4 and up to 8 bytes are parsed, return a Long. * * @param text * a hexadecimal number * @param parsePosition * position to start parsing from * @return return an integer form of Number object if parse is successful; * <CODE>null</CODE> otherwise * * @since 1.0 */ public Number parse(String text, ParsePosition parsePosition) { boolean skipWhitespace = true; int startIndex, nibbles; // remove whitespace StringCharacterIterator iter = new StringCharacterIterator(text, parsePosition.getIndex()); for (char c = iter.current(); c != CharacterIterator.DONE; c = iter.next()) { if (skipWhitespace && Character.isWhitespace(c)) { // skip whitespace continue; } break; } // skip a leading hex designation of the characters '0x' if (text.regionMatches(iter.getIndex(), "0x", 0, 2)) { parsePosition.setIndex(iter.getIndex() + 2); } else { parsePosition.setIndex(iter.getIndex()); } startIndex = parsePosition.getIndex(); Number result = (Number) parseObject(text, parsePosition); if (result == null) { return (result); } nibbles = parsePosition.getIndex() - startIndex; if (nibbles <= 2) { result = new Byte(result.byteValue()); } else if (nibbles <= 4) { result = new Short(result.shortValue()); } else if (nibbles <= 8) { result = new Integer(result.intValue()); } else if (nibbles <= 16) { result = new Long(result.longValue()); } return (result); } /** * Parse a hexadecimal number, skipping leading whitespace. Does not throw * an exception; if no object can be parsed, index is unchanged! Hexadecimal * numbers may be indicated with a leading character designation of '0x'. * * @param source * the string to parse * @param status * the string index to start at * @return The hexadecimal number as a Long object. * * @since 1.0 */ public Object parseObject(String source, ParsePosition status) { int start = status.getIndex(); boolean success = false; StringBuffer buffer = new StringBuffer(); char c, c2; long result; StringCharacterIterator iter = new StringCharacterIterator(source, start); for (c = iter.current(); c != CharacterIterator.DONE; c = iter.next()) { if (Character.isWhitespace(c)) { // skip whitespace continue; } break; } if (c == CharacterIterator.DONE) { return (null); } if (c == '0') { c2 = iter.next(); if (c2 == CharacterIterator.DONE) { return (null); } if (c2 == 'x') { // has a leading '0x' designation, so skip over it } else { // replace the two characters iter.previous(); iter.previous(); } } else { // skip back one character iter.previous(); } // gather valid hex digits for (c = iter.next(); c != CharacterIterator.DONE; c = iter.next()) { if (hexDigits.indexOf(c) != -1) { success = true; buffer.append(c); } else { break; } } if (!success) { // no valid hex digits return (null); } // convert hex to long if (buffer.length() > 16) { // larger than a long, error // with a buffer full of nibbles, the maximum nibbles in a // 64 bit number is 16 nibbles return (null); } // parse number try { result = Long.parseLong(buffer.toString(), 16); } catch (NumberFormatException e) { // unable to parse number return (null); } status.setIndex(iter.getIndex()); return (new Long(result)); } /** * Set upper case mode for alpha characters. * * @param upperCase * true if upper case alpha characters should be used; false * otherwise * * @since 1.0 */ public void setUpperCase(boolean upperCase) { this.upperCase = upperCase; } /** * Get upper case mode for alpha characters. * * @return true if upper case alpha characters should be used; false * otherwise * * @since 1.0 */ public boolean getUpperCase() { return (upperCase); } /** * Is upper case mode for alpha characters in affect? * * @return true if upper case alpha characters should be used; false * otherwise * * @since 1.0 */ public boolean isUpperCase() { return (getUpperCase()); } /** * Is lower case mode for alpha characters in affect? * * @return true if lower case alpha characters should be used; false * otherwise * * @since 1.0 */ public boolean isLowerCase() { return (!getUpperCase()); } // ///////////// // self test // // ///////////// public static void main(String[] args) { String result; HexFormat format = new HexFormat(); // byte byte bNumber = 0x33; result = format.format(bNumber); if (result.equals("33")) { System.out.print("Success => "); } else { System.out.print("FAILURE => "); } System.out.println("Byte: " + bNumber + " (0x" + result + ")"); bNumber = (byte) 0x85; result = format.format(bNumber); if (result.equals("85")) { System.out.print("Success => "); } else { System.out.print("FAILURE => "); } System.out.println("Byte: " + bNumber + " (0x" + result + ")"); bNumber = (byte) 0x0f; result = format.format(bNumber); if (result.equals("0f")) { System.out.print("Success => "); } else { System.out.print("FAILURE => "); } System.out.println("Byte: " + bNumber + " (0x" + result + ")"); short sNumber = (short) 0xa2b6; result = format.format(sNumber); if (result.equals("a2b6")) { System.out.print("Success => "); } else { System.out.print("FAILURE => "); } System.out.println("Byte: " + bNumber + " (0x" + result + ")"); format.setUpperCase(true); int iNumber = (int) 0x4321fedc; result = format.format(iNumber); if (result.equals("4321FEDC")) { System.out.print("Success => "); } else { System.out.print("FAILURE => "); } System.out.println("Byte: " + bNumber + " (0x" + result + ")"); long lNumber = (long) 0x4321fedc4321fedcL; result = format.format(lNumber); if (result.equals("4321FEDC4321FEDC")) { System.out.print("Success => "); } else { System.out.print("FAILURE => "); } System.out.println("Byte: " + bNumber + " (0x" + result + ")"); String num = "0xfe"; Number number = null; Byte bExpect = new Byte((byte) 0xfe); try { number = format.parse(num); } catch (ParseException e) { System.out.println(e); e.printStackTrace(); } if ((number instanceof Byte) && (number.equals(bExpect))) { System.out.print("Success => "); } else { System.out.print("FAILURE => "); } System.out.println("Byte: " + bExpect + " result: " + number); num = "0xf"; number = null; bExpect = new Byte((byte) 0xf); try { number = format.parse(num); } catch (ParseException e) { System.out.println(e); e.printStackTrace(); } if ((number instanceof Byte) && (number.equals(bExpect))) { System.out.print("Success => "); } else { System.out.print("FAILURE => "); } System.out.println("Byte: " + bExpect + " result: " + number); num = "0xf0f0"; number = null; Short sExpect = new Short((short) 0xf0f0); try { number = format.parse(num); } catch (ParseException e) { System.out.println(e); e.printStackTrace(); } if ((number instanceof Short) && (number.equals(sExpect))) { System.out.print("Success => "); } else { System.out.print("FAILURE => "); } System.out.println("Short: " + sExpect + " result: " + number); num = "0xdEAdbEEf"; number = null; Integer iExpect = new Integer((int) 0xdEAdbEEf); try { number = format.parse(num); } catch (ParseException e) { System.out.println(e); e.printStackTrace(); } if ((number instanceof Integer) && (number.equals(iExpect))) { System.out.print("Success => "); } else { System.out.print("FAILURE => "); } System.out.println("Integer: " + iExpect + " result: " + number); } }