Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write LEB128 in Go

Tags:

binary

go

varint

How do you write an integer to LEB128 format in Go? I'm trying to encode an int32 to a Minecraft VarInt, so far I've tried importing the example on the wiki to Go. I get the wrong results when testing though, wiki says -1 should equal [255 255 255 255 15], but I get [255 255 255 255 255] instead. What I'm I doing wrong here?

func WriteVarInt2(v int32) []byte{
   var out []byte
   c := 0
   for{
       currentByte := byte(v & 0b01111111)
       v >>= 7
       if v != 0 {
           currentByte |= 0b10000000
       }
       out = append(out, currentByte)
       c++

       if c >= 5 || v == 0{
           return out
       }
    }
}
like image 610
Angel Avatar asked Jun 25 '21 22:06

Angel


1 Answers

The problem is with the shifting operation.

>> is arithmetic shift right, >>> is logical shift right. The difference is that >> brings in the sign bit (on the left), while >>> brings in zeros (whatever the sign bit was).

The algorithm of LEB128's Varint uses logical shift, and Go's >> is arithmetic shift.

There is no distinct logical shift in Go, but if you treat the number as unsigned, you'll get exactly that:

func WriteVarInt2(v_ int32) []byte {
    v := uint32(v_)

    // rest of your function unchanged
    // ...
}

Testing it:

fmt.Println(WriteVarInt2(-1))

Output is as expected (try it on the Go Playground):

[255 255 255 255 15]
like image 83
icza Avatar answered Sep 28 '22 00:09

icza