au.gov.amsa.sgb.decoder.internal.Bits Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sgb-decoder Show documentation
Show all versions of sgb-decoder Show documentation
Decodes second generation Beacon detection messages and Beacon 23 Hex IDs
The newest version!
package au.gov.amsa.sgb.decoder.internal;
import java.util.Arrays;
import java.util.Optional;
import com.github.davidmoten.guavamini.Preconditions;
public final class Bits {
private static final int BITS_PER_HEX_CHAR = 4;
private final boolean[] bits;
private int pos;
private Bits(boolean[] bits) {
this.bits = bits;
}
public static Bits from(boolean[] bits) {
return new Bits(bits);
}
public static Bits zeros(int length) {
return Bits.from(new boolean[length]);
}
public static Bits from(String bitString) {
boolean[] bits = new boolean[bitString.length()];
for (int i = 0; i < bits.length; i++) {
char ch = bitString.charAt(i);
if (ch == '1') {
bits[i] = true;
} else if (ch != '0') {
throw new IllegalArgumentException("illegal character in bit string " + bitString);
}
}
return from(bits);
}
public static Bits fromHex(String hex) {
return Bits.from(Hex.hexToBinary(hex));
}
public Bits concatWith(String bitString) {
return concatWith(Bits.from(bitString));
}
public Bits concatWith(Bits b) {
boolean[] array = Arrays.copyOf(bits, bits.length + b.bits.length);
System.arraycopy(b.bits, 0, array, bits.length, b.bits.length);
return Bits.from(array);
}
public Bits position(int position) {
Preconditions.checkArgument(position >= 0 && position <= bits.length);
this.pos = position;
return this;
}
public Bits skip(int numBits) {
Preconditions.checkArgument(numBits >= 0);
return position(pos + numBits);
}
public boolean atEnd() {
return pos == bits.length;
}
private int value(int index) {
return bits[index] ? 1 : 0;
}
/**
* Assumes the most significant bit is on the left.
*
* @param numBits number of bits reads
* @return the bits as an integer
*/
public int readUnsignedInt(int numBits) {
Preconditions.checkArgument(numBits > 0);
Preconditions.checkArgument(pos + numBits <= bits.length);
int result = 0;
for (int i = pos; i < pos + numBits; i++) {
result = 2 * result + value(i);
}
pos += numBits;
return result;
}
//////////////////////////////////////////////////////////////
// Modified Baudot parsing
//////////////////////////////////////////////////////////////
private static final int SHORT_BAUDOT_CODE_BINARY_LENGTH = 5;
private static final int BAUDOT_CODE_BINARY_LENGTH = 6;
public String readBaudotCharactersShort(int numChars) {
return readBaudotCharactersShort(numChars, Optional.empty());
}
public String readBaudotCharactersShort(int numChars, String context) {
return readBaudotCharactersShort(numChars, Optional.ofNullable(context));
}
private String readBaudotCharactersShort(int numChars, Optional context) {
try {
StringBuilder s = new StringBuilder();
for (int i = 0; i < numChars; i++) {
int v = readUnsignedInt(SHORT_BAUDOT_CODE_BINARY_LENGTH);
s.append(BaudotCode.toCharFromShortCode(v));
}
return s.toString();
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(context.map(x -> x + ": ").orElse("") + e.getMessage(), e);
}
}
public String readBaudotCharacters(int numChars) {
return readBaudotCharacters(numChars, (String) null);
}
public String readBaudotCharacters(int numChars, String context) {
return readBaudotCharacters(numChars, Optional.ofNullable(context));
}
private String readBaudotCharacters(int numChars, Optional context) {
try {
StringBuilder s = new StringBuilder();
for (int i = 0; i < numChars; i++) {
int v = readUnsignedInt(BAUDOT_CODE_BINARY_LENGTH);
s.append(BaudotCode.toChar(v));
}
return s.toString();
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(context.map(x -> x + ": ").orElse("") + e.getMessage(), e);
}
}
//////////////////////////////////////////////////////////////
public boolean readBoolean() {
Preconditions.checkArgument(!atEnd(), "already at end");
pos += 1;
return bits[pos - 1];
}
public String readHex(int numChars) {
return Hex.bitStringToHex(readBitString(numChars * BITS_PER_HEX_CHAR));
}
public String readBitString(int numBits) {
String s = readBitsString(pos, numBits);
pos += numBits;
return s;
}
private String readBitsString(int pos, int numBits) {
StringBuilder b = new StringBuilder();
for (int i = pos; i < pos + numBits; i++) {
b.append(bits[i] ? '1' : '0');
}
return b.toString();
}
public boolean isEqualTo(Bits b) {
return b != null && b.bits.length == bits.length && Arrays.equals(b.bits, bits);
}
public boolean[] readBooleanArray(int numBits) {
boolean[] b = readBooleanArray(pos, numBits);
pos += numBits;
return b;
}
private boolean[] readBooleanArray(int pos, int numBits) {
Preconditions.checkArgument(numBits > 0);
Preconditions.checkArgument(pos + numBits <= bits.length);
return Arrays.copyOfRange(bits, pos, pos + numBits);
}
public Bits readBits(int numBits) {
return Bits.from(readBooleanArray(numBits));
}
public boolean isZero() {
for (boolean b : bits) {
if (b) {
return false;
}
}
return true;
}
public int position() {
return pos;
}
public int length() {
return bits.length;
}
public String toBitString() {
return readBitsString(0, bits.length);
}
public Bits remainderOnPolynomialDivision(Bits divisor) {
divisor = divisor.trimLeadingZeros();
Bits b = new Bits(this.bits);
int i = 0;
while (i <= b.length() - divisor.length()) {
if (b.bits[i]) {
for (int j = i; j < i + divisor.length(); j++) {
b.bits[j] = b.bits[j] ^ divisor.bits[j - i];
}
}
i++;
}
return b;
}
public Bits trimLeadingZeros() {
int p = bits.length - 1;
for (int i = 0; i < bits.length - 1; i++) {
if (bits[i]) {
p = i;
break;
}
}
boolean[] b = Arrays.copyOfRange(bits, p, bits.length);
return Bits.from(b);
}
public Bits last(int numBits) {
return Bits.from(readBooleanArray(length() - numBits, numBits));
}
@Override
public String toString() {
return toBitString();
}
public Bits replace(int i, Bits b) {
boolean[] a = Arrays.copyOf(bits, bits.length);
System.arraycopy(b.bits, 0, a, i, b.bits.length);
return Bits.from(a);
}
public String toHex() {
return Hex.bitStringToHex(toBitString());
}
}