package com.beowulfe.hap.impl.connections; import java.io.ByteArrayOutputStream; import java.util.Collection; import java.util.LinkedList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; class LengthPrefixedByteArrayProcessor { private final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); private Byte firstLengthByteBuffer; //Only used if we've received a single byte at the start of a message private int targetLength = 0; private final static Logger LOGGER = LoggerFactory.getLogger(LengthPrefixedByteArrayProcessor.class); public synchronized Collection<byte[]> handle(byte[] data) { Collection<byte[]> results = new LinkedList<>(); int pos = 0; LOGGER.trace("Received message of length {}. Existing buffer is {}", data.length, buffer.size()); if (buffer.size() == 0) { while(data.length - pos > 18) { int targetLength = (data[0] & 0xFF) + (data[1] & 0xFF) * 256 + 16 + 2; LOGGER.trace("Attempting to read message of length {}", targetLength); if (data.length >= pos + targetLength) { byte[] b = new byte[targetLength - 2]; System.arraycopy(data, pos+2, b, 0, targetLength-2); results.add(b); LOGGER.trace("Read complete message"); pos = pos + targetLength; } else { LOGGER.trace("Not enough data available"); break; } } } if (data.length > pos) { LOGGER.trace("Remaining data available"); step(data, pos, results); } LOGGER.trace("Returning {} results", results.size()); return results; } private void step(byte[] data, int pos, Collection<byte[]> results) { LOGGER.trace("Performing step operation on buffer of length {} with pos {}", data.length, pos); if (targetLength == 0 && data.length == 1 + pos) { firstLengthByteBuffer = data[pos]; LOGGER.trace("Received a single byte message, storing byte {} for later", firstLengthByteBuffer); return; } if (targetLength == 0) { if (firstLengthByteBuffer != null) { targetLength = (firstLengthByteBuffer & 0xFF) + (data[pos] & 0xFF) * 256 + 16; pos += 1; LOGGER.trace("Received the second byte after storing the first byte. New length is {}", targetLength); } else { targetLength = (data[pos] & 0xFF) + (data[pos+1] & 0xFF) * 256 + 16; pos += 2; LOGGER.trace("targetLength is {}", targetLength); } } int toWrite = targetLength - buffer.size(); if (toWrite <= data.length - pos) { //We have a complete message LOGGER.trace("Received a complete message"); buffer.write(data, pos, toWrite); results.add(buffer.toByteArray()); buffer.reset(); targetLength=0; if (pos + toWrite > data.length) { step(data, pos + toWrite, results); } } else { LOGGER.trace("Storing {} bytes in buffer until we receive the complete {}", data.length-pos, targetLength); buffer.write(data, pos, data.length - pos); } } }