233 lines
5.1 KiB
Go
233 lines
5.1 KiB
Go
package taf
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"math"
|
|
)
|
|
|
|
// Writer 负责按 TAF/JCE 格式编码字段。
|
|
type Writer struct {
|
|
buf bytes.Buffer
|
|
}
|
|
|
|
func NewWriter() *Writer {
|
|
return &Writer{}
|
|
}
|
|
|
|
func (w *Writer) Bytes() []byte {
|
|
return w.buf.Bytes()
|
|
}
|
|
|
|
func (w *Writer) WriteHead(tag int, typ Type) error {
|
|
if tag < 0 || tag > 255 {
|
|
return fmt.Errorf("taf: tag 超出范围: %d", tag)
|
|
}
|
|
if tag < 15 {
|
|
return w.buf.WriteByte(byte(tag<<4) | byte(typ))
|
|
}
|
|
if err := w.buf.WriteByte(0xf0 | byte(typ)); err != nil {
|
|
return err
|
|
}
|
|
return w.buf.WriteByte(byte(tag))
|
|
}
|
|
|
|
func (w *Writer) WriteInt8(tag int, value int64) error {
|
|
if value == 0 {
|
|
return w.WriteHead(tag, TypeZero)
|
|
}
|
|
if value < math.MinInt8 || value > math.MaxInt8 {
|
|
return fmt.Errorf("taf: int8 溢出: %d", value)
|
|
}
|
|
if err := w.WriteHead(tag, TypeInt8); err != nil {
|
|
return err
|
|
}
|
|
return w.buf.WriteByte(byte(int8(value)))
|
|
}
|
|
|
|
func (w *Writer) WriteInt16(tag int, value int64) error {
|
|
if value >= math.MinInt8 && value <= math.MaxInt8 {
|
|
return w.WriteInt8(tag, value)
|
|
}
|
|
if value < math.MinInt16 || value > math.MaxInt16 {
|
|
return fmt.Errorf("taf: int16 溢出: %d", value)
|
|
}
|
|
if err := w.WriteHead(tag, TypeInt16); err != nil {
|
|
return err
|
|
}
|
|
var b [2]byte
|
|
binary.BigEndian.PutUint16(b[:], uint16(int16(value)))
|
|
_, err := w.buf.Write(b[:])
|
|
return err
|
|
}
|
|
|
|
func (w *Writer) WriteInt32(tag int, value int64) error {
|
|
if value >= math.MinInt16 && value <= math.MaxInt16 {
|
|
return w.WriteInt16(tag, value)
|
|
}
|
|
if value < math.MinInt32 || value > math.MaxInt32 {
|
|
return fmt.Errorf("taf: int32 溢出: %d", value)
|
|
}
|
|
if err := w.WriteHead(tag, TypeInt32); err != nil {
|
|
return err
|
|
}
|
|
var b [4]byte
|
|
binary.BigEndian.PutUint32(b[:], uint32(int32(value)))
|
|
_, err := w.buf.Write(b[:])
|
|
return err
|
|
}
|
|
|
|
func (w *Writer) WriteInt64(tag int, value int64) error {
|
|
if value >= math.MinInt32 && value <= math.MaxInt32 {
|
|
return w.WriteInt32(tag, value)
|
|
}
|
|
if err := w.WriteHead(tag, TypeInt64); err != nil {
|
|
return err
|
|
}
|
|
var b [8]byte
|
|
binary.BigEndian.PutUint64(b[:], uint64(value))
|
|
_, err := w.buf.Write(b[:])
|
|
return err
|
|
}
|
|
|
|
func (w *Writer) WriteBool(tag int, value bool) error {
|
|
if value {
|
|
return w.WriteInt8(tag, 1)
|
|
}
|
|
return w.WriteInt8(tag, 0)
|
|
}
|
|
|
|
func (w *Writer) WriteFloat(tag int, value float32) error {
|
|
if err := w.WriteHead(tag, TypeFloat); err != nil {
|
|
return err
|
|
}
|
|
var b [4]byte
|
|
binary.BigEndian.PutUint32(b[:], math.Float32bits(value))
|
|
_, err := w.buf.Write(b[:])
|
|
return err
|
|
}
|
|
|
|
func (w *Writer) WriteDouble(tag int, value float64) error {
|
|
if err := w.WriteHead(tag, TypeDouble); err != nil {
|
|
return err
|
|
}
|
|
var b [8]byte
|
|
binary.BigEndian.PutUint64(b[:], math.Float64bits(value))
|
|
_, err := w.buf.Write(b[:])
|
|
return err
|
|
}
|
|
|
|
func (w *Writer) WriteString(tag int, value string) error {
|
|
raw := []byte(value)
|
|
if len(raw) > math.MaxUint8 {
|
|
if err := w.WriteHead(tag, TypeString4); err != nil {
|
|
return err
|
|
}
|
|
var b [4]byte
|
|
binary.BigEndian.PutUint32(b[:], uint32(len(raw)))
|
|
if _, err := w.buf.Write(b[:]); err != nil {
|
|
return err
|
|
}
|
|
_, err := w.buf.Write(raw)
|
|
return err
|
|
}
|
|
if err := w.WriteHead(tag, TypeString1); err != nil {
|
|
return err
|
|
}
|
|
if err := w.buf.WriteByte(byte(len(raw))); err != nil {
|
|
return err
|
|
}
|
|
_, err := w.buf.Write(raw)
|
|
return err
|
|
}
|
|
|
|
func (w *Writer) WriteBytes(tag int, value []byte) error {
|
|
if err := w.WriteHead(tag, TypeSimpleList); err != nil {
|
|
return err
|
|
}
|
|
if err := w.WriteHead(0, TypeInt8); err != nil {
|
|
return err
|
|
}
|
|
if err := w.WriteInt32(0, int64(len(value))); err != nil {
|
|
return err
|
|
}
|
|
_, err := w.buf.Write(value)
|
|
return err
|
|
}
|
|
|
|
func (w *Writer) WriteStructBegin(tag int) error {
|
|
return w.WriteHead(tag, TypeStructBegin)
|
|
}
|
|
|
|
func (w *Writer) WriteStructEnd() error {
|
|
return w.WriteHead(0, TypeStructEnd)
|
|
}
|
|
|
|
func (w *Writer) WriteStruct(tag int, value Marshaler) error {
|
|
if err := w.WriteStructBegin(tag); err != nil {
|
|
return err
|
|
}
|
|
if err := value.WriteTo(w); err != nil {
|
|
return err
|
|
}
|
|
return w.WriteStructEnd()
|
|
}
|
|
|
|
func (w *Writer) WriteMapStringString(tag int, value map[string]string) error {
|
|
if value == nil {
|
|
value = map[string]string{}
|
|
}
|
|
if err := w.WriteHead(tag, TypeMap); err != nil {
|
|
return err
|
|
}
|
|
if err := w.WriteInt32(0, int64(len(value))); err != nil {
|
|
return err
|
|
}
|
|
for k, v := range value {
|
|
if err := w.WriteString(0, k); err != nil {
|
|
return err
|
|
}
|
|
if err := w.WriteString(1, v); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (w *Writer) WriteMapStringBytes(tag int, value map[string][]byte) error {
|
|
if value == nil {
|
|
value = map[string][]byte{}
|
|
}
|
|
if err := w.WriteHead(tag, TypeMap); err != nil {
|
|
return err
|
|
}
|
|
if err := w.WriteInt32(0, int64(len(value))); err != nil {
|
|
return err
|
|
}
|
|
for k, v := range value {
|
|
if err := w.WriteString(0, k); err != nil {
|
|
return err
|
|
}
|
|
if err := w.WriteBytes(1, v); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (w *Writer) WriteListStruct(tag int, values []Marshaler) error {
|
|
if err := w.WriteHead(tag, TypeList); err != nil {
|
|
return err
|
|
}
|
|
if err := w.WriteInt32(0, int64(len(values))); err != nil {
|
|
return err
|
|
}
|
|
for _, value := range values {
|
|
if err := w.WriteStruct(0, value); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|