/* * Copyright 2011 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package org.jboss.netty.handler.codec.protobuf; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.frame.CorruptedFrameException; import org.jboss.netty.handler.codec.frame.FrameDecoder; import com.google.protobuf.CodedInputStream; /** * A decoder that splits the received {@link ChannelBuffer}s dynamically by the * value of the Google Protocol Buffers * <a href="http://code.google.com/apis/protocolbuffers/docs/encoding.html#varints">Base * 128 Varints</a> integer length field in the message. For example: * <pre> * BEFORE DECODE (302 bytes) AFTER DECODE (300 bytes) * +--------+---------------+ +---------------+ * | Length | Protobuf Data |----->| Protobuf Data | * | 0xAC02 | (300 bytes) | | (300 bytes) | * +--------+---------------+ +---------------+ * </pre> * * @see com.google.protobuf.CodedInputStream */ public class ProtobufVarint32FrameDecoder extends FrameDecoder { // TODO maxFrameLength + safe skip + fail-fast option // (just like LengthFieldBasedFrameDecoder) /** * Creates a new instance. */ public ProtobufVarint32FrameDecoder() { super(); } @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { buffer.markReaderIndex(); final byte[] buf = new byte[5]; for (int i = 0; i < buf.length; i ++) { if (!buffer.readable()) { buffer.resetReaderIndex(); return null; } buf[i] = buffer.readByte(); if (buf[i] >= 0) { int length = CodedInputStream.newInstance(buf, 0, i + 1).readRawVarint32(); if (length < 0) { throw new CorruptedFrameException("negative length: " + length); } if (buffer.readableBytes() < length) { buffer.resetReaderIndex(); return null; } else { return buffer.readBytes(length); } } } // Couldn't find the byte whose MSB is off. throw new CorruptedFrameException("length wider than 32-bit"); } }