0

I have been working on a program that can connect to a Minecraft Server and exchange packets with it but Minecraft's server packets heavily rely on signed VarInts. On the site documenting how their communication works is explanation of VarInt and even an example implementation of them in Java:

So i followed it and it works for non negative numbers but for negative numbers it's just goes infinitely long. I serched for other means of implementing it but i couldn't find any.

Here is my version it (works as i said only for positive numbers which is not fully what i want)

class VarInt
{
public:
    char* data = NULL;
    int length = 0;

    int Read();
    void Write(int value);

    ~VarInt();
private:
    int SEGMENT_BIT_MASK = 0x7F;
    int CONTINUE_BIT_MASK = 0x80;

};

int VarInt::Read()
{
    int value = 0;
    int position = 0;
    byte currentByte;

    int i = 0;
    while (true)
    {
        currentByte = data[i];
        value |= (currentByte & SEGMENT_BIT_MASK) << position;

        if ((currentByte & CONTINUE_BIT_MASK) == 0)
            break;

        i++;
        position += 7;

        if (position >= 32)
            std::cout << "VarInt is too Big" << std::endl;
    }
    return value;
};

void VarInt::Write(int value)
{
    bool state = true;
    std::vector<byte> bytes;

    while (state)
    {
        if ((value & ~SEGMENT_BIT_MASK) == 0)
        {
            bytes.push_back(value);
            state = false;
            break;
        }
        bytes.push_back(((value & SEGMENT_BIT_MASK) | CONTINUE_BIT_MASK));
        value >>= 7;
    }

    int bytes_size = bytes.size();

    length = bytes_size;
    data = (char*)malloc(bytes_size);

    int i = 0;
    while (i != bytes_size)
    {
        data[i] = bytes.at(i);
        i++;
    }
};

VarInt::~VarInt()
{

};

And here are my means of testing it:

#include <iostream>
#include "MDatatypes.h"

int main()
{
    ndt::VarInt test;
    //Sets value of test to -127
    test.Write(-127);

    //Sets value of test2 to 255
    ndt::VarInt test2;
    test2.Write(255);

    //Outputing length of each Varint in bytes
    std::cout << test.length << '|' << test2.length << std::endl;
    //Outputing the values of each Varint
    std::cout << test.Read() << '|' << test2.Read() << std::endl;
}
  • Tip: In C++ use `nullptr` in preference to C's typeless `NULL`. – tadman Aug 05 '22 at 20:22
  • Can you use `std::vector` instead of manual allocation? Using `malloc` in C++ code is generally bad form when `new[]` is right there. – tadman Aug 05 '22 at 20:23
  • Can you use a library like [Google Protocol Buffers](https://developers.google.com/protocol-buffers/docs/encoding) which already has an implementation? – tadman Aug 05 '22 at 20:25
  • @tadman I could but i prefer not to when I know the size and that it won't change – themakabrapl Aug 05 '22 at 20:29
  • Why not `std::array` then? These containers are very low cost and can be used for that sort of thing without worrying. It also saves you the hassle of tracking ownership and implementing a destructor. This code has a lot of undefined behavior baked in due to uninitialized variables. It looks like `Write` should actually be your constructor. – tadman Aug 05 '22 at 20:32
  • You're already using `std::vector` in there, and then manually crunching the data over. Remember, in C++ you have [`std::move`](https://en.cppreference.com/w/cpp/utility/move) and other tools to do that for you. – tadman Aug 05 '22 at 20:33
  • As far as negative numbers not working right, just cast to `uint32_t` (or `uint64_t`) before converting. – Miles Budnek Aug 05 '22 at 22:44
  • 1
    @tadman I will look into Protocol Buffers thanks – themakabrapl Aug 06 '22 at 20:57

0 Answers0