Teeworlds protocol

Technical int packing deep dive

This page is covering a technical dissection of the int packing code. With some examples to better visualize it.

There is a chance you never have to fully understand int packing to achieve your goals related to tw networking. This section is a bit weird. I recommend reading the higher level docs on that in the fundamentals section. If you already red that and still want to dive deeper you are correct here.


Other projects test code as reference

When trying to figure out how the packer should behave it can help to look at the tests that were written for it.


The C packer code with print statements

Here the official teeworlds Pack() method annotated with some debug statements to better visualize what is happening.

                
    #include "stdio.h"

    void printbincharpad(char c)
    {
        for (int i = 7; i >= 0; --i)
        {
            putchar( (c & (1 << i)) ? '1' : '0' );
        }
    }

    void str_hex(char *dst, int dst_size, const void *data, int data_size)
    {
        static const char hex[] = "0123456789ABCDEF";
        int b;

        for(b = 0; b < data_size && b < dst_size/4-4; b++)
        {
            dst[b*3] = hex[((const unsigned char *)data)[b]>>4];
            dst[b*3+1] = hex[((const unsigned char *)data)[b]&0xf];
            dst[b*3+2] = ' ';
            dst[b*3+3] = 0;
        }
    }

    void print_bin(const char * pBuf, int size)
    {
        for(int i = 0; i < size; i++)
        {
            printbincharpad(pBuf[i]);
            putchar(' ');
        }
        putchar('\n');
    }

    unsigned char *Pack(unsigned char *pDst, int i)
    {
        *pDst = 0;
        if(i < 0)
        {
            *pDst |= 0x40; // set sign bit
            i = ~i;
        }

        *pDst |= i & 0x3F; // pack 6bit into dst
        i >>= 6; // discard 6 bits
        while(i)
        {
            *pDst |= 0x80; // set extend bit
            pDst++;
            *pDst = i & 0x7F; // pack 7bit
            i >>= 7; // discard 7 bits
        }

        pDst++;
        return pDst;
    }

    void verbose_pack(int i)
    {
        int num_bytes = 1;
        if(i > 63 || i < -64)
            num_bytes = 2;
        char aBuf[1024];
        char aHex[1024];

        Pack((unsigned char *)aBuf, i);

        str_hex(aHex, sizeof(aHex), aBuf, num_bytes);
        printf("Pack(%d)\n => hex=%s\n => bin=", i, aHex);
        print_bin(aBuf, num_bytes);

        printf(" => fmt=ESDDDDDD ");
        for(int k = 1; k < num_bytes; k++)
            printf("EDDDDDDD ");
        if(num_bytes > 1)
            puts("\n    when building the int keep in mind it is little endian!\n");
        else
            puts("\n");
    }

    int main()
    {
        verbose_pack(1);
        verbose_pack(2);
        verbose_pack(3);

        verbose_pack(-1);
        verbose_pack(-2);
        verbose_pack(-3);

        verbose_pack(63);
        verbose_pack(64);
        verbose_pack(65);

        verbose_pack(-63);
        verbose_pack(-64);
        verbose_pack(-65);
        verbose_pack(-66);
        verbose_pack(-67);
        return 0;
    }
                
            
It will output the following
                
    Pack(1)
     => hex=01
     => bin=00000001
     => fmt=ESDDDDDD

    Pack(2)
     => hex=02
     => bin=00000010
     => fmt=ESDDDDDD

    Pack(3)
     => hex=03
     => bin=00000011
     => fmt=ESDDDDDD

    Pack(-1)
     => hex=40
     => bin=01000000
     => fmt=ESDDDDDD

    Pack(-2)
     => hex=41
     => bin=01000001
     => fmt=ESDDDDDD

    Pack(-3)
     => hex=42
     => bin=01000010
     => fmt=ESDDDDDD

    Pack(63)
     => hex=3F
     => bin=00111111
     => fmt=ESDDDDDD

    Pack(64)
     => hex=80 01
     => bin=10000000 00000001
     => fmt=ESDDDDDD EDDDDDDD
        when building the int keep in mind it is little endian!

    Pack(65)
     => hex=81 01
     => bin=10000001 00000001
     => fmt=ESDDDDDD EDDDDDDD
        when building the int keep in mind it is little endian!

    Pack(-63)
     => hex=7E
     => bin=01111110
     => fmt=ESDDDDDD

    Pack(-64)
     => hex=7F
     => bin=01111111
     => fmt=ESDDDDDD

    Pack(-65)
     => hex=C0 01
     => bin=11000000 00000001
     => fmt=ESDDDDDD EDDDDDDD
        when building the int keep in mind it is little endian!

    Pack(-66)
     => hex=C1 01
     => bin=11000001 00000001
     => fmt=ESDDDDDD EDDDDDDD
        when building the int keep in mind it is little endian!

    Pack(-67)
     => hex=C2 01
     => bin=11000010 00000001
     => fmt=ESDDDDDD EDDDDDDD
        when building the int keep in mind it is little endian!