package org.rakam.kume; import com.esotericsoftware.kryo.KryoException; import com.esotericsoftware.kryo.io.Input; import io.netty.buffer.ByteBuf; import java.io.IOException; import java.io.InputStream; public class ByteBufInput extends Input { private final ByteBuf byteBuf; public ByteBufInput(ByteBuf byteBuf) { super(); this.byteBuf = byteBuf; } @Override public void setBuffer(byte[] bytes) { throw new UnsupportedOperationException(); } @Override public void setBuffer(byte[] bytes, int offset, int count) { throw new UnsupportedOperationException(); } @Override public byte[] getBuffer() { return byteBuf.array(); } @Override public InputStream getInputStream() { throw new UnsupportedOperationException(); } @Override public void setInputStream(InputStream inputStream) { throw new UnsupportedOperationException(); } @Override public long total() { throw new UnsupportedOperationException(); } @Override public void setTotal(long total) { throw new UnsupportedOperationException(); } @Override public void setPosition(int position) { byteBuf.readerIndex(position); } @Override public void setLimit(int limit) { throw new UnsupportedOperationException(); } @Override public void rewind() { throw new UnsupportedOperationException(); } @Override public void skip(int count) throws KryoException { byteBuf.skipBytes(count); } @Override protected int fill(byte[] buffer, int offset, int count) throws KryoException { throw new UnsupportedOperationException(); } @Override protected int require(int required) throws KryoException { return byteBuf.readerIndex(); } @Override public boolean eof() { throw new UnsupportedOperationException(); } @Override public int available() throws IOException { throw new UnsupportedOperationException(); } @Override public int read() throws KryoException { return byteBuf.readByte(); } @Override public int read(byte[] bytes) throws KryoException { byteBuf.readBytes(bytes); return bytes.length; } @Override public int read(byte[] bytes, int offset, int count) throws KryoException { byteBuf.readBytes(bytes, offset, count); return bytes.length; } @Override public long skip(long count) throws KryoException { byteBuf.skipBytes((int) count); return byteBuf.readerIndex(); } @Override public void close() throws KryoException { throw new UnsupportedOperationException(); } @Override public byte readByte() throws KryoException { return byteBuf.readByte(); } @Override public int readByteUnsigned() throws KryoException { return byteBuf.readUnsignedByte(); } @Override public byte[] readBytes(int length) throws KryoException { return byteBuf.readBytes(length).array(); } @Override public void readBytes(byte[] bytes) throws KryoException { byteBuf.readBytes(bytes); } @Override public void readBytes(byte[] bytes, int offset, int count) throws KryoException { byteBuf.readBytes(bytes, offset, count); } @Override public int readInt() throws KryoException { return byteBuf.readInt(); } @Override public int readInt(boolean optimizePositive) throws KryoException { return byteBuf.readInt(); } @Override public int readVarInt(boolean optimizePositive) throws KryoException { return byteBuf.readInt(); } @Override public boolean canReadInt() throws KryoException { return byteBuf.readableBytes() >= 4; } @Override public boolean canReadLong() throws KryoException { return byteBuf.readableBytes() >= 8; } @Override public String readString() { int available = require(1); int b = byteBuf.readByte(); // if ((b & 0x80) == 0) return readAscii(); // ASCII. // Null, empty, or UTF8. int charCount = available >= 5 ? readUtf8Length(b) : readUtf8Length_slow(b); switch (charCount) { case 0: return null; case 1: return ""; } charCount--; if (chars.length < charCount) chars = new char[charCount]; readUtf8(charCount); return new String(chars, 0, charCount); } private int readUtf8Length (int b) { int result = b & 0x3F; // Mask all but first 6 bits. if ((b & 0x40) != 0) { // Bit 7 means another byte, bit 8 means UTF8. b = byteBuf.readByte(); result |= (b & 0x7F) << 6; if ((b & 0x80) != 0) { b = byteBuf.readByte(); result |= (b & 0x7F) << 13; if ((b & 0x80) != 0) { b = byteBuf.readByte(); result |= (b & 0x7F) << 20; if ((b & 0x80) != 0) { b = byteBuf.readByte(); result |= (b & 0x7F) << 27; } } } } return result; } private void readUtf8 (int charCount) { char[] chars = this.chars; // Try to read 7 bit ASCII chars. int charIndex = 0; int count = Math.min(require(1), charCount); int b; while (charIndex < count) { b = byteBuf.readByte(); if (b < 0) { byteBuf.readerIndex(byteBuf.readerIndex()-1); break; } chars[charIndex++] = (char)b; } // If buffer didn't hold all chars or any were not ASCII, use slow path for remainder. if (charIndex < charCount) readUtf8_slow(charCount, charIndex); } private void readUtf8_slow (int charCount, int charIndex) { char[] chars = this.chars; while (charIndex < charCount) { if (byteBuf.readableBytes() == 0) require(1); int b = byteBuf.readByte() & 0xFF; switch (b >> 4) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: chars[charIndex] = (char)b; break; case 12: case 13: if (byteBuf.readableBytes() == 0) require(1); chars[charIndex] = (char)((b & 0x1F) << 6 | byteBuf.readByte() & 0x3F); break; case 14: require(2); chars[charIndex] = (char)((b & 0x0F) << 12 | (byteBuf.readByte() & 0x3F) << 6 | byteBuf.readByte() & 0x3F); break; } charIndex++; } } private int readUtf8Length_slow (int b) { int result = b & 0x3F; // Mask all but first 6 bits. if ((b & 0x40) != 0) { // Bit 7 means another byte, bit 8 means UTF8. require(1); b = byteBuf.readByte(); result |= (b & 0x7F) << 6; if ((b & 0x80) != 0) { require(1); b = byteBuf.readByte(); result |= (b & 0x7F) << 13; if ((b & 0x80) != 0) { require(1); b = byteBuf.readByte(); result |= (b & 0x7F) << 20; if ((b & 0x80) != 0) { require(1); b = byteBuf.readByte(); result |= (b & 0x7F) << 27; } } } } return result; } @Override public StringBuilder readStringBuilder() { int available = require(1); int b = byteBuf.readByte(); // if ((b & 0x80) == 0) return new StringBuilder(readAscii()); // ASCII. // Null, empty, or UTF8. int charCount = available >= 5 ? readUtf8Length(b) : readUtf8Length_slow(b); switch (charCount) { case 0: return null; case 1: return new StringBuilder(""); } charCount--; if (chars.length < charCount) chars = new char[charCount]; readUtf8(charCount); StringBuilder builder = new StringBuilder(charCount); builder.append(chars, 0, charCount); return builder; } @Override public float readFloat() throws KryoException { return byteBuf.readFloat(); } @Override public float readFloat(float precision, boolean optimizePositive) throws KryoException { return byteBuf.readFloat(); } @Override public short readShort() throws KryoException { return byteBuf.readShort(); } @Override public int readShortUnsigned() throws KryoException { return byteBuf.readUnsignedShort(); } @Override public long readLong() throws KryoException { return byteBuf.readLong(); } @Override public long readLong(boolean optimizePositive) throws KryoException { return byteBuf.readLong(); } @Override public long readVarLong(boolean optimizePositive) throws KryoException { return byteBuf.readLong(); } @Override public boolean readBoolean() throws KryoException { return byteBuf.readBoolean(); } @Override public char readChar() throws KryoException { return byteBuf.readChar(); } @Override public double readDouble() throws KryoException { return byteBuf.readDouble(); } @Override public double readDouble(double precision, boolean optimizePositive) throws KryoException { return byteBuf.readDouble(); } }