package iamrescue.communication.messages.codec; import iamrescue.communication.BitStream; import iamrescue.communication.messages.codec.property.PropertyCodec; import iamrescue.communication.messages.codec.property.PropertyEncoderStore; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.ArrayUtils; import rescuecore2.worldmodel.Entity; import rescuecore2.worldmodel.EntityID; import rescuecore2.worldmodel.Property; public class BitStreamDecoder { private BitStream bitStream; private ICommunicationBeliefBaseAdapter beliefBase; private int currentTimestep; private PropertyEncoderStore encoders; public BitStreamDecoder(BitStream bitStream, ICommunicationBeliefBaseAdapter beliefBase, int currentTimeStep) { this.bitStream = bitStream; this.beliefBase = beliefBase; this.currentTimestep = currentTimeStep; this.encoders = beliefBase.getEncoders(); } public ICommunicationBeliefBaseAdapter getBeliefBase() { return beliefBase; } public int readInt() { byte[] bs = readBytes(CodecUtils.INT_SIZE); return CodecUtils.decodeInt(bs, 0); } public short readShort() { byte[] bs = readBytes(CodecUtils.SHORT_SIZE); return CodecUtils.decodeShort(bs, 0); } public byte readByte() { byte[] bs = readBytes(CodecUtils.BYTE_SIZE); return CodecUtils.decodeByte(bs, 0); } public int readNumber() { // read the prefix that determines the type of the number boolean firstBit = bitStream.readBit(); if (firstBit == BitStreamEncoder.BYTE_PREFIX[0]) { return readByte(); } else { boolean secondBit = bitStream.readBit(); if (secondBit == BitStreamEncoder.SHORT_PREFIX[1]) { return readShort(); } else { return readInt(); } } } public int[] readIntArray() { byte length = readByte(); int[] array = new int[length]; for (int i = 0; i < array.length; i++) { array[i] = readNumber(); } return array; } public short peekShort() { bitStream.mark(); short s = readShort(); bitStream.reset(); return s; } public int peekInt() { bitStream.mark(); int s = readInt(); bitStream.reset(); return s; } public int peekNumber() { bitStream.mark(); int number = readNumber(); bitStream.reset(); return number; } private byte[] readBytes(int size) { byte[] bs = new byte[size]; bitStream.read(bs); return bs; } public byte[] readByteArray() { byte length = readByte(); byte[] array = new byte[length]; for (int i = 0; i < array.length; i++) { array[i] = readByte(); } return array; } public byte[] readByteArraySpecial() { byte maxB = readByte(); if (maxB == Byte.MIN_VALUE) return new byte[0]; BigInteger max = BigInteger.valueOf(maxB); BigInteger num = new BigInteger(readByteArray()); List<Byte> decoded = new ArrayList<Byte>(); while (num.compareTo(BigInteger.ZERO) > 0) { // (num - 1) % max decoded.add(num.mod(max).subtract(BigInteger.ONE).byteValue()); // num /= max num = num.divide(max); } return ArrayUtils.toPrimitive(decoded.toArray(new Byte[0])); } public boolean readBoolean() { return bitStream.readBit(); } public Property readProperty(Entity object, String propertyKey) { PropertyCodec propertyEncoder = encoders.get(propertyKey); return propertyEncoder.decode(object, this); } /** * This method returns an entity with the specified object class. It will * attempt to read an entity id from the stream and find the proper object * in the belief base. If the object does not exist in the beliefbase, the * method returns null, and the bytestream pointer will not have been * changed * * @param objectClass * @return */ public Entity readEntityByID() { Entity object; boolean isShort = readBoolean(); if (isShort) { short shortID = readShort(); object = beliefBase.getObjectByShortID(shortID); if (object == null) throw new IllegalArgumentException( "Could not find object with shortID: " + shortID + " in the beliefbase"); } else { int id = peekNumber() - Short.MIN_VALUE; object = beliefBase.getObjectByID(id); if (object != null) { int readID = readNumber() - Short.MIN_VALUE; assert id == readID; } } return object; } public EntityID readEntityID() { boolean isShort = readBoolean(); if (isShort) { return beliefBase.getShortIndex().getEntityID(readShort()); } else { return new EntityID(readNumber() - Short.MIN_VALUE); } } }