/* Converter.java
*
* This class provides a set of static method for numeric conversion.
* (c) 2006 Salvatore Scellato
*
* This file is part of the EduMIPS64 project, and is released under the GNU
* General Public License.
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.edumips64.utils;
/** This class provides a set of static method for numeric conversion.
* NOTE: bit strings will be considered little-endian, that is to say that the right-most bit is the less significant one: this
* assumption is implicitely made by each method of this class.
* @author Salvatore Scellato
* */
public class Converter {
/** Converts a string of bits in the relative value.
* @param bits string of bits, must be composed obly by '0' and '1' chars, otherwise
* an exception will be thrown. If the bit string is coded into a signed representation a negative number will be produced
* if the leftmost bit is '1' and a positive number if it is '0'.
* @param unsignd if set to true the conversion will be unsigned, if set to false the binary representation will be considered
* of a signed value.
* @return int value of the bits representation (32 bit)
* @throws IrregularStringOfBitsException if the string of bits is not well-formed or the string of bits contains
* a value that cannot be stored into an <code>int</code> variable
*/
public static int binToInt(String bits, boolean unsignd) throws IrregularStringOfBitsException {
if (bits.length() > 32) {
throw new IrregularStringOfBitsException();
}
if (unsignd && bits.length() == 32 && bits.charAt(0) == '1') {
throw new IrregularStringOfBitsException();
}
//se la stringa di bits Ú lunga 32 bit
//ed Ú composta da uno 1 e 31 0
//allora la conversione si deve fare a mano
//perchÚ il numero da ritornare Ú -(2^32)
//e non si può utilizzare il valore positivo (2^32)
//con il tipo int :-(
if (!unsignd && bits.length() == 32 && bits.charAt(0) == '1') {
boolean overflow = true;
for (int i = 1; i < bits.length(); i++) {
if (bits.charAt(i) != '0') {
overflow = false;
break;
}
}
if (overflow) {
return (int)(-Math.pow(2.0, 32.0));
}
}
int value = 0;
if (unsignd) {
for (int j = bits.length() - 1, i = 0; j >= 0; j--, i++) {
if (bits.charAt(j) == '1') {
value += (int) Math.pow(2.0, (double) i);
} else if (bits.charAt(j) != '0') {
throw new IrregularStringOfBitsException();
}
}
return value;
} else {
if (bits.charAt(0) == '0') {
return Converter.binToInt(bits.substring(1), true);
} else if (bits.charAt(0) == '1') {
String s = Converter.twoComplement(bits);
return -1 * Converter.binToInt(s, true);
} else {
throw new IrregularStringOfBitsException();
}
}
}
/** Converts a string of bits in the relative value.
* @param bits string of bits, must be composed obly by '0' and '1' chars, otherwise
* an exception will be thrown. If the bit string is coded into a signed representation a negative number will be produced
* if the leftmost bit is '1' and a positive number if it is '0'.
* @param unsignd if set to true the conversion will be unsigned, if set to false the binary representation will be considered
* of a signed value.
* @return long value of the bits representation (64 bit)
* @throws IrregularStringOfBitsException if the string of bits is not well-formed or the string of bits contains
* a value that cannot be stored into a <code>long</code> variable
*/
public static long binToLong(String bits, boolean unsignd) throws IrregularStringOfBitsException {
if (bits.length() > 64) {
throw new IrregularStringOfBitsException();
}
if (unsignd && bits.length() == 64 && bits.charAt(0) == '1') {
throw new IrregularStringOfBitsException();
}
//se la stringa di bits Ú lunga 64 bit
//ed Ú composta da uno 1 e 63 0
//allora la conversione si deve fare a mano
//perchÚ il numero da ritornare Ú -(2^63)
//e non si può utilizzare il valore positivo (2^63)
//con il tipo long :-(
if (!unsignd && bits.length() == 64 && bits.charAt(0) == '1') {
boolean overflow = true;
for (int i = 1; i < bits.length(); i++) {
if (bits.charAt(i) != '0') {
overflow = false;
break;
}
}
if (overflow) {
return (long)(-Math.pow(2.0, 63.0));
}
}
long value = 0;
if (bits.length() == 0) {
return 0;
}
if (unsignd) {
for (int j = bits.length() - 1, i = 0; j >= 0; j--, i++) {
if (bits.charAt(j) == '1') {
value += (long) Math.pow(2.0, (double) i);
} else if (bits.charAt(j) != '0') {
throw new IrregularStringOfBitsException();
}
}
return value;
} else {
if (bits.charAt(0) == '0') {
return Converter.binToLong(bits.substring(1), true);
} else if (bits.charAt(0) == '1') {
String s = Converter.twoComplement(bits);
return -1 * Converter.binToLong(s, true);
} else {
throw new IrregularStringOfBitsException();
}
}
}
/** Converts an integer positive value in the relative string of bits.
* @param value positive integer to be converted into the relative string of bits: if it is negative,
* the opposite integer will be converted.
* @return string of bits representation of the number
*/
public static String positiveIntToBin(long value) {
StringBuffer buf = new StringBuffer();
long divide = (value < 0 ? -value : value);
int rem = 0;
while (divide > 0) {
rem = (int)(divide % 2);
if (rem == 1) {
buf.insert(0, '1');
} else {
buf.insert(0, '0');
}
divide = divide / 2;
}
return new String(buf);
}
/** Converts an integer positive value in the relative string of bits with length nbit, doing a zero-padding
* if the value string is shorter than nbit..
* @param nbit length of the resultant string of bits
* @param value positive integer to be converted into the relative string of bits: if it is negative,
* the opposite integer will be converted.
* @return string of bits representation of the number with length nbit
*/
public static String intToBin(int nbit, long value) {
String s = Converter.positiveIntToBin(value);
int num = nbit - s.length();
StringBuffer buf = new StringBuffer(s);
for (int i = 0; i < num; i++) {
buf.insert(0, '0');
}
if (value < 0) {
try {
String tmp = twoComplement(new String(buf));
return tmp;
} catch (IrregularStringOfBitsException e) {
return null;
}
} else {
return new String(buf);
}
}
/** Converts an integer positive value in the relative string of bits with length nbit, doing a zero-padding
* if the value string is shorter than nbit..
* @param nbit length of the resultant string of bits
* @param value positive integer to be converted into the relative string of bits: if it is negative,
* the opposite integer will be converted.
* @return string of bits representation of the number with length nbit
*/
public static String positiveIntToBin(int nbit, long value) {
String s = Converter.positiveIntToBin(value);
int num = nbit - s.length();
StringBuffer buf = new StringBuffer(s);
for (int i = 0; i < num; i++) {
buf.insert(0, '0');
}
return new String(buf);
}
/** Performs an two-complement operation on the string of bits: that is to say every bit is complemented and then 1 is added to
* the value. This method is used for coding and decoding negative integers.
* @param bits string of bits, must be composed obly by '0' and '1' chars, otherwise
* an exception will be thrown.
* @return string of bits with the result.
* @throws IrregularStringOfBitsException if the string of bits is not well-formed.
* */
public static String twoComplement(String bits) throws IrregularStringOfBitsException {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < bits.length(); i++) {
if (bits.charAt(i) == '1') {
buf.insert(i, '0');
} else if (bits.charAt(i) == '0') {
buf.insert(i, '1');
} else {
throw new IrregularStringOfBitsException();
}
}
boolean carry = false;
for (int i = buf.length() - 1; i >= 0; i--) {
if (buf.charAt(i) == '1') {
buf.setCharAt(i, '0');
carry = true;
} else if (buf.charAt(i) == '0') {
buf.setCharAt(i, '1');
carry = false;
}
if (!carry) {
break;
}
}
return new String(buf);
}
public static String twoComplementAndrea(String bits) {
boolean carry = true;
StringBuffer sbf = new StringBuffer(bits);
for (int i = bits.length() - 1; i >= 0; --i) {
if (carry) {
if (bits.charAt(i) == '0') {
sbf.setCharAt(i, '0');
} else {
sbf.setCharAt(i, '1');
carry = false;
}
} else {
if (bits.charAt(i) == '0') {
sbf.setCharAt(i, '1');
} else {
sbf.setCharAt(i, '0');
}
}
}
return sbf.toString();
}
/** Converts a string of bits in the relative hexadecimal representation of the same value.
* @param bits string of bits, must be composed obly by '0' and '1' chars, otherwise
* an exception will be thrown.
* @return string of hexadecimal digit [0-9,A-F], obtained by mapping every set of 4 bits
* into the correspondant hexadecimal digit.
* @throws IrregularStringOfBitsException if the string of bits is not well-formed.
*/
public static String binToHex(String bits) throws IrregularStringOfBitsException {
// if( Converter.binToLong(bits,false) == 0)
// return "0";
StringBuffer buf = new StringBuffer(bits);
StringBuffer ret = new StringBuffer();
int rem = bits.length() % 4;
if (rem != 0) { //padding
for (int i = rem; i < 4; i++) {
buf.insert(0, '0');
}
}
int exas = buf.length() / 4;
for (int i = 0; i < exas; i++) {
String token = buf.substring(4 * i, 4 * (i + 1));
int value = Converter.binToInt(token, true);
char toAppend = 'x';
switch (value) {
case 0:
toAppend = '0';
break;
case 1:
toAppend = '1';
break;
case 2:
toAppend = '2';
break;
case 3:
toAppend = '3';
break;
case 4:
toAppend = '4';
break;
case 5:
toAppend = '5';
break;
case 6:
toAppend = '6';
break;
case 7:
toAppend = '7';
break;
case 8:
toAppend = '8';
break;
case 9:
toAppend = '9';
break;
case 10:
toAppend = 'A';
break;
case 11:
toAppend = 'B';
break;
case 12:
toAppend = 'C';
break;
case 13:
toAppend = 'D';
break;
case 14:
toAppend = 'E';
break;
case 15:
toAppend = 'F';
break;
default:
throw new IrregularStringOfBitsException();
}
ret.append(toAppend);
}
return new String(ret);
}
/** Converts a string of hexadecimal in the relative Short value.
* @param hex string of hexadecimal, must start whith a 'x' or a 'X' and continue with only [0-9] or [A-F] (or [a-f]) chars, otherwise
* an IrregularStringOfHexException exception will be thrown.
* @return string of long digit [0-9].
* @throws IrregularStringOHexException if the string of hexadecimal is not well-formed.
*/
public static String hexToShort(String hex) throws IrregularStringOfHexException {
if (hex.charAt(0) != '0' || hex.toUpperCase().charAt(1) != 'X') {
throw new IrregularStringOfHexException();
}
short ret = 0;
int reversecont = hex.length() - 2;
for (int i = 2; i < hex.length(); i++) {
reversecont--;
char value = hex.toUpperCase().charAt(i);
switch (value) {
case '0':
ret += 0 * powLong(16, reversecont);
break;
case '1':
ret += 1 * powLong(16, reversecont);
break;
case '2':
ret += 2 * powLong(16, reversecont);
break;
case '3':
ret += 3 * powLong(16, reversecont);
break;
case '4':
ret += 4 * powLong(16, reversecont);
break;
case '5':
ret += 5 * powLong(16, reversecont);
break;
case '6':
ret += 6 * powLong(16, reversecont);
break;
case '7':
ret += 7 * powLong(16, reversecont);
break;
case '8':
ret += 8 * powLong(16, reversecont);
break;
case '9':
ret += 9 * powLong(16, reversecont);
break;
case 'A':
ret += 10 * powLong(16, reversecont);
break;
case 'B':
ret += 11 * powLong(16, reversecont);
break;
case 'C':
ret += 12 * powLong(16, reversecont);
break;
case 'D':
ret += 13 * powLong(16, reversecont);
break;
case 'E':
ret += 14 * powLong(16, reversecont);
break;
case 'F':
ret += 15 * powLong(16, reversecont);
break;
default:
throw new IrregularStringOfHexException();
}
}
return new String("" + ret);
}
/** Converts a string of hexadecimal in the relative long value.
* @param hex string of hexadecimal, must start whith a 'x' or a 'X' and continue with only [0-9] or [A-F] (or [a-f]) chars, otherwise
* an IrregularStringOfHexException exception will be thrown.
* @return string of long digit [0-9].
* @throws IrregularStringOHexException if the string of hexadecimal is not well-formed.
*/
public static String hexToLong(String hex) throws IrregularStringOfHexException {
if (hex.charAt(0) != '0' || hex.toUpperCase().charAt(1) != 'X') {
throw new IrregularStringOfHexException();
}
long ret = 0;
int reversecont = hex.length() - 2;
for (int i = 2; i < hex.length(); i++) {
reversecont--;
char value = hex.toUpperCase().charAt(i);
switch (value) {
case '0':
ret += 0 * powLong(16, reversecont);
break;
case '1':
ret += 1 * powLong(16, reversecont);
break;
case '2':
ret += 2 * powLong(16, reversecont);
break;
case '3':
ret += 3 * powLong(16, reversecont);
break;
case '4':
ret += 4 * powLong(16, reversecont);
break;
case '5':
ret += 5 * powLong(16, reversecont);
break;
case '6':
ret += 6 * powLong(16, reversecont);
break;
case '7':
ret += 7 * powLong(16, reversecont);
break;
case '8':
ret += 8 * powLong(16, reversecont);
break;
case '9':
ret += 9 * powLong(16, reversecont);
break;
case 'A':
ret += 10 * powLong(16, reversecont);
break;
case 'B':
ret += 11 * powLong(16, reversecont);
break;
case 'C':
ret += 12 * powLong(16, reversecont);
break;
case 'D':
ret += 13 * powLong(16, reversecont);
break;
case 'E':
ret += 14 * powLong(16, reversecont);
break;
case 'F':
ret += 15 * powLong(16, reversecont);
break;
default:
throw new IrregularStringOfHexException();
}
}
return new String("" + ret);
}
/** Converts a string of hexadecimal in the relative long value.
* @param hex string of hexadecimal, must start whith a 'x' or a 'X' and continue with only [0-9] or [A-F] (or [a-f]) chars, otherwise
* an IrregularStringOfHexException exception will be thrown.
* @return string of long digit [0-9].
* @throws IrregularStringOHexException if the string of hexadecimal is not well-formed.
*/
public static String hexToBin(String hex) throws IrregularStringOfHexException {
String ret = "";
for (int i = 0; i < hex.length(); i++) {
char value = hex.toUpperCase().charAt(i);
switch (value) {
case '0':
ret += "0000";
break;
case '1':
ret += "0001";
break;
case '2':
ret += "0010";
break;
case '3':
ret += "0011";
break;
case '4':
ret += "0100";
break;
case '5':
ret += "0101";
break;
case '6':
ret += "0110";
break;
case '7':
ret += "0111";
break;
case '8':
ret += "1000";
break;
case '9':
ret += "1001";
break;
case 'A':
ret += "1010";
break;
case 'B':
ret += "1011";
break;
case 'C':
ret += "1100";
break;
case 'D':
ret += "1101";
break;
case 'E':
ret += "1110";
break;
case 'F':
ret += "1111";
break;
default:
throw new IrregularStringOfHexException();
}
}
return ret;
}
public static long powLong(int base, long exp) {
long ret = 1;
for (int i = 1; i <= exp; i++) {
ret *= base;
}
return ret;
}
}