From 4605d3907ce31b503743d1e7514ede90850a4da5 Mon Sep 17 00:00:00 2001 From: ChillerDragon Date: Mon, 17 Jun 2024 12:23:54 +0800 Subject: [PATCH] Add int packer and unpacker --- packer/packer.go | 67 +++++++++++++++++ packer/packer_test.go | 163 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 packer/packer.go create mode 100644 packer/packer_test.go diff --git a/packer/packer.go b/packer/packer.go new file mode 100644 index 0000000..3f442bf --- /dev/null +++ b/packer/packer.go @@ -0,0 +1,67 @@ +package packer + +import "errors" + +func PackInt(num int) ([]byte, error) { + dstLen := 4 + res := []byte{0x00} + idx := 0 + if num < 0 { + res[0] |= 0x40 // set sign bit + num = ^num + } + + res[0] |= byte(num & 0x3F) // pack 6 bit into dst + num >>= 6 // discard 6 bits + for num != 0 { + if idx > dstLen { + return nil, errors.New("Int too big") + } + + res = append(res, 0x00) + + res[idx] |= 0x80 // set extend bit + idx++ + res[idx] = byte(num & 0x7F) // pack 7 bit + num >>= 7 // discard 7 bits + } + + return res, nil +} + +func UnpackInt(data []byte) int { + sign := int(data[0]>>6) & 1 + res := int(data[0] & 0x3F) + i := 0 + // fake loop should only loop once + // its the poor mans goto hack + for { + if (data[i] & 0x80) == 0 { + break + } + i += 1 + res |= int(data[i]&0x7F) << 6 + + if (data[i] & 0x80) == 0 { + break + } + i += 1 + res |= int(data[i]&0x7F) << (6 + 7) + + if (data[i] & 0x80) == 0 { + break + } + i += 1 + res |= int(data[i]&0x7F) << (6 + 7 + 7) + + if (data[i] & 0x80) == 0 { + break + } + i += 1 + res |= int(data[i]&0x7F) << (6 + 7 + 7 + 7) + break + } + + res ^= -sign + return res +} diff --git a/packer/packer_test.go b/packer/packer_test.go new file mode 100644 index 0000000..4057a13 --- /dev/null +++ b/packer/packer_test.go @@ -0,0 +1,163 @@ +package packer + +import ( + "reflect" + "testing" +) + +// pack + +func TestPackSmallPositiveInts(t *testing.T) { + got, err := PackInt(1) + want := []byte{0x01} + + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, wanted %v", got, want) + } +} + +func TestPackMultiBytePositiveInts(t *testing.T) { + got, err := PackInt(63) + want := []byte{0x3F} + + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, wanted %v", got, want) + } + + got, err = PackInt(64) + want = []byte{0x80, 0x01} + + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, wanted %v", got, want) + } + + got, err = PackInt(65) + want = []byte{0x81, 0x01} + + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, wanted %v", got, want) + } +} + +func TestPackSmallNegativeInts(t *testing.T) { + got, err := PackInt(-1) + want := []byte{0x40} + + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, wanted %v", got, want) + } + + got, err = PackInt(-2) + want = []byte{0x41} + + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, wanted %v", got, want) + } +} + +func TestPackMultiByteNegativeInts(t *testing.T) { + got, err := PackInt(-63) + want := []byte{0x7E} + + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, wanted %v", got, want) + } + + got, err = PackInt(-64) + want = []byte{0x7F} + + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, wanted %v", got, want) + } + + got, err = PackInt(-65) + want = []byte{0xC0, 0x01} + + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, wanted %v", got, want) + } +} + +// unpack + +func TestUnpackSmallPositiveInts(t *testing.T) { + got := UnpackInt([]byte{0x01}) + want := 1 + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, wanted %v", got, want) + } + + got = UnpackInt([]byte{0x02}) + want = 2 + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, wanted %v", got, want) + } + + got = UnpackInt([]byte{0x03}) + want = 3 + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, wanted %v", got, want) + } +} + +func TestUnpackMultiBytePositiveInts(t *testing.T) { + got := UnpackInt([]byte{0x3f}) + want := 63 + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, wanted %v", got, want) + } + + got = UnpackInt([]byte{0x80, 0x01}) + want = 64 + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, wanted %v", got, want) + } + + got = UnpackInt([]byte{0x81, 0x01}) + want = 65 + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, wanted %v", got, want) + } +}