439 lines
10 KiB
Java
439 lines
10 KiB
Java
/**
|
|
* 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.injector.netty;
|
|
|
|
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.FileChannel;
|
|
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
|
|
*/
|
|
@SuppressWarnings("unused")
|
|
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 = Integer.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 ByteBufAllocator.DEFAULT;
|
|
}
|
|
|
|
@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;
|
|
}
|
|
|
|
protected int _getIntLE(int arg0) {
|
|
return 0;
|
|
}
|
|
|
|
protected long _getLongLE(int arg0) {
|
|
return 0;
|
|
}
|
|
|
|
protected short _getShortLE(int arg0) {
|
|
return 0;
|
|
}
|
|
|
|
protected int _getUnsignedMediumLE(int arg0) {
|
|
return 0;
|
|
}
|
|
|
|
protected void _setIntLE(int arg0, int arg1) {
|
|
}
|
|
|
|
protected void _setLongLE(int arg0, long arg1) {
|
|
}
|
|
|
|
protected void _setMediumLE(int arg0, int arg1) {
|
|
}
|
|
|
|
protected void _setShortLE(int arg0, int arg1) {
|
|
}
|
|
|
|
public int getBytes(int arg0, FileChannel arg1, long arg2, int arg3) throws IOException {
|
|
return 0;
|
|
}
|
|
|
|
public int setBytes(int arg0, FileChannel arg1, long arg2, int arg3) throws IOException {
|
|
return 0;
|
|
}
|
|
|
|
public ByteBuf touch() {
|
|
return null;
|
|
}
|
|
|
|
public ByteBuf touch(Object arg0) {
|
|
return null;
|
|
}
|
|
}
|