package net.glowstone.net.pipeline;
import com.flowpowered.networking.util.ByteBufUtils;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;
import java.util.List;
/**
* Experimental pipeline component.
*/
public final class FramingHandler extends ByteToMessageCodec<ByteBuf> {
@Override
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception {
ByteBufUtils.writeVarInt(out, msg.readableBytes());
out.writeBytes(msg);
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
// check for length field readability
in.markReaderIndex();
if (!readableVarInt(in)) {
return;
}
// check for contents readability
int length = ByteBufUtils.readVarInt(in);
if (in.readableBytes() < length) {
in.resetReaderIndex();
return;
}
// read contents into buf
ByteBuf buf = ctx.alloc().buffer(length);
in.readBytes(buf, length);
out.add(buf);
}
private static boolean readableVarInt(ByteBuf buf) {
if (buf.readableBytes() > 5) {
// maximum varint size
return true;
}
int idx = buf.readerIndex();
byte in;
do {
if (buf.readableBytes() < 1) {
buf.readerIndex(idx);
return false;
}
in = buf.readByte();
} while ((in & 0x80) != 0);
buf.readerIndex(idx);
return true;
}
}