All Downloads are FREE. Search and download functionalities are using the official Maven repository.

zserio.runtime.validation.ValidationBitStreamReader Maven / Gradle / Ivy

package zserio.runtime.validation;

import java.io.IOException;

import zserio.runtime.io.ByteArrayBitStreamReader;

/**
 * The bit stream reader used in validate() method generated by Zserio.
 * 

* The validation bit stream reader records * - a special 'AND' bit mask (invalidMaskBuffer) which contains '1' if corresponding bit in read buffer is not * used for validation and * - a special 'OR' bit mask (nanMaskBuffer) which constains normalized NaN values (NaNs used by writer).

*

* Bits in reader do not have to be used for validation in the following situations: * 1. If the bits have been skipped (not read) which can happen using Zserio 'align' command for example. * 2. If NaN occurs. NaNs do not have unique binary representation and they must be normalized to NaNs used by * writer.

*/ public final class ValidationBitStreamReader extends ByteArrayBitStreamReader { /** * Constructs a new ValidationBitStreamReader. * * @param bytes Array of bytes to construct from. */ public ValidationBitStreamReader(final byte[] bytes) { super(bytes); invalidMaskBuffer = new byte[bytes.length]; invalidMaskBufferEraser = new MaskBufferEraser(invalidMaskBuffer); invalidMaskBufferSetter = new MaskBufferSetter(invalidMaskBuffer); nanMaskBuffer = new byte[bytes.length]; nanMaskBufferEraser = new MaskBufferEraser(nanMaskBuffer); } /** * Returns the read byte array with unused bits set to zero and with 'normalized' NaNs. * * 'Normalized' NaNs means NaNs with the same binary format as it is used by Java BitStreamWriter. * * @return Read byte array with masked unused bits. */ public byte[] toMaskedByteArray() { final byte[] maskedByteArray = new byte[invalidMaskBuffer.length]; final int endBytePosition = getBytePosition(); for (int i = 0; i < endBytePosition; ++i) maskedByteArray[i] = (byte)(getBuffer()[i] & ~invalidMaskBuffer[i] | nanMaskBuffer[i]); final int endBitOffset = getBitOffset(); if (endBitOffset > 0) { // endBitOffset | 1 | 2 | 3 | 4 | 5 | 6 | 7 | // -------------|------|------|------|------|------|------|------| // mask | 0x7F | 0x3F | 0x1F | 0x0F | 0x07 | 0x03 | 0x01 | final int mask = (1 << (8 - endBitOffset)) - 1; final int invalidMask = invalidMaskBuffer[endBytePosition] | mask; maskedByteArray[endBytePosition] = (byte)(getBuffer()[endBytePosition] & ~invalidMask | nanMaskBuffer[endBytePosition]); } return maskedByteArray; } @Override public void setBitPosition(long bitPosition) throws IOException { final int startBytePosition = getBytePosition(); final int startBitOffset = getBitOffset(); final long startBitPosition = getBitPosition(); super.setBitPosition(bitPosition); final int endBytePosition = getBytePosition(); final int endBitOffset = getBitOffset(); final int requieredBufferLength = endBytePosition + ((endBitOffset != 0) ? 1 : 0); if (requieredBufferLength > invalidMaskBuffer.length) throw new IOException("ValidationBitStreamReader: Unable to set bit position to " + bitPosition + ". It is beyond end of stream."); final long endBitPosition = getBitPosition(); // this checking is neccesary because both positions can be end of stream if (endBitPosition != startBitPosition) { if (endBitPosition > startBitPosition) { modifyMaskBuffer(startBytePosition, startBitOffset, endBytePosition, endBitOffset, invalidMaskBufferSetter); } else { modifyMaskBuffer(endBytePosition, endBitOffset, startBytePosition, startBitOffset, invalidMaskBufferEraser); modifyMaskBuffer( endBytePosition, endBitOffset, startBytePosition, startBitOffset, nanMaskBufferEraser); } } } @Override public float readFloat16() throws IOException { final int startBytePosition = getBytePosition(); final int startBitOffset = getBitOffset(); final float readFloat = super.readFloat16(); if (Float.isNaN(readFloat)) { modifyMaskBuffer(startBytePosition, startBitOffset, getBytePosition(), getBitOffset(), invalidMaskBufferSetter); setNanMaskBuffer(startBytePosition, startBitOffset); } return readFloat; } private void modifyMaskBuffer(int startBytePosition, int startBitOffset, int endBytePosition, int endBitOffset, MaskBufferAction action) throws IOException { if (endBytePosition == startBytePosition) { action.modifyBits(startBytePosition, startBitOffset, endBitOffset - startBitOffset); } else { action.modifyBits(startBytePosition, startBitOffset, 8 - startBitOffset); for (int bytePosition = startBytePosition + 1; bytePosition < endBytePosition; ++bytePosition) action.modifyByte(bytePosition); if (endBitOffset > 0) action.modifyBits(endBytePosition, 0, endBitOffset); } } private void setNanMaskBuffer(int startBytePosition, int startBitOffset) { // set NaN used by writer (0x7E00) to nanMaskBuffer final byte nanHighByte = (byte)0x7E; nanMaskBuffer[startBytePosition] |= (nanHighByte >> startBitOffset); if (startBitOffset != 0) nanMaskBuffer[startBytePosition + 1] |= (nanHighByte << (8 - startBitOffset)); } private interface MaskBufferAction { public void modifyBits(int bytePosition, int bitOffset, int numBits); public void modifyByte(int bytePosition); } private static class MaskBufferSetter implements MaskBufferAction { public MaskBufferSetter(byte[] maskBuffer) { this.maskBuffer = maskBuffer; } @Override public void modifyBits(int bytePosition, int bitOffset, int numBits) { // numBits | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | // --------|------|------|------|------|------|------|------|------|------| // mask | 0x00 | 0x01 | 0x03 | 0x07 | 0x0F | 0x1F | 0x3F | 0x7F | 0xFF | final int mask = (1 << numBits) - 1; maskBuffer[bytePosition] |= mask << (8 - bitOffset - numBits); } @Override public void modifyByte(int bytePosition) { maskBuffer[bytePosition] = (byte)0xFF; } private final byte[] maskBuffer; } private static class MaskBufferEraser implements MaskBufferAction { public MaskBufferEraser(byte[] maskBuffer) { this.maskBuffer = maskBuffer; } @Override public void modifyBits(int bytePosition, int bitOffset, int numBits) { // numBits | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | // --------|------|------|------|------|------|------|------|------|------| // mask | 0xFF | 0xFE | 0xFC | 0xF8 | 0xF0 | 0xE0 | 0xC0 | 0x80 | 0x00 | final int mask = ~((1 << numBits) - 1); maskBuffer[bytePosition] &= mask << (8 - bitOffset - numBits); } @Override public void modifyByte(int bytePosition) { maskBuffer[bytePosition] = (byte)0x00; } private final byte[] maskBuffer; } private final byte[] invalidMaskBuffer; private final MaskBufferEraser invalidMaskBufferEraser; private final MaskBufferSetter invalidMaskBufferSetter; private final byte[] nanMaskBuffer; private final MaskBufferEraser nanMaskBufferEraser; }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy