org.lanternpowered.server.network.buffer.LanternByteBuffer.java Source code

Java tutorial

Introduction

Here is the source code for org.lanternpowered.server.network.buffer.LanternByteBuffer.java

Source

/*
 * This file is part of LanternServer, licensed under the MIT License (MIT).
 *
 * Copyright (c) LanternPowered <https://www.lanternpowered.org>
 * Copyright (c) SpongePowered <https://www.spongepowered.org>
 * Copyright (c) contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the Software), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.lanternpowered.server.network.buffer;

import static com.google.common.base.Preconditions.checkNotNull;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufOutputStream;
import io.netty.handler.codec.CodecException;
import io.netty.handler.codec.DecoderException;
import io.netty.handler.codec.EncoderException;
import org.lanternpowered.server.data.persistence.nbt.NbtDataContainerInputStream;
import org.lanternpowered.server.data.persistence.nbt.NbtStreamUtils;
import org.lanternpowered.server.network.buffer.objects.Type;
import org.lanternpowered.server.util.LimitInputStream;
import org.spongepowered.api.data.DataView;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.UUID;

import javax.annotation.Nullable;

public class LanternByteBuffer implements ByteBuffer {

    private final ByteBuf buf;

    @Nullable
    private LanternByteBuffer opposite;

    LanternByteBuffer(ByteBuf buf) {
        this.buf = buf;
    }

    public ByteBuf getDelegate() {
        return this.buf;
    }

    @Override
    public int getCapacity() {
        return this.buf.capacity();
    }

    @Override
    public int available() {
        return this.buf.readableBytes();
    }

    // TODO: Deprecate in the api
    @SuppressWarnings("deprecation")
    @Deprecated
    @Override
    public int refCnt() {
        return this.buf.refCnt();
    }

    @Override
    public OutputStream asOutputStream() {
        return new ByteBufOutputStream(this.buf);
    }

    @Override
    public ByteBuffer retain() {
        this.buf.retain();
        return this;
    }

    @Override
    public ByteBuffer retain(int increment) {
        this.buf.retain(increment);
        return this;
    }

    @Override
    public ByteBuffer touch() {
        this.buf.touch();
        return this;
    }

    @Override
    public ByteBuffer touch(Object hint) {
        this.buf.touch(hint);
        return this;
    }

    @Override
    public LanternByteBuffer order(ByteOrder order) {
        if (this.buf.order().equals(order)) {
            return this;
        } else {
            if (this.opposite == null) {
                this.opposite = new LanternByteBuffer(this.buf.order(order));
                this.opposite.opposite = this;
            }
            return this.opposite;
        }
    }

    @SuppressWarnings("deprecation")
    @Deprecated
    @Override
    public ByteOrder getByteOrder() {
        return this.buf.order();
    }

    @Override
    public int readerIndex() {
        return this.buf.readerIndex();
    }

    @Override
    public LanternByteBuffer setReadIndex(int index) {
        this.buf.readerIndex(index);
        return this;
    }

    @Override
    public int writerIndex() {
        return this.buf.writerIndex();
    }

    @Override
    public LanternByteBuffer setWriteIndex(int index) {
        this.buf.writerIndex(index);
        return this;
    }

    @Override
    public LanternByteBuffer setIndex(int readIndex, int writeIndex) {
        this.buf.setIndex(readIndex, writeIndex);
        return this;
    }

    @Override
    public LanternByteBuffer clear() {
        this.buf.clear();
        return this;
    }

    @Override
    public LanternByteBuffer markRead() {
        this.buf.markReaderIndex();
        return this;
    }

    @Override
    public LanternByteBuffer markWrite() {
        this.buf.markWriterIndex();
        return this;
    }

    @Override
    public LanternByteBuffer resetRead() {
        this.buf.resetReaderIndex();
        return this;
    }

    @Override
    public LanternByteBuffer resetWrite() {
        this.buf.resetWriterIndex();
        return this;
    }

    @Override
    public LanternByteBuffer slice() {
        return new LanternByteBuffer(this.buf.slice());
    }

    @Override
    public LanternByteBuffer slice(int index, int length) {
        return new LanternByteBuffer(this.buf.slice(index, length));
    }

    @Override
    public boolean hasArray() {
        return this.buf.hasArray();
    }

    @Override
    public byte[] array() {
        return this.buf.array();
    }

    @Override
    public LanternByteBuffer writeBoolean(boolean data) {
        this.buf.writeBoolean(data);
        return this;
    }

    @Override
    public LanternByteBuffer setBoolean(int index, boolean data) {
        this.buf.setBoolean(index, data);
        return this;
    }

    @Override
    public boolean readBoolean() {
        return this.buf.readBoolean();
    }

    @Override
    public boolean getBoolean(int index) {
        return this.buf.getBoolean(index);
    }

    @Override
    public LanternByteBuffer writeByte(byte data) {
        this.buf.writeByte(data);
        return this;
    }

    @Override
    public LanternByteBuffer setByte(int index, byte data) {
        this.buf.setByte(index, data);
        return this;
    }

    @Override
    public byte readByte() {
        return this.buf.readByte();
    }

    @Override
    public byte getByte(int index) {
        return this.buf.getByte(index);
    }

    @Override
    public LanternByteBuffer writeByteArray(byte[] data) {
        writeVarInt(data.length);
        writeBytes(data);
        return this;
    }

    @Override
    public LanternByteBuffer writeByteArray(byte[] data, int start, int length) {
        writeVarInt(length);
        writeBytes(data, start, length);
        return this;
    }

    @Override
    public LanternByteBuffer setByteArray(int index, byte[] data) {
        final int oldIndex = this.buf.writerIndex();
        this.buf.writerIndex(index);
        writeByteArray(data);
        this.buf.writerIndex(oldIndex);
        return this;
    }

    @Override
    public LanternByteBuffer setByteArray(int index, byte[] data, int start, int length) {
        final int oldIndex = this.buf.writerIndex();
        this.buf.writerIndex(index);
        writeVarInt(length);
        writeBytes(data, start, length);
        this.buf.writerIndex(oldIndex);
        return this;
    }

    @Override
    public byte[] readLimitedByteArray(int maxLength) throws DecoderException {
        final int length = readVarInt();
        if (length < 0) {
            throw new DecoderException("Byte array length may not be negative.");
        }
        if (length > maxLength) {
            throw new DecoderException(
                    "Exceeded the maximum allowed length, got " + length + " which is greater then " + maxLength);
        }
        final byte[] bytes = new byte[length];
        this.buf.readBytes(bytes);
        return bytes;
    }

    @Override
    public byte[] readByteArray() {
        return readLimitedByteArray(Integer.MAX_VALUE);
    }

    @Override
    public byte[] readByteArray(int index) {
        final int oldIndex = this.buf.readerIndex();
        this.buf.readerIndex(index);
        final byte[] data = readByteArray();
        this.buf.readerIndex(oldIndex);
        return data;
    }

    @Override
    public LanternByteBuffer writeBytes(byte[] data) {
        this.buf.writeBytes(data);
        return this;
    }

    @Override
    public LanternByteBuffer writeBytes(byte[] data, int start, int length) {
        this.buf.writeBytes(data, start, length);
        return this;
    }

    @Override
    public LanternByteBuffer setBytes(int index, byte[] data) {
        final int oldIndex = this.buf.writerIndex();
        this.buf.writerIndex(index);
        this.buf.writeBytes(data);
        this.buf.writerIndex(oldIndex);
        return this;
    }

    @Override
    public LanternByteBuffer setBytes(int index, byte[] data, int start, int length) {
        final int oldIndex = this.buf.writerIndex();
        this.buf.writerIndex(index);
        this.buf.writeBytes(data, start, length);
        this.buf.writerIndex(oldIndex);
        return this;
    }

    @Override
    public byte[] readBytes(int length) {
        final byte[] data = new byte[length];
        this.buf.readBytes(data);
        return data;
    }

    @Override
    public byte[] readBytes(int index, int length) {
        final int oldIndex = this.buf.readerIndex();
        this.buf.readerIndex(index);
        final byte[] data = new byte[length];
        this.buf.readBytes(data);
        this.buf.readerIndex(oldIndex);
        return data;
    }

    @Override
    public LanternByteBuffer writeShort(short data) {
        this.buf.writeShort(data);
        return this;
    }

    @Override
    public LanternByteBuffer setShort(int index, short data) {
        this.buf.setShort(index, data);
        return this;
    }

    @Override
    public short readShort() {
        return this.buf.readShort();
    }

    @Override
    public short getShort(int index) {
        return this.buf.getShort(index);
    }

    @Override
    public LanternByteBuffer writeChar(char data) {
        this.buf.writeChar(data);
        return this;
    }

    @Override
    public LanternByteBuffer setChar(int index, char data) {
        this.buf.setChar(index, data);
        return this;
    }

    @Override
    public char readChar() {
        return this.buf.readChar();
    }

    @Override
    public char getChar(int index) {
        return this.buf.getChar(index);
    }

    @Override
    public LanternByteBuffer writeInteger(int data) {
        this.buf.writeInt(data);
        return this;
    }

    @Override
    public LanternByteBuffer setInteger(int index, int data) {
        this.buf.setInt(index, data);
        return this;
    }

    @Override
    public int readInteger() {
        return this.buf.readInt();
    }

    @Override
    public int getInteger(int index) {
        return this.buf.getInt(index);
    }

    @Override
    public LanternByteBuffer writeLong(long data) {
        this.buf.writeLong(data);
        return this;
    }

    @Override
    public LanternByteBuffer setLong(int index, long data) {
        this.buf.setLong(index, data);
        return this;
    }

    @Override
    public long readLong() {
        return this.buf.readLong();
    }

    @Override
    public long getLong(int index) {
        return this.buf.getLong(index);
    }

    @Override
    public LanternByteBuffer writeFloat(float data) {
        this.buf.writeFloat(data);
        return this;
    }

    @Override
    public LanternByteBuffer setFloat(int index, float data) {
        this.buf.setFloat(index, data);
        return this;
    }

    @Override
    public float readFloat() {
        return this.buf.readFloat();
    }

    @Override
    public float getFloat(int index) {
        return this.buf.getFloat(index);
    }

    @Override
    public LanternByteBuffer writeDouble(double data) {
        this.buf.writeDouble(data);
        return this;
    }

    @Override
    public LanternByteBuffer setDouble(int index, double data) {
        this.buf.setDouble(index, data);
        return this;
    }

    @Override
    public double readDouble() {
        return this.buf.readDouble();
    }

    @Override
    public double getDouble(int index) {
        return this.buf.getDouble(index);
    }

    public static void writeVarInt(ByteBuf byteBuf, int value) {
        while ((value & 0xFFFFFF80) != 0L) {
            byteBuf.writeByte((value & 0x7F) | 0x80);
            value >>>= 7;
        }
        byteBuf.writeByte(value & 0x7F);
    }

    public static int readVarInt(ByteBuf byteBuf) {
        int value = 0;
        int i = 0;
        int b;
        while (((b = byteBuf.readByte()) & 0x80) != 0) {
            value |= (b & 0x7F) << i;
            i += 7;
            if (i > 35) {
                throw new DecoderException("Variable length is too long!");
            }
        }
        return value | (b << i);
    }

    @Override
    public LanternByteBuffer writeVarInt(int value) {
        writeVarInt(this.buf, value);
        return this;
    }

    @Override
    public LanternByteBuffer setVarInt(int index, int value) {
        int oldIndex = this.buf.writerIndex();
        this.buf.writerIndex(index);
        this.writeVarInt(value);
        this.buf.writerIndex(oldIndex);
        return this;
    }

    @Override
    public int readVarInt() {
        return readVarInt(this.buf);
    }

    @Override
    public int getVarInt(int index) {
        final int oldIndex = this.buf.readerIndex();
        this.buf.readerIndex(index);
        final int data = readVarInt();
        this.buf.readerIndex(oldIndex);
        return data;
    }

    @Override
    public LanternByteBuffer writeString(String data) {
        writeByteArray(data.getBytes(StandardCharsets.UTF_8));
        return this;
    }

    @Override
    public LanternByteBuffer setString(int index, String data) {
        setByteArray(index, data.getBytes(StandardCharsets.UTF_8));
        return this;
    }

    @Override
    public String readLimitedString(int maxLength) throws DecoderException {
        return new String(readLimitedByteArray(maxLength * 4), StandardCharsets.UTF_8);
    }

    @Override
    public String readString() {
        return readLimitedString(Short.MAX_VALUE);
    }

    @Override
    public String getString(int index) {
        return new String(readByteArray(index), StandardCharsets.UTF_8);
    }

    @Override
    public LanternByteBuffer writeUTF(String data) {
        final byte[] bytes = data.getBytes(StandardCharsets.UTF_8);
        if (bytes.length > 32767) {
            throw new EncoderException(
                    "String too big (was " + data.length() + " bytes encoded, max " + 32767 + ")");
        }
        this.buf.writeShort(bytes.length);
        this.buf.writeBytes(bytes);
        return this;
    }

    @Override
    public LanternByteBuffer setUTF(int index, String data) {
        checkNotNull(data, "data");
        final int oldIndex = this.buf.writerIndex();
        this.buf.writerIndex(index);
        writeUTF(data);
        this.buf.writerIndex(oldIndex);
        return this;
    }

    @Override
    public String readUTF() {
        final int length = readShort();
        return new String(readBytes(length), StandardCharsets.UTF_8);
    }

    @Override
    public String getUTF(int index) {
        final int oldIndex = this.buf.readerIndex();
        this.buf.readerIndex(index);
        final String data = readUTF();
        this.buf.readerIndex(oldIndex);
        return data;
    }

    @Override
    public LanternByteBuffer writeUniqueId(UUID data) {
        this.buf.writeLong(data.getMostSignificantBits());
        this.buf.writeLong(data.getLeastSignificantBits());
        return this;
    }

    @Override
    public LanternByteBuffer setUniqueId(int index, UUID data) {
        final int oldIndex = this.buf.writerIndex();
        this.buf.writerIndex(index);
        writeUniqueId(data);
        this.buf.writerIndex(oldIndex);
        return this;
    }

    @Override
    public UUID readUniqueId() {
        final long most = this.buf.readLong();
        final long least = this.buf.readLong();
        return new UUID(most, least);
    }

    @Override
    public UUID getUniqueId(int index) {
        final int oldIndex = this.buf.readerIndex();
        this.buf.readerIndex(index);
        final UUID data = readUniqueId();
        this.buf.readerIndex(oldIndex);
        return data;
    }

    @Override
    public LanternByteBuffer writeDataView(@Nullable DataView data) {
        if (data == null) {
            this.buf.writeByte(0);
            return this;
        }
        try {
            NbtStreamUtils.write(data, new ByteBufOutputStream(this.buf), false);
        } catch (IOException e) {
            throw new CodecException(e);
        }
        return this;
    }

    @Override
    public LanternByteBuffer setDataView(int index, @Nullable DataView data) {
        final int oldIndex = this.buf.writerIndex();
        this.buf.writerIndex(index);
        writeDataView(data);
        this.buf.writerIndex(oldIndex);
        return this;
    }

    @Nullable
    @Override
    public DataView readLimitedDataView(int maximumDepth, int maxBytes) {
        final int index = this.buf.readerIndex();
        if (this.buf.readByte() == 0) {
            return null;
        }
        this.buf.readerIndex(index);
        try {
            try (NbtDataContainerInputStream input = new NbtDataContainerInputStream(
                    new LimitInputStream(new ByteBufInputStream(this.buf), maxBytes), false, maximumDepth)) {
                return input.read();
            }
        } catch (IOException e) {
            throw new CodecException(e);
        }
    }

    @Nullable
    @Override
    public DataView readDataView() {
        return readLimitedDataView(Integer.MAX_VALUE, Integer.MAX_VALUE);
    }

    @Nullable
    @Override
    public DataView getDataView(int index) {
        final int oldIndex = this.buf.readerIndex();
        this.buf.readerIndex(index);
        final DataView data = readDataView();
        this.buf.readerIndex(oldIndex);
        return data;
    }

    @Override
    public ByteBuffer writeBytes(ByteBuffer byteBuffer) {
        this.buf.writeBytes(((LanternByteBuffer) byteBuffer).getDelegate());
        return this;
    }

    @Override
    public ByteBuffer readBytes(byte[] byteArray) {
        this.buf.readBytes(byteArray);
        return this;
    }

    @Override
    public ByteBuffer readBytes(byte[] dst, int dstIndex, int length) {
        this.buf.readBytes(dst, dstIndex, length);
        return this;
    }

    @Override
    public ByteBuffer readBytes(ByteBuffer byteBuffer) {
        this.buf.readBytes(((LanternByteBuffer) byteBuffer).getDelegate());
        return this;
    }

    @Override
    public ByteBuffer readBytes(ByteBuffer dst, int dstIndex, int length) {
        this.buf.readBytes(((LanternByteBuffer) dst).getDelegate(), dstIndex, length);
        return this;
    }

    @Override
    public LanternByteBuffer writeVarLong(long value) {
        while ((value & 0xFFFFFFFFFFFFFF80L) != 0L) {
            this.buf.writeByte(((int) value & 0x7F) | 0x80);
            value >>>= 7;
        }
        this.buf.writeByte((int) value & 0x7F);
        return this;
    }

    @Override
    public LanternByteBuffer setVarLong(int index, long value) {
        final int oldIndex = this.buf.writerIndex();
        this.buf.writerIndex(index);
        writeVarLong(value);
        this.buf.writerIndex(oldIndex);
        return this;
    }

    @Override
    public long readVarLong() {
        long value = 0L;
        int i = 0;
        long b;
        while (((b = this.buf.readByte()) & 0x80L) != 0) {
            value |= (b & 0x7F) << i;
            i += 7;
            if (i > 63) {
                throw new DecoderException("Variable length is too long!");
            }
        }
        return value | (b << i);
    }

    @Override
    public long getVarLong(int index) {
        final int oldIndex = this.buf.readerIndex();
        this.buf.readerIndex(index);
        final long data = readVarLong();
        this.buf.readerIndex(oldIndex);
        return data;
    }

    @Override
    public <V> LanternByteBuffer write(Type<V> type, V value) {
        type.getSerializer().write(this, value);
        return this;
    }

    @Override
    public <V> LanternByteBuffer set(int index, Type<V> type, V value) {
        final int oldIndex = this.buf.writerIndex();
        this.buf.writerIndex(index);
        write(type, value);
        this.buf.writerIndex(oldIndex);
        return this;
    }

    @Override
    public <V> V read(Type<V> type) {
        return type.getSerializer().read(this);
    }

    @Override
    public <V> V get(int index, Type<V> type) {
        final int oldIndex = this.buf.readerIndex();
        this.buf.readerIndex(index);
        final V data = read(type);
        this.buf.readerIndex(oldIndex);
        return data;
    }

    @Override
    public LanternByteBuffer ensureWritable(int minWritableBytes) {
        this.buf.ensureWritable(minWritableBytes);
        return this;
    }

    @Override
    public boolean release() {
        return this.buf.release();
    }

    @Override
    public boolean release(int decrement) {
        return this.buf.release(decrement);
    }

    @Override
    public LanternByteBuffer copy() {
        return new LanternByteBuffer(this.buf.copy());
    }
}