1 /* 2 * Copyright 2009 Red Hat, Inc. 3 * 4 * Red Hat licenses this file to you under the Apache License, version 2.0 5 * (the "License"); you may not use this file except in compliance with the 6 * License. You may obtain a copy of the License at: 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations 14 * under the License. 15 */ 16 package org.jboss.netty.handler.codec.protobuf; 17 18 import org.jboss.netty.buffer.ChannelBuffer; 19 import org.jboss.netty.channel.Channel; 20 import org.jboss.netty.channel.ChannelHandlerContext; 21 import org.jboss.netty.handler.codec.frame.CorruptedFrameException; 22 import org.jboss.netty.handler.codec.frame.FrameDecoder; 23 24 import com.google.protobuf.CodedInputStream; 25 26 /** 27 * A decoder that splits the received {@link ChannelBuffer}s dynamically by the 28 * value of the Google Protocol Buffers 29 * <a href="http://code.google.com/apis/protocolbuffers/docs/encoding.html#varints">Base 30 * 128 Varints</a> integer length field in the message. For example: 31 * <pre> 32 * BEFORE DECODE (302 bytes) AFTER DECODE (300 bytes) 33 * +--------+---------------+ +---------------+ 34 * | Length | Protobuf Data |----->| Protobuf Data | 35 * | 0xAC02 | (300 bytes) | | (300 bytes) | 36 * +--------+---------------+ +---------------+ 37 * </pre> 38 * 39 * @see com.google.protobuf.CodedInputStream 40 * 41 * @author <a href="http://www.jboss.org/netty/">The Netty Project</a> 42 * @author Tomasz Blachowicz (tblachowicz@gmail.com) 43 * @author <a href="http://gleamynode.net/">Trustin Lee</a> 44 * 45 * @version $Rev: 2323 $, $Date: 2010-06-24 11:13:12 +0900 (Thu, 24 Jun 2010) $ 46 */ 47 public class ProtobufVarint32FrameDecoder extends FrameDecoder { 48 49 // TODO maxFrameLength + safe skip + fail-fast option 50 // (just like LengthFieldBasedFrameDecoder) 51 52 /** 53 * Creates a new instance. 54 */ 55 public ProtobufVarint32FrameDecoder() { 56 super(); 57 } 58 59 @Override 60 protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { 61 buffer.markReaderIndex(); 62 final byte[] buf = new byte[5]; 63 for (int i = 0; i < buf.length; i ++) { 64 if (!buffer.readable()) { 65 buffer.resetReaderIndex(); 66 return null; 67 } 68 69 buf[i] = buffer.readByte(); 70 if (buf[i] >= 0) { 71 int length = CodedInputStream.newInstance(buf, 0, i + 1).readRawVarint32(); 72 if (length < 0) { 73 throw new CorruptedFrameException("negative length: " + length); 74 } 75 76 if (buffer.readableBytes() < length) { 77 buffer.resetReaderIndex(); 78 return null; 79 } else { 80 return buffer.readBytes(length); 81 } 82 } 83 } 84 85 // Couldn't find the byte whose MSB is off. 86 throw new CorruptedFrameException("length wider than 32-bit"); 87 } 88 }