go_cstruct

package module
v0.0.0-...-4cd4995 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 28, 2024 License: Apache-2.0 Imports: 10 Imported by: 0

README

go-bit

Go Go Report Card Go Reference

一个对 golang 结构进行编码/解码的库,支持切片数据,并支持校验。 Go struct 与 C struct 对应,内存分布一致。

Installation

go get -u github.com/piaoxue1949/go-cstruct

Usage

这是一个解码TCP标头的简单示例。(大端)

  1. 将以下代码保存为tcp.go。
  2. go mod init go-cstruct-example
  3. go mod tidy
  4. go run tcp.go
package main

import (
	"bytes"
	"encoding/binary"
	"fmt"
	go_cstruct "github.com/piaoxue1949/go-cstruct"
)

func main() {
	type TcpHeader struct {
		SrcPort    uint16
		DstPort    uint16
		SeqNo      uint32
		AckNo      uint32
		HeaderLen  [4]bool
		Reserved   [3]bool `cst:"skip"`
		NS         bool
		CWR        bool
		ECE        bool
		URG        bool
		ACK        bool
		PSH        bool
		RST        bool
		SYN        bool
		FIN        bool
		WinSize    uint16
		CheckSum   uint16
		EmePointer uint16
	}

	s := TcpHeader{}

	buf := []byte{0xd8, 0x65, 0x01, 0xbb, 0x4b, 0xe0, 0x76, 0xcd, 0x48, 0xc8, 0x70, 0x8f, 0x50, 0x10, 0x10,
		0x18, 0x0e, 0xc1, 0x00, 0x00}

	if err := go_cstruct.Decode(buf, binary.BigEndian, &s); err != nil {
		fmt.Printf("error:%s", err)
	}

	fmt.Printf("src=%d dst=%d\n", s.SrcPort, s.DstPort)
	fmt.Printf("SeqNo=%d AckNo=%d\n", s.SeqNo, s.AckNo)
	fmt.Printf("HeaderLen=%d\n", go_cstruct.BoolsToNumber(s.HeaderLen[:]))
	fmt.Printf("Ack=%t\n", s.ACK)
}

此外,还有一个自动编码和解码切片的例子

type SmsType uint8

const (
	SmsTypeLogin        SmsType = 1 // 登录
	SmsTypeUpdateMobile SmsType = 2 // 修改手机号
)

type SendSmsReq struct {
	SmsType SmsType `v:"enums"`
	Mobile  []byte  `cst:"len-size:1"`
	Code    []byte  `cst:"len-size:1"`
}

//上面的代码位于test_types/types.go
// 枚举的自动验证需要使用goframe库

func TestCheckAndWrite(t *testing.T) {
	ctx := context.TODO()
	req := &test_types.SendSmsReq{
		SmsType: test_types.SmsTypeLogin,
		Mobile:  []byte("13800138000"),
		Code:    []byte{0x01, 0x02},
	}
	data, err := go_cstruct.CheckAndEncode(ctx, binary.BigEndian, req)
	if err != nil {
		t.Errorf("CheckAndWrite() error = %v", err)
		return
	}
	expect := []byte{0x01, 11, '1', '3', '8', '0', '0', '1', '3', '8', '0', '0', '0', 2, 0x1, 0x2}
	if !bytes.Equal(data, expect) {
		t.Errorf("CheckAndWrite() = %v, want %v", data, expect)
	}
	req.SmsType = 3
	_, err = go_cstruct.CheckAndEncode(ctx, binary.BigEndian, req)
	if err == nil {
		t.Errorf("Check invalid SmsType %v failed", req.SmsType)
		return
	}
}

func TestDecodeAndCheck(t *testing.T) {
	ctx := context.TODO()
	req := &test_types.SendSmsReq{}
	buf := []byte{0x01, 11, '1', '3', '8', '0', '0', '1', '3', '8', '0', '0', '0', 2, 0x1, 0x2}
	err := go_cstruct.DecodeAndCheck(ctx, buf, binary.BigEndian, req)
	if err != nil {
		t.Errorf("ReadAndCheck() error = %v", err)
		return
	}
	expect := &test_types.SendSmsReq{
		SmsType: test_types.SmsTypeLogin,
		Mobile:  []byte("13800138000"),
		Code:    []byte{0x1, 0x2},
	}
	if !reflect.DeepEqual(req, expect) {
		t.Errorf("ReadAndCheck() = %v, want %v", req, expect)
	}
	buf[0] = 3
	err = go_cstruct.DecodeAndCheck(ctx, buf, binary.BigEndian, req)
	if err == nil {
		t.Errorf("Check invalid SmsType %v failed", req.SmsType)
		return
	}
}

结构体标签

该包支持结构标签。

标签 说明
`cst:"skip"` 忽略该字段。偏移将根据字段的大小进行更新。它对保留字段很有用.
`cst:"-"` 忽略该字段。偏移未更新.
`cst:"BE"` 将字段解码为大端。它对于混合大小端的数据很有用.
`cst:"LE"` 将字段解码为小端。它对于混合大小端数据很有用.
`cst:"len-size:1"` 对切片字段进行编码/解码,在此字段之前使用隐藏的len字段,其中len-size为切片长度字段长度。此功能对于二进制协议编码和解码非常有用.

文档

https://pkg.go.dev/github.com/piaoxue1949/go-cstruct

License

Apache License v2.0

参考项目

https://github.com/fananchong/cstruct-go

https://github.com/nokute78/go-bit

Documentation

Overview

package go_cstruct provides functions for bit.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrOutOfRange = errors.New("out of range")
)

Functions

func BitsToBytes

func BitsToBytes(b []bool, o binary.ByteOrder) []byte

BitsToBytes converts the unit. bit -> byte.

func BoolsToNumber

func BoolsToNumber(bools []bool) uint64

func BytesToBits

func BytesToBits(b []byte, bitSize uint64, o binary.ByteOrder) ([]bool, error)

BytesToBits returns Bit slices. bitSize is the size of Bit slice.

func CheckAndEncode

func CheckAndEncode(ctx context.Context, order binary.ByteOrder, input interface{}) ([]byte, error)

func Decode

func Decode(buf []byte, order binary.ByteOrder, data interface{}) error

Decode reads structured binary data from i into data. Data must be a pointer to a fixed-size value. Not exported struct field is ignored.

Supports StructTag.
    `cst:"skip"` : ignore the field. Skip X bits which is the size of the field. It is useful for reserved field.
    `cst:"-"`    : ignore the field. Offset is not changed.

func DecodeAndCheck

func DecodeAndCheck(ctx context.Context, buf []byte, order binary.ByteOrder, data interface{}) error

func Encode

func Encode(order binary.ByteOrder, input interface{}) ([]byte, error)

Encode writes structured binary data from input into w.

func GetBit

func GetBit(b []byte, off Offset, o binary.ByteOrder) (bool, error)

GetBit returns 1 or 0. GetBit reads b at Offset off, returns the bit.

Example
package main

import (
	"encoding/binary"
	"fmt"

	go_cstruct "github.com/piaoxue1949/go-cstruct"
)

func main() {
	b := []byte{0x00, 0x80} /* 1000_0000 0000_0000 in bit */

	off := go_cstruct.Offset{Byte: 0, Bit: 15}
	ret, err := go_cstruct.GetBit(b, off, binary.LittleEndian)
	if err != nil {
		fmt.Printf("error:%s\n", err)
	}

	fmt.Printf("%t\n", ret)
}
Output:
true

func GetBitAsByte

func GetBitAsByte(b []byte, off Offset, o binary.ByteOrder) (byte, error)

GetBitAsByte returns byte (1 or 0). GetBitAsByte reads b at Offset off, returns the bit.

func GetBitAsByteNotShift

func GetBitAsByteNotShift(b []byte, off Offset, o binary.ByteOrder) (byte, error)

GetBitAsByteNotShift reads b at Offset off, returns the bit. Return value is not bit shifted.

Example
package main

import (
	"encoding/binary"
	"fmt"

	go_cstruct "github.com/piaoxue1949/go-cstruct"
)

func main() {
	b := []byte{0x00, 0x80} /* 1000_0000 0000_0000 in bit */

	off := go_cstruct.Offset{Byte: 0, Bit: 15}
	ret, err := go_cstruct.GetBitAsByteNotShift(b, off, binary.LittleEndian)
	if err != nil {
		fmt.Printf("error:%s\n", err)
	}

	fmt.Printf("0x%x\n", ret)
}
Output:
0x80

func GetBits

func GetBits(bytes []byte, off Offset, bitSize uint64, o binary.ByteOrder) (ret []bool, err error)

GetBits returns Bit slice. GetBits reads bytes slice from Offset off. Read size is bitSize in bit.

func GetBitsAsByte

func GetBitsAsByte(bytes []byte, off Offset, bitSize uint64, o binary.ByteOrder) (ret []byte, err error)

GetBitsAsByte returns byte slice. GetBitsAsByte reads bytes slice from Offset off. Read size is bitSize in bit.

Example
package main

import (
	"encoding/binary"
	"fmt"

	go_cstruct "github.com/piaoxue1949/go-cstruct"
)

func main() {
	b := []byte{0x78} /* 0111_1000 in bit */

	/* try to get 4bits(1111b) from 0111_1000 */
	off := go_cstruct.Offset{Byte: 0, Bit: 3}

	ret, err := go_cstruct.GetBitsAsByte(b, off, 4, binary.LittleEndian)
	if err != nil {
		fmt.Printf("error:%s\n", err)
	}

	fmt.Printf("0x%x\n", ret)
}
Output:
0x0f

func GetBitsBitEndian

func GetBitsBitEndian(b []byte, o Offset, bitSize uint64, order binary.ByteOrder) ([]bool, error)

GetBitsBitEndian returns Bit slice. If order is LittleEndian, it is same as GetBits function. It respect bit order endianness when order is BigEndian.

func GetVals

func GetVals(bytes []byte, off Offset, v reflect.Value, o binary.ByteOrder) error

func NewBits

func NewBits(size uint64, v bool) []bool

NewBits generates slice of Bit.

func NumberToBools

func NumberToBools(number uint64, length int) []bool

func SetBit

func SetBit(b []byte, off Offset, val bool, o binary.ByteOrder) error

SetBit sets bit on b at off. Bit is 0 if val == 0, 1 if val > 0. SetBit returns error if error occurred.

Example
package main

import (
	"encoding/binary"
	"fmt"

	go_cstruct "github.com/piaoxue1949/go-cstruct"
)

func main() {
	b := []byte{0x00, 0x00} /* 0000_0000 0000_0000 in bit */

	off := go_cstruct.Offset{Byte: 0, Bit: 15}
	val := bool(true)

	err := go_cstruct.SetBit(b, off, val, binary.LittleEndian)
	if err != nil {
		fmt.Printf("error:%s\n", err)
	}
	fmt.Printf("0x%x\n", b)
}
Output:
0x0080

func SetBits

func SetBits(bytes []byte, off Offset, setBits []bool, o binary.ByteOrder) error

SetBits sets bits on bytes at off. The length to set is bitSize. SetBits returns error if error occurred.

Example
package main

import (
	"encoding/binary"
	"fmt"

	go_cstruct "github.com/piaoxue1949/go-cstruct"
)

func main() {
	b := []byte{0x00, 0x00} /* 0000_0000 0000_0000 in bit */

	off := go_cstruct.Offset{Byte: 0, Bit: 8}
	val := []bool{false, false, false, true} /* 0000_1000 in bit */

	err := go_cstruct.SetBits(b, off, val, binary.LittleEndian)
	if err != nil {
		fmt.Printf("error:%s\n", err)
	}

	fmt.Printf("0x%x\n", b)
}
Output:
0x0008

func SetBitsBitEndian

func SetBitsBitEndian(b []byte, off Offset, setBits []bool, order binary.ByteOrder) error

SetBitsBitEndian sets bits in b. If order is LittleEndian, it is same as GetBits function. It respect bit order endianness when order is BigEndian.

func SetVals

func SetVals(bytes []byte, off Offset, v reflect.Value, o binary.ByteOrder) error

SetVals returns error if error occurred.

func SizeInByte

func SizeInByte(b []bool) int

SizeInByte returns size of []bool slice in byte. e.g. It returns len([]bool) == 9.

Types

type Offset

type Offset struct {
	Byte uint64 /* Offset in byte. */
	Bit  uint64 /* Offset in bit.  */
}

Offset represents offset to access bits in byte slices.

func (Offset) AddOffset

func (off Offset) AddOffset(diff Offset) (Offset, error)

AddOffset adds diff and returns new Offset.

func (*Offset) AlignByte

func (off *Offset) AlignByte() uint8

func (Offset) Bits

func (off Offset) Bits() uint64

Bits returns offset in bit. e.g. Offset{Byte:3, Bit:2} -> 26.

func (Offset) Compare

func (off Offset) Compare(b Offset) int

Compare returns an integer comparing two Offsets. The result will be 0 if off==b, -1 if off < b, and +1 if off > b.

func (*Offset) Normalize

func (off *Offset) Normalize()

Normalize updates off.Byte if off.Bit >= 8. e.g. Offset{Byte: 3, Bit: 53} -> Offset{Byte: 9, Bit: 5}

func (Offset) String

func (o Offset) String() string

func (Offset) SubOffset

func (off Offset) SubOffset(diff Offset) (Offset, error)

SubOffset subs diff and returns new Offset. diff must be larger then off.

Directories

Path Synopsis
cmd
readbit command
test

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL