// Path: src/java/kt4j/binary/BinaryResponse.java
// class BinaryResponse implements Response {
//     static final byte ERROR = (byte) 0xBF;
//     static final byte REPLICATION = (byte) 0xB1;
//     static final byte PLAY_SCRIPT = (byte) 0xB4;
//     static final byte SET_BULK = (byte) 0xB8;
//     static final byte REMOVE_BULK = (byte) 0xB9;
//     static final byte GET_BULK = (byte) 0xBA;
//     
//     final byte magic;
//     private long number;
//     
//     protected BinaryResponse(byte magic) {
//         this(magic, 0);
//     }
//     
//     protected BinaryResponse(byte magic, long number) {
//         this.magic = magic;
//         this.number = number;
//     }
//     
//     @Override
//     public boolean isSucceeded() {
//         return magic != ERROR;
//     }
//     
//     /**
//      * Returns the number of the result records
//      */
//     public long getNumber() {
//         return number;
//     }
// }


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.FrameDecoder;
import static kt4j.binary.BinaryResponse.*;
package kt4j.binary;



/**
 * Decodes the received {@link ChannelBuffer}s into a Kyoto Tycoon's response object.
 * 
 * @author kumai
 */
public class BinaryProtocolDecoder extends FrameDecoder {
    private static final int HITS_LENGTH = 4;
    private static final int DBIDX_LENGTH = 2;
    private static final int KSIZ_LENGTH = 4;
    private static final int VSIZ_LENGTH = 4;
    private static final int XT_LENGTH = 8;
    private static final int RNUM_LENGTH = 4;

    @Override
    protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer)
            throws Exception {
        if (!buffer.readable()) {
            return null;
        }

        buffer.markReaderIndex();

        byte op = buffer.readByte();
        switch (op) {
        case ERROR:
            return new BinaryResponse(ERROR);
            
        case SET_BULK:
        case REMOVE_BULK:
            if (buffer.readableBytes() < HITS_LENGTH) {
                buffer.resetReaderIndex();
                return null;
            } else {
                long hits = buffer.readUnsignedInt();
// Path: src/java/kt4j/binary/BinaryResponse.java
// class BinaryResponse implements Response {
//     static final byte ERROR = (byte) 0xBF;
//     static final byte REPLICATION = (byte) 0xB1;
//     static final byte PLAY_SCRIPT = (byte) 0xB4;
//     static final byte SET_BULK = (byte) 0xB8;
//     static final byte REMOVE_BULK = (byte) 0xB9;
//     static final byte GET_BULK = (byte) 0xBA;
//     
//     final byte magic;
//     private long number;
//     
//     protected BinaryResponse(byte magic) {
//         this(magic, 0);
//     }
//     
//     protected BinaryResponse(byte magic, long number) {
//         this.magic = magic;
//         this.number = number;
//     }
//     
//     @Override
//     public boolean isSucceeded() {
//         return magic != ERROR;
//     }
//     
//     /**
//      * Returns the number of the result records
//      */
//     public long getNumber() {
//         return number;
//     }
// }


// Path: src/java/kt4j/binary/BinaryProtocolDecoder.java
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.FrameDecoder;
import static kt4j.binary.BinaryResponse.*;

package kt4j.binary;



/**
 * Decodes the received {@link ChannelBuffer}s into a Kyoto Tycoon's response object.
 * 
 * @author kumai
 */
public class BinaryProtocolDecoder extends FrameDecoder {
    private static final int HITS_LENGTH = 4;
    private static final int DBIDX_LENGTH = 2;
    private static final int KSIZ_LENGTH = 4;
    private static final int VSIZ_LENGTH = 4;
    private static final int XT_LENGTH = 8;
    private static final int RNUM_LENGTH = 4;

    @Override
    protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer)
            throws Exception {
        if (!buffer.readable()) {
            return null;
        }

        buffer.markReaderIndex();

        byte op = buffer.readByte();
        switch (op) {
        case ERROR:
            return new BinaryResponse(ERROR);
            
        case SET_BULK:
        case REMOVE_BULK:
            if (buffer.readableBytes() < HITS_LENGTH) {
                buffer.resetReaderIndex();
                return null;
            } else {
                long hits = buffer.readUnsignedInt();
                return new BinaryResponse(op, hits);