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 converted to it's unsigned value. This works * for bytes, shorts, and ints, as the value is returned as a long * * @author Jesse Peterson <jesse@jpeterson.com> * * @version 1.0 */ public class Unsigned extends Object { /** * Return the unsigned value of the number. * * @param number * a byte value * @return the unsigned value */ public static long unsigned(byte number) { long result = 0; BinaryFormat format = new BinaryFormat(); String binary = format.format(number); StringBuffer buffer = new StringBuffer(binary); buffer.reverse(); int length = buffer.length(); for (int i = 0; i < length; i++) { result += (buffer.charAt(i) == '1') ? 1 << i : 0; } return (result); } /** * Return the unsigned value of the number. * * @param number * a short value * @return the unsigned value */ public static long unsigned(short number) { long result = 0; BinaryFormat format = new BinaryFormat(); String binary = format.format(number); StringBuffer buffer = new StringBuffer(binary); buffer.reverse(); int length = buffer.length(); for (int i = 0; i < length; i++) { result += (buffer.charAt(i) == '1') ? 1 << i : 0; } return (result); } /** * Return the unsigned value of the number. * * @param number * an int value * @return the unsigned value */ public static long unsigned(int number) { long result = 0; BinaryFormat format = new BinaryFormat(); String binary = format.format(number); StringBuffer buffer = new StringBuffer(binary); buffer.reverse(); int length = buffer.length(); for (int i = 0; i < length; i++) { result += (buffer.charAt(i) == '1') ? 1 << i : 0; } return (result); } // ///////////// // self test // // ///////////// public static void main(String[] args) { long expected, result; byte aByte = (byte) 0xff; expected = 255; result = Unsigned.unsigned(aByte); if (result == expected) { System.out.print("Success => "); } else { System.out.print("FAILURE => "); } System.out.println("expected: " + expected + " | result: " + result); aByte = (byte) 0x80; expected = 128; result = Unsigned.unsigned(aByte); if (result == expected) { System.out.print("Success => "); } else { System.out.print("FAILURE => "); } System.out.println("expected: " + expected + " | result: " + result); short aShort = (short) 0xffff; expected = 65535; result = Unsigned.unsigned(aShort); if (result == expected) { System.out.print("Success => "); } else { System.out.print("FAILURE => "); } System.out.println("expected: " + expected + " | result: " + result); } } /** * This class allows a number to be easily formatted as a binary number. The * representation uses 1's and 0's. * * @author Jesse Peterson <jesse@jpeterson.com> * * @version 1.0 */ class BinaryFormat extends Format { /** * spacer between a digit */ private String divider; /** * Create a new BinaryFormat object with no divider. * * @since 1.0 */ public BinaryFormat() { divider = ""; } /** * Format an object in a binary 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 binary 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 binary number. * * @param number * the byte 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 a byte, returning an 8 bit binary number. * * @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) { String prefix = ""; prefix = ""; for (int i = 8; i-- > 0;) { toAppendTo.append(prefix); toAppendTo.append(((number & (1 << i)) != 0) ? 1 : 0); prefix = divider; } return (toAppendTo); } /** * Format an array of bytes, returning 8 bits 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. 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) { String prefix = ""; prefix = ""; for (int i = 0; i < number.length; i++) { toAppendTo.append(prefix); format(number[i], toAppendTo, pos); prefix = divider; } return (toAppendTo); } /** * Format a short value, returning a 16 bit binary number. * * @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 binary number. * * @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 binary number. * * @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 binary number. * * @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 binary number. * * @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 binary number. * * @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 binary number into a Number object. If up to 8 bits are parsed, * returns a Byte. If more than 8 and up to 16 bits are parsed, return a * Short. If more than 16 and up to 32 bits are parsed, return an Integer. * If more than 32 and up to 64 bits 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 BinaryFormat", parsePosition.getIndex()); } return (result); } /** * Parse a binary number into a Number object. If up to 8 bits are parsed, * returns a Byte. If more than 8 and up to 16 bits are parsed, return a * Short. If more than 16 and up to 32 bits are parsed, return an Integer. * If more than 32 and up to 64 bits are parsed, return a Long. * * @param text * a binary 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, bits; // 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; } } parsePosition.setIndex(iter.getIndex()); startIndex = parsePosition.getIndex(); Number result = (Number) parseObject(text, parsePosition); if (result == null) { return (result); } bits = parsePosition.getIndex() - startIndex; if (bits <= 8) { result = new Byte(result.byteValue()); } else if (bits <= 16) { result = new Short(result.shortValue()); } else if (bits <= 32) { result = new Integer(result.intValue()); } else if (bits <= 64) { result = new Long(result.longValue()); } return (result); } /** * Parse a binary number, skipping leading whitespace. Does not throw an * exception; if no object can be parsed, index is unchanged! * * @param source * the string to parse * @param status * the string index to start at * @return The binary number as a Long object. * * @since 1.0 */ public Object parseObject(String source, ParsePosition status) { int start = status.getIndex(); boolean success = false; boolean skipWhitespace = true; StringBuffer buffer = new StringBuffer(); StringCharacterIterator iter = new StringCharacterIterator(source, start); for (char c = iter.current(); c != CharacterIterator.DONE; c = iter.next()) { if (skipWhitespace && Character.isWhitespace(c)) { // skip whitespace continue; } skipWhitespace = false; if ((c == '1') || (c == '0')) { success = true; buffer.append(c); } else { break; } } if (!success) { return (null); } // convert binary to long if (buffer.length() > 64) { // larger than a long, error return (null); } long result = 0; buffer.reverse(); int length = buffer.length(); for (int i = 0; i < length; i++) { result += (buffer.charAt(i) == '1') ? 1 << i : 0; } status.setIndex(iter.getIndex()); return (new Long(result)); } /** * Set the string used to seperate bits. Is useful some times to insert a * space between bits for readability. * * @param divider * String to insert between bits * * @since 1.0 */ public void setDivider(String divider) { this.divider = divider; } /** * Get the string used to seperate bits. * * @return the string used to seperate bits * * @since 1.0 */ public String getDivider() { return (divider); } // ///////////// // self test // // ///////////// public static void main(String[] args) { String result; BinaryFormat format = new BinaryFormat(); format.setDivider(" "); // byte byte bNumber = 0x33; result = format.format(bNumber); if (result.equals("0 0 1 1 0 0 1 1")) { System.out.print("Success => "); } else { System.out.print("FAILURE => "); } System.out.println("Byte: " + bNumber + " (" + result + ")"); // byte bNumber = (byte) 0x85; result = format.format(bNumber); if (result.equals("1 0 0 0 0 1 0 1")) { System.out.print("Success => "); } else { System.out.print("FAILURE => "); } System.out.println("Byte: " + bNumber + " (" + result + ")"); // short short sNumber = (short) 0xa2b6; result = format.format(sNumber); if (result.equals("1 0 1 0 0 0 1 0 1 0 1 1 0 1 1 0")) { System.out.print("Success => "); } else { System.out.print("FAILURE => "); } System.out.println("Byte: " + sNumber + " (" + result + ")"); // int format.setDivider(""); int iNumber = (int) 0x4321fedc; result = format.format(iNumber); if (result.equals("01000011001000011111111011011100")) { System.out.print("Success => "); } else { System.out.print("FAILURE => "); } System.out.println("Byte: " + iNumber + " (" + result + ")"); // long format.setDivider(""); long lNumber = (long) 0x4321fedc4321fedcL; result = format.format(lNumber); if (result.equals("0100001100100001111111101101110001000011001000011111111011011100")) { System.out.print("Success => "); } else { System.out.print("FAILURE => "); } System.out.println("Byte: " + lNumber + " (" + result + ")"); } }