shithub: furgit

ref: 94011e3762ca25b8ab3a9b9fe0d7a9e155381477
dir: /protocol/pktline/header.go/

View raw version
package pktline

import "fmt"

func hexval(b byte) int {
	switch {
	case b >= '0' && b <= '9':
		return int(b - '0')
	case b >= 'a' && b <= 'f':
		return int(b-'a') + 10
	case b >= 'A' && b <= 'F':
		return int(b-'A') + 10
	default:
		return -1
	}
}

// ParseLengthHeader parses a 4-byte hexadecimal pkt-line length header.
//
// The returned value is the full on-wire packet size, including the 4-byte
// header. Semantic interpretation (data/control/error) is done by Decoder.
//
// The 4-byte header is only an actual length when above or equal to 4.
// Otherwise, it indicates some control packet.
func ParseLengthHeader(h [4]byte) (int, error) {
	a := hexval(h[0])
	b := hexval(h[1])
	c := hexval(h[2])
	d := hexval(h[3])

	if a < 0 || b < 0 || c < 0 || d < 0 {
		return 0, fmt.Errorf("%w: %q", ErrInvalidLength, string(h[:]))
	}

	return (a << 12) | (b << 8) | (c << 4) | d, nil
}

// EncodeLengthHeader encodes n as a 4-byte hexadecimal pkt-line header.
//
// n is the full on-wire packet size including the 4-byte header.
//
// The 4-byte header is only an actual length when above or equal to 4.
// Otherwise, it indicates some control packet.
func EncodeLengthHeader(dst *[4]byte, n int) error {
	if n < 0 || n > LargePacketMax {
		return fmt.Errorf("%w: %d", ErrInvalidLength, n)
	}

	const hex = "0123456789abcdef"

	dst[0] = hex[(n>>12)&0xf]
	dst[1] = hex[(n>>8)&0xf]
	dst[2] = hex[(n>>4)&0xf]
	dst[3] = hex[n&0xf]

	return nil
}