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; } }