src.com.ibm.as400.util.commtrace.BitBuf Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jt400-jdk8 Show documentation
Show all versions of jt400-jdk8 Show documentation
The Open Source version of the IBM Toolbox for Java
///////////////////////////////////////////////////////////////////////////////
//
// JTOpen (IBM Toolbox for Java - OSS version)
//
// Filename: BitBuf.java
//
// The source code contained herein is licensed under the IBM Public License
// Version 1.0, which has been approved by the Open Source Initiative.
// Copyright (C) 2002 International Business Machines Corporation and
// others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
package com.ibm.as400.util.commtrace;
import java.io.StringWriter;
/**
* The BitBuf class is an abstraction for an arbitrarily long string of bits.
* Its methods allow bit shifting, substring extraction, converting substrings
* to bytes, shorts, longs, or floats, and representing a bit string as a
* sequence of binary or hexadecimal digits.
* A new BitBuf can be constructed from another BitBuf or from a byte array.
*/
class BitBuf implements Cloneable {
private byte data[];
private int bitlen; // used if not a byte-boundary;
private static StringBuffer binbyte = new StringBuffer("01234567");
private static StringBuffer hexbyte = new StringBuffer("FF");
private final int masks[] = { 128, 64, 32, 16, 8, 4, 2, 1 };
private final char hexchars[] =
{
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'A',
'B',
'C',
'D',
'E',
'F' };
/**
* Constructs a BitBuf from a byte array.
* @param bytes The byte array.
*/
public BitBuf(byte[] bytes) {
data = (byte[]) bytes.clone();
bitlen = data.length * 8;
}
/**
* Constructor for making a BitBuf from an integer array.
* Note that only the lowest 8 bits of each integer are
* used. This is useful for code such as
*
* int ary[] = {0x01, 0xFF, 0x5E};
* BitBuf b = new BitBuf(ary);
*
* which would be bulkier if a byte array were used instead
* because of the need for implicit type casting of each
* element of array.
* @param ints The integer array
*/
public BitBuf(int[] ints) {
data = new byte[ints.length];
for (int i = 0; i < ints.length; i++)
data[i] = (byte) ints[i];
bitlen = data.length * 8;
}
/**
* Constructs an BitBuf of length 8 from a single byte.
* @param b The byte
*/
public BitBuf(byte b) {
data = new byte[1];
data[0] = b;
bitlen = data.length * 8;
}
/**
* Constructs a zero-filled BitBuf of length i*8.
* @param i The length of the BitBuf.
*/
public BitBuf(int i) {
data = new byte[i];
bitlen = data.length * 8;
}
/**
* Constructs a BitBuf from a substring of another BitBuf.
* @param b The BitBuf to copy bytes from.
* @param bitstart The bit to start copying at.
* @param bitlength the number of bits to copy.
*/
public BitBuf(BitBuf b, int bitstart, int bitlength) {
if (bitlength < 0)
bitlength = 0;
bitlen = bitlength;
int newlen = (bitlength + 7) / 8;
data = new byte[newlen];
for (int x = 0; x < newlen; x++)
data[x] = b.getOctet(bitstart + 8 * x);
truncate();
}
/**
* Returns a string of binary digits representing the 8 bits starting at bit i.
* @param i the bit to start the binary string at.
* @return String
*/
public String byteAsBin(int i) {
int x;
for (x = 7; x >= 0; x--)
binbyte.setCharAt(x, ((data[i] & 0xFF & masks[x]) > 0) ? '1' : '0');
return binbyte.toString();
}
/**
* Returns a string of hex digits representing the 8 bits starting at bit i.
* @param i the bit to start the hex string at.
* @return String
*/
public String byteAsHex(int i) {
hexbyte.setCharAt(0, hexchars[data[i] >>> 4 & 0xF]);
hexbyte.setCharAt(1, hexchars[data[i] & 0xF]);
return hexbyte.toString();
}
/**
* Returns a clone of a BitBuf casted as an Object.
* @return Object a clone of this BitBuf.
*/
public Object clone() {
BitBuf b = new BitBuf(data);
return b;
}
/**
* Returns a boolean representing one bit (at offset bit) of the BitBuf.
* @param bit the offset bit to return a boolean of.
* @return true is on, false if off
*/
public boolean getBitAsBool(int bit) {
int byteloc = bit / 8;
int bitloc = bit % 8;
if ((data[byteloc] & 0xFF & masks[bitloc]) > 0)
return true;
else
return false;
}
/**
* Returns a byte representing one bit (at offset bit) of the BitBuf.
* @param bit the offset bit.
* @return the byte at this offset.
*/
public byte getBitAsByte(int bit) {
int byteloc = bit / 8;
int bitloc = bit % 8;
if ((data[byteloc] & 0xFF & masks[bitloc]) > 0)
return (byte) 1;
else
return (byte) 0;
}
/**
* Returns the length of the BitBuf in bits.
* @return Th Length of this BitBuf in bits.
*/
public int getBitSize() {
return bitlen;
}
/**
* Returns a clone of the byte array used to store the data in a BitBuf.
* @return byte[] clone of the data in this BitBuf.
*/
public byte[] getBytes() {
return (byte[]) data.clone();
}
/**
* Returns the length of the BitBuf in bytes. For example, a BitBuf
* with a bit length of 3 would have a byte length of 1.
* @return length of this BitBuf in bytes
*/
public int getByteSize() {
return data.length;
}
/**
* Returns a byte consisting of the 8 bits in the BitBuf starting at startbit.
* @param startbit bit to start the byte at
* @return byte
*/
public byte getOctet(int startbit) {
// Gets 8 bits starting at the bit location bitloc
byte b;
if ((startbit >= bitlen) || (startbit < -8))
b = 0;
else
if (startbit < 0)
b = (byte) ((data[0] & 0xFF) >>> (0 - startbit));
else {
int byteloc = startbit / 8;
int bitshift = startbit % 8;
b = data[byteloc];
b <<= bitshift;
if ((bitshift > 0) && (startbit + 8 < bitlen))
b |= (data[byteloc + 1] & 0xFF) >>> (8 - bitshift);
}
return b;
}
/**
* Shifts the BitBuf left by x bits, shifting zeros in on the right.
* @param x length to shift to the left
*/
public void shiftLeft(int x) {
shiftBufferLeft(x);
}
/**
* Shifts the BitBuf right by x bits, shifting zeros in on the left.
* Slack bits remain zero (meaning that 11101 shifted right by 2 is 00111,
* even though internally the pattern would be stored using 8 bytes)
* @param x length to shift to the right
*/
public void shiftRight(int x) {
shiftBufferRight(x);
truncate();
}
/**
* Efficient left-shifting of entire buffer.
* First, byte-resolution shifting is done in one pass,
* then bit-resolution in one more pass through the buffer.
* @param d length to shift left
*/
public void shiftBufferLeft(int d) {
int byteshift = d / 8;
int bitshift = d % 8;
if (byteshift > 0)
for (int i = 0; i < data.length; i++)
if (i < (data.length - byteshift))
data[i] = data[i + byteshift];
else
data[i] = 0;
if (bitshift > 0)
for (int i = 0; i < data.length; i++)
if (i < (data.length - 1))
data[i] =
(byte) ((data[i] << bitshift) | ((data[i + 1] & 0xFF) >>> (8 - bitshift)));
else
data[i] <<= bitshift;
}
/**
* Efficient right-shifting of entire buffer.
* First, byte-resolution shifting is done in one pass,
* then bit-resolution in one more pass through the buffer.
* @param d length to shift right
*/
public void shiftBufferRight(int d) {
int byteshift = d / 8;
int bitshift = d % 8;
if (byteshift > 0)
for (int i = data.length; i-- > 0;)
if (i >= byteshift)
data[i] = data[i - byteshift];
else
data[i] = 0;
if (bitshift > 0)
for (int i = data.length; i-- > 0;)
if (i > 0)
data[i] =
(byte) (((data[i] & 0xFF) >>> bitshift) | (data[i - 1] << (8 - bitshift)));
else
data[i] = (byte) ((data[i] & 0xFF) >>> bitshift);
}
/**
* Returns a new BitBuf consisting of all bits from offset s and beyond.
* @param s offset at which to slice
* @return The new BitBuf containing the subset of data
*/
public BitBuf slice(int s) {
return new BitBuf(this, s, this.bitlen - s);
}
/**
* Returns a new BitBuf consisting of l bits starting with offset s.
* @param s offset at which to slice
* @param l how may bits to slice
* @return The new BitBuf containing the subset of data
*/
public BitBuf slice(int s, int l) {
return new BitBuf(this, s, l);
}
/**
* Returns a binary string representing the BitBuf, no spacing
* @return String
*/
public String toBinString() {
return toBinString(0, "");
}
/**
* Returns a binary string representing the BitBuf. The separator
* string is inserted into the result after every groupsize bytes.
* @param groupsize
* @param separator
* @return String
*/
public String toBinString(int groupsize, String separator) {
StringWriter out = new StringWriter();
for (int x = 0; x < data.length; x++) {
out.write(byteAsBin(x));
if ((groupsize != 0) && (x % groupsize == 0))
out.write(separator);
}
return out.toString();
}
/**
* Returns a binary string representing the bit buf. Every 8 bits
* is separated by the string sep.
* @param sep
* @return String
*/
public String toBinString(String sep) {
return toBinString(1, sep);
}
/**
* Returns the rightmost 8 bits of the BitBuf as a byte.
* @return byte
*/
public byte toByte() {
return getOctet(bitlen - 8);
}
/**
* Returns a hex string representing the BitBuf, no spacing.
* @return String
*/
public String toHexString() {
return toHexString(0, "");
}
/**
* Returns a hex string representing the BitBuf. The separator
* string is inserted into the result after every groupsize bytes.
* @param groupsize
* @param separator
* @return String
*/
public String toHexString(int groupsize, String separator) {
StringWriter out = new StringWriter();
for (int x = 0; x < data.length; x++) {
if ((x != 0) && (groupsize > 0) && (x % groupsize == 0))
out.write(separator);
out.write(byteAsHex(x));
}
return out.toString();
}
/**
* Returns a hex string representing the bit buf. Every 2 hex digits
* are separated by the string sep.
* @param sep
* @return String
*/
public String toHexString(String sep) {
return toHexString(1, sep);
}
/**
* Works like toHexString(grouplen, separator) except that if the bitlen
* of the BitBuf is not a multiple of 8, the slack bits will be on the left
* instead of the right.
* @param grouplen
* @param separator
* @return String
*/
public String toHexStringJustified(int grouplen, String separator) {
BitBuf b = (BitBuf) this.clone();
int slack = b.bitlen % 8;
if (slack > 0)
b.shiftBufferRight(8 - slack);
return b.toHexString(grouplen, separator);
}
/**
* Returns the rightmost 32 bits of the BitBuf as an int.
* @return int
*/
public int toInt() {
long r = 0;
for (int i = 0; i < 4; i++)
r |= (getOctet(bitlen - 8 * (i + 1)) & 0xFF) << (i * 8);
return (int) r;
}
/**
* Returns the rightmost 64 bits of the BitBuf as a long.
* @return long
*/
public long toLong() {
long r = 0;
for (int i = 0; i < 8; i++)
r |= (long) (getOctet(bitlen - 8 * (i + 1)) & 0xFF) << (i * 8);
return r;
}
/**
* Returns the rightmost 16 bits of the BitBuf as an int.
* @return short
*/
public short toShort() {
long r = 0;
for (int i = 0; i < 2; i++)
r |= (getOctet(bitlen - 8 * (i + 1)) & 0xFF) << (i * 8);
return (short) r;
}
/**
* Set unused bits on right to 0 (for situations like a string bit len of 6, which still takes 1 byte).
*/
private void truncate() {
int tailbits = bitlen % 8;
if (tailbits > 0)
data[data.length - 1] &= ~((1 << (8 - tailbits)) - 1);
}
}