Java tutorial
/** * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. * Copyright (C) 2015 dmulloy2 * * This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with this program; * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA */ package com.comphenix.protocol.compat.netty.independent; import io.netty.buffer.AbstractByteBuf; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.Channels; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ScatteringByteChannel; import java.nio.channels.WritableByteChannel; import com.comphenix.protocol.reflect.accessors.Accessors; import com.comphenix.protocol.reflect.accessors.FieldAccessor; import com.comphenix.protocol.utility.MinecraftReflection; import com.google.common.io.ByteStreams; /** * Construct a ByteBuf around an input stream and an output stream. * <p> * Note that as streams usually don't support seeking, this implementation will ignore * all indexing in the byte buffer. * @author Kristian */ public class NettyByteBufAdapter extends AbstractByteBuf { private DataInputStream input; private DataOutputStream output; // For modifying the reader or writer index private static FieldAccessor READER_INDEX; private static FieldAccessor WRITER_INDEX; private static final int CAPACITY = Short.MAX_VALUE; private NettyByteBufAdapter(DataInputStream input, DataOutputStream output) { // Just pick a figure super(CAPACITY); this.input = input; this.output = output; // Prepare accessors try { if (READER_INDEX == null) { READER_INDEX = Accessors.getFieldAccessor(AbstractByteBuf.class.getDeclaredField("readerIndex")); } if (WRITER_INDEX == null) { WRITER_INDEX = Accessors.getFieldAccessor(AbstractByteBuf.class.getDeclaredField("writerIndex")); } } catch (Exception e) { throw new RuntimeException("Cannot initialize ByteBufAdapter.", e); } // "Infinite" reading/writing if (input == null) READER_INDEX.set(this, Integer.MAX_VALUE); if (output == null) WRITER_INDEX.set(this, Integer.MAX_VALUE); } /** * Construct a new Minecraft packet serializer using the current byte buf adapter. * @param input - the input stream. * @return A packet serializer with a wrapped byte buf adapter. */ public static ByteBuf packetReader(DataInputStream input) { return (ByteBuf) MinecraftReflection.getPacketDataSerializer(new NettyByteBufAdapter(input, null)); } /** * Construct a new Minecraft packet deserializer using the current byte buf adapter. * @param output - the output stream. * @return A packet serializer with a wrapped byte buf adapter. */ public static ByteBuf packetWriter(DataOutputStream output) { return (ByteBuf) MinecraftReflection.getPacketDataSerializer(new NettyByteBufAdapter(null, output)); } @Override public int refCnt() { return 1; } @Override public boolean release() { return false; } @Override public boolean release(int paramInt) { return false; } @Override protected byte _getByte(int paramInt) { try { return input.readByte(); } catch (IOException e) { throw new RuntimeException("Cannot read input.", e); } } @Override protected short _getShort(int paramInt) { try { return input.readShort(); } catch (IOException e) { throw new RuntimeException("Cannot read input.", e); } } @Override protected int _getUnsignedMedium(int paramInt) { try { return input.readUnsignedShort(); } catch (IOException e) { throw new RuntimeException("Cannot read input.", e); } } @Override protected int _getInt(int paramInt) { try { return input.readInt(); } catch (IOException e) { throw new RuntimeException("Cannot read input.", e); } } @Override protected long _getLong(int paramInt) { try { return input.readLong(); } catch (IOException e) { throw new RuntimeException("Cannot read input.", e); } } @Override protected void _setByte(int index, int value) { try { output.writeByte(value); } catch (IOException e) { throw new RuntimeException("Cannot write output.", e); } } @Override protected void _setShort(int index, int value) { try { output.writeShort(value); } catch (IOException e) { throw new RuntimeException("Cannot write output.", e); } } @Override protected void _setMedium(int index, int value) { try { output.writeShort(value); } catch (IOException e) { throw new RuntimeException("Cannot write output.", e); } } @Override protected void _setInt(int index, int value) { try { output.writeInt(value); } catch (IOException e) { throw new RuntimeException("Cannot write output.", e); } } @Override protected void _setLong(int index, long value) { try { output.writeLong(value); } catch (IOException e) { throw new RuntimeException("Cannot write output.", e); } } @Override public int capacity() { return CAPACITY; } @Override public ByteBuf capacity(int paramInt) { return this; } @Override public ByteBufAllocator alloc() { return null; } @Override public ByteOrder order() { return ByteOrder.LITTLE_ENDIAN; } @Override public ByteBuf unwrap() { return null; } @Override public boolean isDirect() { return false; } @Override public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { try { for (int i = 0; i < length; i++) { dst.setByte(dstIndex + i, input.read()); } } catch (IOException e) { throw new RuntimeException("Cannot read input.", e); } return this; } @Override public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) { try { input.read(dst, dstIndex, length); } catch (IOException e) { throw new RuntimeException("Cannot read input.", e); } return this; } @Override public ByteBuf getBytes(int index, ByteBuffer dst) { try { dst.put(ByteStreams.toByteArray(input)); } catch (IOException e) { throw new RuntimeException("Cannot read input.", e); } return this; } @Override public ByteBuf getBytes(int index, OutputStream dst, int length) throws IOException { ByteStreams.copy(ByteStreams.limit(input, length), dst); return this; } @Override public int getBytes(int index, GatheringByteChannel out, int length) throws IOException { byte[] data = ByteStreams.toByteArray(ByteStreams.limit(input, length)); out.write(ByteBuffer.wrap(data)); return data.length; } @Override public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) { byte[] buffer = new byte[length]; src.getBytes(srcIndex, buffer); try { output.write(buffer); return this; } catch (IOException e) { throw new RuntimeException("Cannot write output.", e); } } @Override public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) { try { output.write(src, srcIndex, length); return this; } catch (IOException e) { throw new RuntimeException("Cannot write output.", e); } } @Override public ByteBuf setBytes(int index, ByteBuffer src) { try { WritableByteChannel channel = Channels.newChannel(output); channel.write(src); return this; } catch (IOException e) { throw new RuntimeException("Cannot write output.", e); } } @Override public int setBytes(int index, InputStream in, int length) throws IOException { InputStream limit = ByteStreams.limit(in, length); ByteStreams.copy(limit, output); return length - limit.available(); } @Override public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException { ByteBuffer buffer = ByteBuffer.allocate(length); WritableByteChannel channel = Channels.newChannel(output); int count = in.read(buffer); channel.write(buffer); return count; } @Override public ByteBuf copy(int index, int length) { throw new UnsupportedOperationException("Cannot seek in input stream."); } @Override public int nioBufferCount() { return 0; } @Override public ByteBuffer nioBuffer(int paramInt1, int paramInt2) { throw new UnsupportedOperationException(); } @Override public ByteBuffer internalNioBuffer(int paramInt1, int paramInt2) { return null; } @Override public ByteBuffer[] nioBuffers(int paramInt1, int paramInt2) { return null; } @Override public boolean hasArray() { return false; } @Override public byte[] array() { return null; } @Override public int arrayOffset() { return 0; } @Override public boolean hasMemoryAddress() { return false; } @Override public long memoryAddress() { return 0; } @Override public ByteBuf retain(int paramInt) { return this; } @Override public ByteBuf retain() { return this; } }