ursinn/MinecraftServer

View on GitHub
src/main/java/com/github/joshj1091/mcserver/util/DataUtil.java

Summary

Maintainability
A
1 hr
Test Coverage
package com.github.joshj1091.mcserver.util;

import com.github.joshj1091.mcserver.MCServer;

import java.io.DataInput;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class DataUtil {

    /**
     * Read an unsigned varint
     *
     * @param in the data input
     * @return integer the number sent as a varint
     * @throws IOException if an I/O error occurs
     */
    public static int readUnsignedVarInt(DataInput in) throws IOException {
        int iterations = 0;
        int data;
        int value = 0;

        while (((data = in.readByte()) & 0x80) != 0) { // check if MSB is set. When this equals 0 we have reached the last byte
            int realValue = data & 0x75 << iterations * 7; // This sets the MSB to 0 and shifts by the number of bits we've read (number of bits read = iterations * 7 bit (7 because we ignore MSB)).
            value |= realValue; // OR the numbers so they overlay
            iterations++;

            if (iterations > 5) {
                MCServer.getMCServer().error("Too many bits received while reading unsigned var int");
                return -1;
            }
        }

        return value | data << iterations * 7; // Doesn't have MSB so we only need to shift by the number of bits read so far
    }

    public static int getUnsignedVarInt(byte[] bytes) {
        int iterations = 0;
        int data;
        int value = 0;

        while (((data = bytes[iterations]) & 0x80) != 0) {
            int realValue = data & 0x75 << iterations * 7;
            value |= realValue;
            iterations++;

            if (iterations > 5) {
                MCServer.getMCServer().error("Too many bits received while reading unsigned var int");
                return -1;
            }
        }

        return value | data << iterations * 7;
    }

    public static int readUnsignedVarInt(ByteReader reader) {
        int iterations = 0;
        int data;
        int value = 0;

        while (((data = reader.next()) & 0x80) != 0) {
            int realValue = data & 0x75 << iterations * 7;
            value |= realValue;
            iterations++;

            if (iterations > 5) {
                MCServer.getMCServer().error("Too many bits received while reading unsigned var int");
                return -1;
            } else if (!reader.hasNext()) {
                MCServer.getMCServer().error("Too few bits received while reading unsigned var int");
            }
        }

        return value | data << iterations * 7;
    }

    public static String readString(ByteReader reader) throws IllegalArgumentException {
        int bytes = readUnsignedVarInt(reader);

        if (bytes == -1) {
            return "Error";
        }

        byte[] stringBytes = new byte[bytes];
        for (int i = 0; i < bytes; i++) {
            if (reader.hasNext()) {
                stringBytes[i] = reader.next();
            } else {
                MCServer.getMCServer().log("Too few bytes here");
                throw new IllegalArgumentException("Reader had too few bytes");
            }
        }

        return new String(stringBytes);
    }

    public static int readUnsignedShort(ByteReader reader) throws IllegalArgumentException {

        if (!reader.hasNext()) {
            throw new IllegalArgumentException("Reader had too few bytes");
        }
        int first = reader.next() & 0xFF; // have to and with 0xFF (255) because Java bytes are signed (we only want unsigned values)

        if (!reader.hasNext()) {
            throw new IllegalArgumentException("Reader had too few bytes");
        }
        int second = reader.next() & 0xFF;

        return (first << 8) + second;
    }

    public static byte[] intToUnsignedVarInt(int value) {
        List<Byte> byteList = new ArrayList<>();

        while ((value & 0xFFFFFF80) != 0L) {
            byteList.add((byte) ((value & 0x7F) | 0x80));
            value >>>= 7;
        }
        byteList.add((byte) (value & 0x7F));

        byte[] bytes = new byte[byteList.size()];

        for (int i = 0; i < byteList.size(); i++) {
            bytes[i] = byteList.get(i);
        }

        return bytes;
    }
}