mq_coder/primitive_decoder.go

89 lines
2.0 KiB
Go
Raw Permalink Normal View History

2022-10-10 14:47:49 +08:00
package mq_coder
import (
"bytes"
"errors"
"fmt"
"git.hpds.cc/Component/mq_coder/encoding"
)
// DecodeState represents the state of decoding
type DecodeState struct {
// ConsumedBytes is the bytes consumed by decoder
ConsumedBytes int
// SizeL is the bytes length of value
SizeL int
}
// DecodeToPrimitivePacket parse out whole buffer to a PrimitivePacket
//
// Examples:
// [0x01, 0x01, 0x01] -> Key=0x01, Value=0x01
// [0x41, 0x06, 0x03, 0x01, 0x61, 0x04, 0x01, 0x62] -> key=0x03, value=0x61; key=0x04, value=0x62
func DecodeToPrimitivePacket(buf []byte, p *PrimitivePacket) (*DecodeState, error) {
decoder := &DecodeState{
ConsumedBytes: 0,
SizeL: 0,
}
if buf == nil || len(buf) < primitivePacketBufferMinimalLength {
return decoder, errors.New("invalid packet minimal size")
}
p.packet = &packet{
valBuf: []byte{},
buf: &bytes.Buffer{},
}
var pos = 0
// first byte is `Tag`
p.tag = NewTag(buf[pos])
p.buf.WriteByte(buf[pos])
pos++
decoder.ConsumedBytes = pos
// read `Varint` from buf for `Length of value`
tmpBuf := buf[pos:]
var bufLen int32
codec := encoding.VarCodec{}
err := codec.DecodePVarInt32(tmpBuf, &bufLen)
if err != nil {
return decoder, err
}
if codec.Size < 1 {
return decoder, errors.New("malformed, size of Length can not smaller than 1")
}
// codec.Size describes how many bytes used to represent `Length`
p.buf.Write(buf[pos : pos+codec.Size])
pos += codec.Size
decoder.ConsumedBytes = pos
decoder.SizeL = codec.Size
// if length<0, error on decoding
if bufLen < 0 {
return decoder, errors.New("invalid packet, negative length")
}
// the length of value
p.length = int(bufLen)
if p.length == 0 {
p.valBuf = nil
return decoder, nil
}
// the next `p.length` bytes store value
endPos := pos + p.length
if pos > endPos || endPos > len(buf) || pos > len(buf) {
return decoder, fmt.Errorf("beyond the boundary, pos=%v, endPos=%v", pos, endPos)
}
p.valBuf = buf[pos:endPos]
p.buf.Write(buf[pos:endPos])
decoder.ConsumedBytes = endPos
return decoder, nil
}