Porting serializer from C# to C (VLQ w/ ZigZag)

1

I've encountered a strange behavior while porting serializer from C# to C which utilizes VLQ and ZigZag under the hood based on integers family. I think the ported code is technically correct, but on practice encoded data is always less for one byte than with the original C# implementation, and this breaks everything: data is serialized/deserialized incorrectly when large integer numbers are used. I've spent 2 days trying to find a mistake, but still, I can't determine it... Any help is much appreciated.

Original implementation in C#:

using System;
using System.Runtime.CompilerServices;
using System.Text;

public class BitBuffer {
    private const int defaultCapacity = 8;
    private const int stringLengthMax = 512;
    private const int stringLengthBits = 9;
    private const int bitsASCII = 7;
    private const int growFactor = 2;
    private const int minGrow = 1;
    private int readPosition;
    private int nextPosition;
    private uint[] chunks;

    public BitBuffer(int capacity = defaultCapacity) {
        readPosition = 0;
        nextPosition = 0;
        chunks = new uint[capacity];
    }

    public int Length {
        get {
            return ((nextPosition - 1) >> 3) + 1;
        }
    }

    public bool IsFinished {
        get {
            return nextPosition == readPosition;
        }
    }

    public void Clear() {
        readPosition = 0;
        nextPosition = 0;
    }

    public void Add(int numBits, uint value) {
        if (numBits < 0)
            throw new ArgumentOutOfRangeException("Pushing negative bits");

        if (numBits > 32)
            throw new ArgumentOutOfRangeException("Pushing too many bits");

        int index = nextPosition >> 5;
        int used = nextPosition & 0x0000001F;

        if ((index + 1) >= chunks.Length)
            ExpandArray();

        ulong chunkMask = ((1UL << used) - 1);
        ulong scratch = chunks[index] & chunkMask;
        ulong result = scratch | ((ulong)value << used);

        chunks[index] = (uint)result;
        chunks[index + 1] = (uint)(result >> 32);
        nextPosition += numBits;
    }

    public uint Read(int numBits) {
        uint result = Peek(numBits);

        readPosition += numBits;

        return result;
    }

    public uint Peek(int numBits) {
        if (numBits < 0)
            throw new ArgumentOutOfRangeException("Pushing negative bits");

        if (numBits > 32)
            throw new ArgumentOutOfRangeException("Pushing too many bits");

        int index = readPosition >> 5;
        int used = readPosition & 0x0000001F;

        ulong chunkMask = ((1UL << numBits) - 1) << used;
        ulong scratch = (ulong)chunks[index];

        if ((index + 1) < chunks.Length)
            scratch |= (ulong)chunks[index + 1] << 32;

        ulong result = (scratch & chunkMask) >> used;

        return (uint)result;
    }

    public int ToArray(byte[] data) {
        Add(1, 1);

        int numChunks = (nextPosition >> 5) + 1;
        int length = data.Length;

        for (int i = 0; i < numChunks; i++) {
            int dataIdx = i * 4;
            uint chunk = chunks[i];

            if (dataIdx < length)
                data[dataIdx] = (byte)(chunk);

            if (dataIdx + 1 < length)
                data[dataIdx + 1] = (byte)(chunk >> 8);

            if (dataIdx + 2 < length)
                data[dataIdx + 2] = (byte)(chunk >> 16);

            if (dataIdx + 3 < length)
                data[dataIdx + 3] = (byte)(chunk >> 24);
        }

        return Length;
    }

    public void FromArray(byte[] data, int length) {
        int numChunks = (length / 4) + 1;

        if (chunks.Length < numChunks)
            chunks = new uint[numChunks];

        for (int i = 0; i < numChunks; i++) {
            int dataIdx = i * 4;
            uint chunk = 0;

            if (dataIdx < length)
                chunk = (uint)data[dataIdx];

            if (dataIdx + 1 < length)
                chunk = chunk | (uint)data[dataIdx + 1] << 8;

            if (dataIdx + 2 < length)
                chunk = chunk | (uint)data[dataIdx + 2] << 16;

            if (dataIdx + 3 < length)
                chunk = chunk | (uint)data[dataIdx + 3] << 24;

            chunks[i] = chunk;
        }

        int positionInByte = FindHighestBitPosition(data[length - 1]);

        nextPosition = ((length - 1) * 8) + (positionInByte - 1);
        readPosition = 0;
    }

    public BitBuffer AddBool(bool value) {
        Add(1, value ? 1U : 0U);

        return this;
    }

    public bool ReadBool() {
        return Read(1) > 0;
    }

    public bool PeekBool() {
        return Peek(1) > 0;
    }

    public BitBuffer AddByte(byte value) {
        Add(8, value);

        return this;
    }

    public byte ReadByte() {
        return (byte)Read(8);
    }

    public byte PeekByte() {
        return (byte)Peek(8);
    }

    public BitBuffer AddShort(short value) {
        AddInt(value);

        return this;
    }

    public short ReadShort() {
        return (short)ReadInt();
    }

    public short PeekShort() {
        return (short)PeekInt();
    }

    public BitBuffer AddUShort(ushort value) {
        AddUInt(value);

        return this;
    }

    public ushort ReadUShort() {
        return (ushort)ReadUInt();
    }

    public ushort PeekUShort() {
        return (ushort)PeekUInt();
    }

    public BitBuffer AddInt(int value) {
        uint zigzag = (uint)((value << 1) ^ (value >> 31));

        AddUInt(zigzag);

        return this;
    }

    public int ReadInt() {
        uint value = ReadUInt();
        int zagzig = (int)((value >> 1) ^ (-(value & 1)));

        return zagzig;
    }

    public int PeekInt() {
        uint value = PeekUInt();
        int zagzig = (int)((value >> 1) ^ (-(value & 1)));

        return zagzig;
    }

    public BitBuffer AddUInt(uint value) {
        uint buffer = 0x0u;

        do {
            buffer = value & 0x7Fu;
            value >>= 7;

            if (value > 0)
                buffer |= 0x80u;

            Add(8, buffer);
        }

        while (value > 0);

        return this;
    }

    public uint ReadUInt() {
        uint buffer = 0x0u;
        uint value = 0x0u;
        int shift = 0;

        do {
            buffer = Read(8);

            value |= (buffer & 0x7Fu) << shift;
            shift += 7;
        }

        while ((buffer & 0x80u) > 0);

        return value;
    }

    public uint PeekUInt() {
        int tempPosition = readPosition;
        uint value = ReadUInt();

        readPosition = tempPosition;

        return value;
    }

    public BitBuffer AddString(string value) {
        if (value == null)
            throw new ArgumentNullException("value");

        uint length = (uint)value.Length;

        if (value.Length > stringLengthMax)
            length = (uint)stringLengthMax;

        Add(stringLengthBits, length);

        for (int i = 0; i < length; i++) {
            Add(bitsASCII, ToASCII(value[i]));
        }

        return this;
    }

    public string ReadString() {
        StringBuilder builder = new StringBuilder();
        uint length = Read(stringLengthBits);

        for (int i = 0; i < length; i++) {
            builder.Append((char)Read(bitsASCII));
        }

        return builder.ToString();
    }

    public override string ToString() {
        StringBuilder builder = new StringBuilder();

        for (int i = chunks.Length - 1; i >= 0; i--) {
            builder.Append(Convert.ToString(chunks[i], 2).PadLeft(32, '0'));
        }

        StringBuilder spaced = new StringBuilder();

        for (int i = 0; i < builder.Length; i++) {
            spaced.Append(builder[i]);

            if (((i + 1) % 8) == 0)
                spaced.Append(" ");
        }

        return spaced.ToString();
    }

    private void ExpandArray() {
        int newCapacity = (chunks.Length * growFactor) + minGrow;
        uint[] newChunks = new uint[newCapacity];

        Array.Copy(chunks, newChunks, chunks.Length);
        chunks = newChunks;
    }

    private static int FindHighestBitPosition(byte data) {
        int shiftCount = 0;

        while (data > 0) {
            data >>= 1;
            shiftCount++;
        }

        return shiftCount;
    }

    private static byte ToASCII(char character) {
        byte value = 0;

        try {
            value = Convert.ToByte(character);
        }

        catch (OverflowException) {
            throw new Exception("Cannot convert to ASCII: " + character);
        }

        if (value > 127)
            throw new Exception("Cannot convert to ASCII: " + character);

        return value;
    }
}

Ported implementation in C:

#ifndef BITBUFFER_H
#define BITBUFFER_H

#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#define BITBUFFER_VERSION_MAJOR 1
#define BITBUFFER_VERSION_MINOR 0
#define BITBUFFER_VERSION_PATCH 0

#define BITBUFFER_DEFAULT_CAPACITY 8
#define BITBUFFER_STRING_LENGTH_MAX 512
#define BITBUFFER_STRING_LENGTH_BITS 9
#define BITBUFFER_BITS_ASCII 7
#define BITBUFFER_GROW_FACTOR 2
#define BITBUFFER_MIN_GROW 1

#define BITBUFFER_OK 0
#define BITBUFFER_ERROR -1
#define BITBUFFER_TOO_MANY_BITS_ERROR 500

#if defined(_WIN32) && defined(BITBUFFER_DLL)
    #define BITBUFFER_API __declspec(dllexport)
#else
    #define BITBUFFER_API extern
#endif

// API

#ifdef __cplusplus
extern "C" {
#endif

    typedef struct _BitBuffer {
        int readPosition;
        int nextPosition;
        uint32_t* chunks;
        int length;
    } BitBuffer;

    // Public API

    BITBUFFER_API int bitbuffer_create(BitBuffer*);

    BITBUFFER_API int bitbuffer_create_capacity(BitBuffer*, uint32_t);

    BITBUFFER_API int bitbuffer_destroy(BitBuffer*);

    BITBUFFER_API int bitbuffer_length(BitBuffer*);

    BITBUFFER_API bool bitbuffer_is_finished(BitBuffer*);

    BITBUFFER_API int bitbuffer_clear(BitBuffer*);

    BITBUFFER_API int bitbuffer_add(BitBuffer*, int, uint32_t);

    BITBUFFER_API int bitbuffer_read(BitBuffer*, int);

    BITBUFFER_API uint32_t bitbuffer_peek(BitBuffer*, int);

    BITBUFFER_API int bitbuffer_to_array(BitBuffer*, uint8_t*, int);

    BITBUFFER_API void bitbuffer_from_array(BitBuffer*, const uint8_t*, int);

    BITBUFFER_API int bitbuffer_add_bool(BitBuffer*, bool);

    BITBUFFER_API bool bitbuffer_read_bool(BitBuffer*);

    BITBUFFER_API bool bitbuffer_peek_bool(BitBuffer*);

    BITBUFFER_API int bitbuffer_add_byte(BitBuffer*, uint8_t);

    BITBUFFER_API uint8_t bitbuffer_read_byte(BitBuffer*);

    BITBUFFER_API uint8_t bitbuffer_peek_byte(BitBuffer*);

    BITBUFFER_API int bitbuffer_add_short(BitBuffer*, int16_t);

    BITBUFFER_API int16_t bitbuffer_read_short(BitBuffer*);

    BITBUFFER_API int16_t bitbuffer_peek_short(BitBuffer*);

    BITBUFFER_API int bitbuffer_add_ushort(BitBuffer*, uint16_t);

    BITBUFFER_API uint16_t bitbuffer_read_ushort(BitBuffer*);

    BITBUFFER_API uint16_t bitbuffer_peek_ushort(BitBuffer*);

    BITBUFFER_API int bitbuffer_add_int(BitBuffer*, int);

    BITBUFFER_API int bitbuffer_read_int(BitBuffer*);

    BITBUFFER_API int bitbuffer_peek_int(BitBuffer*);

    BITBUFFER_API int bitbuffer_add_uint(BitBuffer*, uint32_t);

    BITBUFFER_API uint32_t bitbuffer_read_uint(BitBuffer*);

    BITBUFFER_API uint32_t bitbuffer_peek_uint(BitBuffer*);



    // Private API

    static void bitbuffer_expand_array(BitBuffer*);

    static int bitbuffer_find_highest_bit_position(uint8_t);

    static uint8_t bitbuffer_to_ascii(char);

#ifdef __cplusplus
}
#endif

#if defined(BITBUFFER_IMPLEMENTATION) && !defined(BITBUFFER_IMPLEMENTATION_DONE)
#define BITBUFFER_IMPLEMENTATION_DONE
#ifdef __cplusplus
extern "C" {
#endif

    // Functions

    int bitbuffer_create(BitBuffer* bitbuffer) {
        return bitbuffer_create_capacity(bitbuffer, BITBUFFER_DEFAULT_CAPACITY);
    }

    int bitbuffer_create_capacity(BitBuffer* bitbuffer, uint32_t capacity) {
        assert(bitbuffer != NULL);

        if (bitbuffer == NULL)
            return BITBUFFER_ERROR;

        bitbuffer->readPosition = 0;
        bitbuffer->nextPosition = 0;
        bitbuffer->chunks = malloc(capacity * sizeof(uint32_t));
        bitbuffer->length = capacity;

        return bitbuffer->chunks != NULL ? BITBUFFER_OK : BITBUFFER_ERROR;
    }

    int bitbuffer_destroy(BitBuffer* bitbuffer) {
        assert(bitbuffer != NULL);

        if (bitbuffer == NULL)
            return BITBUFFER_ERROR;

        free(bitbuffer->chunks);

        bitbuffer->chunks = NULL;

        return BITBUFFER_OK;
    }

    int bitbuffer_length(BitBuffer* bitbuffer) {
        assert(bitbuffer != NULL);

        return ((bitbuffer->nextPosition - 1) >> 3) + 1;
    }

    bool bitbuffer_is_finished(BitBuffer* bitbuffer) {
        assert(bitbuffer != NULL);

        return bitbuffer->nextPosition == bitbuffer->readPosition;
    }

    int bitbuffer_clear(BitBuffer* bitbuffer) {
        assert(bitbuffer != NULL);

        if (bitbuffer == NULL)
            return BITBUFFER_ERROR;

        bitbuffer->nextPosition = 0;
        bitbuffer->readPosition = 0;
        bitbuffer->length = 0;

        return BITBUFFER_OK;
    }

    int bitbuffer_add(BitBuffer* bitbuffer, int numBits, uint32_t value) {
        assert(bitbuffer != NULL);
        assert(numBits >= 0);
        assert(numBits <= 32);

        if (bitbuffer == NULL)
            return BITBUFFER_ERROR;

        if (numBits > 32)
            return BITBUFFER_TOO_MANY_BITS_ERROR;

        int index = bitbuffer->nextPosition >> 5;
        int used = bitbuffer->nextPosition & 0x0000001F;

        if ((index + 1) >= bitbuffer->length)
            bitbuffer_expand_array(bitbuffer);

        uint64_t chunkMask = ((1UL << used) - 1);
        uint64_t scratch = bitbuffer->chunks[index] & chunkMask;
        uint64_t result = scratch | ((uint64_t)value << used);

        bitbuffer->chunks[index] = (uint32_t)result;
        bitbuffer->chunks[index + 1] = (uint32_t)(result >> 32);
        bitbuffer->nextPosition += numBits;

        return BITBUFFER_OK;
    }

    int bitbuffer_read(BitBuffer* bitbuffer, int numBits) {
        uint32_t result = bitbuffer_peek(bitbuffer, numBits);

        bitbuffer->readPosition += numBits;

        return result;
    }

    uint32_t bitbuffer_peek(BitBuffer* bitbuffer, int numBits) {
        assert(bitbuffer != NULL);
        assert(numBits >= 0);
        assert(numBits <= 32);

        int index = bitbuffer->readPosition >> 5;
        int used = bitbuffer->readPosition & 0x0000001F;

        uint64_t chunkMask = ((1UL << numBits) - 1) << used;
        uint64_t scratch = (uint64_t)bitbuffer->chunks[index];

        if ((index + 1) < bitbuffer->length)
            scratch |= (uint64_t)bitbuffer->chunks[index + 1] << 32;

        uint64_t result = (scratch & chunkMask) >> used;

        return (uint32_t)result;
    }

    int bitbuffer_to_array(BitBuffer* bitbuffer, uint8_t* data, int length) {
        assert(bitbuffer != NULL);
        assert(data != NULL);
        assert(length > 0);

        bitbuffer_add(bitbuffer, 1, 1);

        int numChunks = (bitbuffer->nextPosition >> 5) + 1;

        for (int i = 0; i < numChunks; i++) {
            int dataIdx = i * 4;
            uint32_t chunk = bitbuffer->chunks[i];

            if (dataIdx < length)
                data[dataIdx] = (uint8_t)(chunk);

            if (dataIdx + 1 < length)
                data[dataIdx + 1] = (uint8_t)(chunk >> 8);

            if (dataIdx + 2 < length)
                data[dataIdx + 2] = (uint8_t)(chunk >> 16);

            if (dataIdx + 3 < length)
                data[dataIdx + 3] = (uint8_t)(chunk >> 24);
        }

        return bitbuffer_length(bitbuffer);
    }

    void bitbuffer_from_array(BitBuffer* bitbuffer, const uint8_t* data, int length) {
        assert(bitbuffer != NULL);
        assert(data != NULL);
        assert(length > 0);

        int numChunks = (length / 4) + 1;

        if (bitbuffer->length < numChunks)
            bitbuffer->chunks = realloc(bitbuffer->chunks, numChunks * sizeof(uint32_t));

        for (int i = 0; i < numChunks; i++) {
            int dataIdx = i * 4;
            uint32_t chunk = 0;

            if (dataIdx < length)
                chunk = (uint32_t)data[dataIdx];

            if (dataIdx + 1 < length)
                chunk = chunk | (uint32_t)data[dataIdx + 1] << 8;

            if (dataIdx + 2 < length)
                chunk = chunk | (uint32_t)data[dataIdx + 2] << 16;

            if (dataIdx + 3 < length)
                chunk = chunk | (uint32_t)data[dataIdx + 3] << 24;

            bitbuffer->chunks[i] = chunk;
        }

        int positionInByte = bitbuffer_find_highest_bit_position(data[length - 1]);

        bitbuffer->nextPosition = ((length - 1) * 8) + (positionInByte - 1);
        bitbuffer->readPosition = 0;
    }

    inline int bitbuffer_add_bool(BitBuffer* bitbuffer, bool value) {
        assert(bitbuffer != NULL);

        return bitbuffer_add(bitbuffer, 1, value ? 1U : 0U);
    }

    inline bool bitbuffer_read_bool(BitBuffer* bitbuffer) {
        assert(bitbuffer != NULL);

        return bitbuffer_read(bitbuffer, 1) > 0;
    }

    inline bool bitbuffer_peek_bool(BitBuffer* bitbuffer) {
        assert(bitbuffer != NULL);

        return bitbuffer_peek(bitbuffer, 1) > 0;
    }

    inline int bitbuffer_add_byte(BitBuffer* bitbuffer, uint8_t value) {
        assert(bitbuffer != NULL);

        return bitbuffer_add(bitbuffer, 8, value);
    }

    inline uint8_t bitbuffer_read_byte(BitBuffer* bitbuffer) {
        assert(bitbuffer != NULL);

        return (uint8_t)bitbuffer_read(bitbuffer, 8);
    }

    inline uint8_t bitbuffer_peek_byte(BitBuffer* bitbuffer) {
        assert(bitbuffer != NULL);

        return (uint8_t)bitbuffer_peek(bitbuffer, 8);
    }

    inline int bitbuffer_add_short(BitBuffer* bitbuffer, int16_t value) {
        assert(bitbuffer != NULL);

        return bitbuffer_add_int(bitbuffer, value);
    }

    inline int16_t bitbuffer_read_short(BitBuffer* bitbuffer) {
        assert(bitbuffer != NULL);

        return (int16_t)bitbuffer_read_int(bitbuffer);
    }

    inline int16_t bitbuffer_peek_short(BitBuffer* bitbuffer) {
        assert(bitbuffer != NULL);

        return (int16_t)bitbuffer_peek_int(bitbuffer);
    }

    inline int bitbuffer_add_ushort(BitBuffer* bitbuffer, uint16_t value) {
        assert(bitbuffer != NULL);

        return bitbuffer_add_uint(bitbuffer, value);
    }

    inline uint16_t bitbuffer_read_ushort(BitBuffer* bitbuffer) {
        assert(bitbuffer != NULL);

        return (uint16_t)bitbuffer_read_uint(bitbuffer);
    }

    inline uint16_t bitbuffer_peek_ushort(BitBuffer* bitbuffer) {
        assert(bitbuffer != NULL);

        return (uint16_t)bitbuffer_peek_uint(bitbuffer);
    }

    inline int bitbuffer_add_int(BitBuffer* bitbuffer, int value) {
        assert(bitbuffer != NULL);

        uint32_t zigzag = (uint32_t)((value << 1) ^ (value >> 31));

        return bitbuffer_add_uint(bitbuffer, zigzag);
    }

    inline int bitbuffer_read_int(BitBuffer* bitbuffer) {
        assert(bitbuffer != NULL);

        uint32_t value = bitbuffer_read_uint(bitbuffer);
        int zagzig = (int)((value >> 1) ^ (-(value & 1)));

        return zagzig;
    }

    inline int bitbuffer_peek_int(BitBuffer* bitbuffer) {
        assert(bitbuffer != NULL);

        uint32_t value = bitbuffer_peek_uint(bitbuffer);
        int zagzig = (int)((value >> 1) ^ (-(value & 1)));

        return zagzig;
    }

    inline int bitbuffer_add_uint(BitBuffer* bitbuffer, uint32_t value) {
        assert(bitbuffer != NULL);

        int status = BITBUFFER_OK;
        uint32_t buffer = 0x0u;

        do {
            buffer = value & 0x7Fu;
            value >>= 7;

            if (value > 0)
                buffer |= 0x80u;

            status = bitbuffer_add(bitbuffer, 8, buffer);
        }

        while (value > 0);

        return status;
    }

    inline uint32_t bitbuffer_read_uint(BitBuffer* bitbuffer) {
        assert(bitbuffer != NULL);

        uint32_t buffer = 0x0u;
        uint32_t value = 0x0u;
        int shift = 0;

        do {
            buffer = bitbuffer_read(bitbuffer, 8);
            value |= (buffer & 0x7Fu) << shift;
            shift += 7;
        }

        while ((buffer & 0x80u) > 0);

        return value;
    }

    inline uint32_t bitbuffer_peek_uint(BitBuffer* bitbuffer) {
        assert(bitbuffer != NULL);

        int tempPosition = bitbuffer->readPosition;
        uint32_t value = bitbuffer_read_uint(bitbuffer);

        bitbuffer->readPosition = tempPosition;

        return value;
    }



    static void bitbuffer_expand_array(BitBuffer* bitbuffer) {
        assert(bitbuffer != NULL);

        int newCapacity = (bitbuffer->length * BITBUFFER_GROW_FACTOR) + BITBUFFER_MIN_GROW;
        uint32_t* oldChunks = bitbuffer->chunks;
        uint32_t* newChunks = malloc(newCapacity * sizeof(uint32_t));

        memcpy(newChunks, oldChunks, bitbuffer->length * sizeof(uint32_t));

        bitbuffer->chunks = newChunks;
        bitbuffer->length = newCapacity;

        free(oldChunks);
    }

    static int bitbuffer_find_highest_bit_position(uint8_t data) {
        int shiftCount = 0;

        while (data > 0) {
            data >>= 1;
            shiftCount++;
        }

        return shiftCount;
    }

    static uint8_t bitbuffer_to_ascii(char character) {
        char value = 0;



        return value;
    }

#ifdef __cplusplus
}
#endif

#endif // BITBUFFER_IMPLEMENTATION

#endif // BITBUFFER_H

Testbed for C#:

private static void Main() {
    byte[] buffer;
    BitBuffer outbound = new BitBuffer(128);
    BitBuffer inbound = new BitBuffer(128);

    ushort peer = 999;
    bool accelerated = true;
    uint speed = 9999999;
    byte flag = byte.MaxValue;
    ushort color = 512;
    int integer = -int.MaxValue;

    outbound.AddUShort(peer)
    .AddBool(accelerated)
    .AddUInt(speed)
    .AddByte(flag)
    .AddUShort(color)
    .AddInt(integer);

    buffer = new byte[outbound.Length];

    int length = outbound.ToArray(buffer);

    Console.WriteLine("Outbound length: " + outbound.Length + " bytes");

    inbound.FromArray(buffer, outbound.Length);

    Console.WriteLine("Inbound length: " + inbound.Length + " bytes");
    Console.WriteLine("Peer: " + inbound.ReadUShort() + ", Accelerated: " + inbound.ReadBool() + ", Speed: " + inbound.ReadUInt() + ", Flag: " + inbound.ReadByte() + ", Color: " + HalfPrecision.Decompress(inbound.ReadUShort()) + ", Integer: " + inbound.ReadInt());
    Console.WriteLine("Is finished: " + inbound.IsFinished);
}

Testbed for C:

int main() {
    uint8_t* buffer;

    BitBuffer outbound;
    BitBuffer inbound;

    bitbuffer_create_capacity(&outbound, 128);
    bitbuffer_create_capacity(&inbound, 128);

    uint16_t peer = 999;
    bool accelerated = true;
    uint32_t speed = 9999999;
    uint8_t flag = UCHAR_MAX;
    uint16_t color = 512;
    int integer = -INT_MAX;

    bitbuffer_add_ushort(&outbound, peer);
    bitbuffer_add_bool(&outbound, accelerated);
    bitbuffer_add_uint(&outbound, speed);
    bitbuffer_add_byte(&outbound, flag);
    bitbuffer_add_ushort(&outbound, color);
    bitbuffer_add_int(&outbound, integer);

    buffer = malloc(bitbuffer_length(&outbound));

    int length = bitbuffer_to_array(&outbound, buffer, bitbuffer_length(&outbound));

    printf("Outbound length: %d bytes\n", length);

    bitbuffer_from_array(&inbound, buffer, length);

    printf("Inbound length: %d bytes\n", bitbuffer_length(&inbound));

    peer = bitbuffer_read_ushort(&inbound);
    accelerated = bitbuffer_read_bool(&inbound);
    speed = bitbuffer_read_uint(&inbound);
    flag = bitbuffer_read_byte(&inbound);
    color = bitbuffer_read_ushort(&inbound);
    integer = bitbuffer_read_int(&inbound);

    printf("Peer: %d, Accelerated: %d, Speed: %d, Flag: %d, Color: %d, Integer: %d\n", peer, accelerated, speed, flag, color, integer);
    printf("Is finished: %d", bitbuffer_is_finished(&inbound));

    free(buffer);

    bitbuffer_destroy(&outbound);
    bitbuffer_destroy(&inbound);
}

One thing to note that small values and booleans work fine: peer and accelerated data is correct in the testbed.

c#
c
serialization
bitwise-operators
bit-shift
asked on Stack Overflow Feb 3, 2019 by Stas • edited Feb 4, 2019 by Stas

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0