Data Type Java

/*
 * 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 
 * 
 * @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 
 * 
 * @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
   * number must be an integer Number; Byte, Short, Integer, or
   * Long. If the parameter number is not one of these, this
   * method will throw a IllegalArgumentException.
   * 
   * @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;
   *         null 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 + ")");
  }
}