package little // LOW TO HIGHT import ( "errors" "fmt" "io" "math" ) const ( maxReadAttempts = 5 MinInt24 = -1 << 23 // -8388608 MaxInt24 = 1<<23 - 1 // 8388607 MinInt48 = -1 << 47 // -140737488355328 MaxInt48 = 1<<47 - 1 // 140737488355327 MaxUint24 = 1<<24 - 1 // 16777215 MaxUint48 = 1<<48 - 1 // 281474976710655 //Int32SignBit uint32 = 1 << 31 //Int64SignBit uint64 = 1 << 63 ) var ( // ErrReadOverflow shows 100% bug in the source reader ErrReadOverflow = errors.New("bin: reader returned 'n' > bufsize") // ErrNegativeReadCount shows 100% bug in the source reader ErrNegativeReadCount = errors.New("bin: reader returned negative 'n'") ErrNoSpace = errors.New("bin: no space") ErrTooLong = errors.New("bin: too long") // слишком длинная строка или массив байт ErrRange = errors.New("bin: out of range") ErrNegativeSize = errors.New("bin: negative size") ) func ReadByteAsInt(r io.Reader) (i int, err error) { a, err := ReadN(r, 1) if err != nil { return } return int(a[0]), nil } func ReadUint16AsInt(r io.Reader) (_ int, err error) { u16, err := ReadUint16(r) if err != nil { return } return int(u16), nil } func ReadUint32AsInt(r io.Reader) (_ int, err error) { u32, err := ReadUint32(r) if err != nil { return } return int(u32), nil } func ReadUint32AsInt64(r io.Reader) (_ int64, err error) { u32, err := ReadUint32(r) if err != nil { return } return int64(u32), nil } func ReadByte(r io.Reader) (byte, error) { buf := make([]byte, 1) if err := ReadNInto(r, buf); err != nil { return 0, err } return buf[0], nil } // ReadN - безопасно читаем n байт. Обрабатывает все возможные ситуации, в том числе // баги Reader func ReadN(r io.Reader, n int) (_ []byte, err error) { if n < 0 { err = fmt.Errorf("wrong n=%d", n) return } buf := make([]byte, n) err = ReadNInto(r, buf) if err != nil { return } return buf, nil } func ReadNInto(r io.Reader, buf []byte) (err error) { if len(buf) == 0 { return } var q, total, readAttempts int // Избегаем вечного цикла из-за неправильной реализации ридера for readAttempts < maxReadAttempts { bufsize := len(buf) - total q, err = r.Read(buf[total:]) // Если буфер заполнен - успех, err игнорируем if q == bufsize { return nil } // Если ошибка - выходим с ошибкой if err != nil { return } // Если прочитали больше чем размер буфера. Баг в Reader if q > bufsize { err = ErrReadOverflow return } // Если прочитали < 0. Баг в Reader if q < 0 { err = ErrNegativeReadCount return } // Если ошибки нет, а прочитали 0 байт - чтобы не войти в бесконечный цикл // увеличиваем readAttempts if q == 0 { readAttempts++ } else { // Что-то прочитали, но меньше чем нужно - увеличиваем счетчик // суммарно прочитанного total += q } } err = io.ErrNoProgress return } func ReadString(r io.Reader, n int) (string, error) { buf, err := ReadN(r, n) if err != nil { return "", nil } return string(buf), nil } // ReadInt16 - читает из io.Reader 2 байта и декодирует их в int16. func ReadInt16(src io.Reader) (int16, error) { a, err := ReadN(src, 2) if err != nil { return 0, err } num := int16(a[0]) num |= int16(a[1]) << 8 return num, nil } // ReadInt24 - читает из io.Reader 3 байта и декодирует их в int32. // Нужно для протокола mbus. func ReadInt24(src io.Reader) (int32, error) { a, err := ReadN(src, 3) if err != nil { return 0, err } tmp := uint32(a[0]) tmp |= uint32(a[1]) << 8 tmp |= uint32(a[2]&127) << 16 if a[2] > 127 { // для отрицательного числа старшие 9 бит выставляю в единицы tmp |= (1<<9 - 1) << 23 } return int32(tmp), nil } // ReadInt32 - читает из io.Reader 4 байта и декодирует их в int32. func ReadInt32(src io.Reader) (int32, error) { a, err := ReadN(src, 4) if err != nil { return 0, err } num := int32(a[0]) num |= int32(a[1]) << 8 num |= int32(a[2]) << 16 num |= int32(a[3]) << 24 return num, nil } // ReadInt48 - читает из io.Reader 6 байт и декодирует их в int64. func ReadInt48(src io.Reader) (int64, error) { a, err := ReadN(src, 6) if err != nil { return 0, err } tmp := uint64(a[0]) tmp |= uint64(a[1]) << 8 tmp |= uint64(a[2]) << 16 tmp |= uint64(a[3]) << 24 tmp |= uint64(a[4]) << 32 tmp |= uint64(a[5]&127) << 40 if a[5] > 127 { // для отрицательного числа старшие 17 бит выставляю в единицы tmp |= (1<<17 - 1) << 47 } return int64(tmp), nil } // ReadInt64 - читает из io.Reader 8 байт и декодирует их в int64. func ReadInt64(src io.Reader) (int64, error) { a, err := ReadN(src, 8) if err != nil { return 0, err } num := int64(a[0]) num |= int64(a[1]) << 8 num |= int64(a[2]) << 16 num |= int64(a[3]) << 24 num |= int64(a[4]) << 32 num |= int64(a[5]) << 40 num |= int64(a[6]) << 48 num |= int64(a[7]) << 56 return num, nil } // ReadUint16 - читает из io.Reader 2 байта и декодирует их в uint16. func ReadUint16(src io.Reader) (uint16, error) { a, err := ReadN(src, 2) if err != nil { return 0, err } num := uint16(a[0]) num |= uint16(a[1]) << 8 return num, nil } // ReadUint24 - читает из io.Reader 3 байта и декодирует их в uint32. func ReadUint24(src io.Reader) (uint32, error) { a, err := ReadN(src, 3) if err != nil { return 0, err } num := uint32(a[0]) num |= uint32(a[1]) << 8 num |= uint32(a[2]) << 16 return num, nil } // ReadUint32 - читает из io.Reader 4 байта и декодирует их в uint32. func ReadUint32(src io.Reader) (uint32, error) { a, err := ReadN(src, 4) if err != nil { return 0, err } num := uint32(a[0]) num |= uint32(a[1]) << 8 num |= uint32(a[2]) << 16 num |= uint32(a[3]) << 24 return num, nil } // ReadUint48 - читает из io.Reader 6 байт и декодирует их в uint64. func ReadUint48(src io.Reader) (uint64, error) { a, err := ReadN(src, 6) if err != nil { return 0, err } num := uint64(a[0]) num |= uint64(a[1]) << 8 num |= uint64(a[2]) << 16 num |= uint64(a[3]) << 24 num |= uint64(a[4]) << 32 num |= uint64(a[5]) << 40 return num, nil } // ReadUint64 - читает из io.Reader 8 байт и декодирует их в uint64. func ReadUint64(src io.Reader) (uint64, error) { a, err := ReadN(src, 8) if err != nil { return 0, err } num := uint64(a[0]) num |= uint64(a[1]) << 8 num |= uint64(a[2]) << 16 num |= uint64(a[3]) << 24 num |= uint64(a[4]) << 32 num |= uint64(a[5]) << 40 num |= uint64(a[6]) << 48 num |= uint64(a[7]) << 56 return num, nil } // ReadFloat32 - читает из io.Reader 4 байта и декодирует их в float32. func ReadFloat32(src io.Reader) (float32, error) { tmp, err := ReadUint32(src) if err != nil { return 0, err } return math.Float32frombits(tmp), nil } // ReadFloat64 - читает из io.Reader 8 байт и декодирует их в float64. func ReadFloat64(src io.Reader) (_ float64, err error) { tmp, err := ReadUint64(src) if err != nil { return } return math.Float64frombits(tmp), nil } func ReadString8(src io.Reader) (string, error) { length, err := ReadByteAsInt(src) if err != nil { return "", io.ErrUnexpectedEOF } return ReadString(src, length) } func ReadString16(src io.Reader) (string, error) { length, err := ReadUint16AsInt(src) if err != nil { return "", err } return ReadString(src, length) } // WRITE // WriteInt16 - записывает в io.Writer 2 байта func WriteInt16(w io.Writer, num int16) (err error) { _, err = w.Write([]byte{ byte(num), byte(num >> 8), }) return } // WriteInt24 - записывает в io.Writer 3 байта func WriteInt24(w io.Writer, num int32) (err error) { if num < MinInt24 || num > MaxInt24 { return ErrRange } var sign byte if num < 0 { sign = 128 } _, err = w.Write([]byte{ byte(num), byte(num >> 8), byte((num>>16)&127) | sign, }) return } // WriteInt32 - записывает в io.Writer 4 байта func WriteInt32(w io.Writer, num int32) (err error) { _, err = w.Write([]byte{ byte(num), byte(num >> 8), byte(num >> 16), byte(num >> 24), }) return } // WriteInt48 - записывает в io.Writer 6 байт func WriteInt48(w io.Writer, num int64) (err error) { if num < MinInt48 || num > MaxInt48 { return ErrRange } var sign byte if num < 0 { sign = 128 } _, err = w.Write([]byte{ byte(num), byte(num >> 8), byte(num >> 16), byte(num >> 24), byte(num >> 32), byte((num>>40)&127) | sign, }) return } // WriteInt64 - записывает в io.Writer 8 байт func WriteInt64(w io.Writer, num int64) (err error) { _, err = w.Write([]byte{ byte(num), byte(num >> 8), byte(num >> 16), byte(num >> 24), byte(num >> 32), byte(num >> 40), byte(num >> 48), byte(num >> 56), }) return } // WriteUint16 - записывает в io.Writer 2 байта func WriteUint16(w io.Writer, num uint16) (err error) { _, err = w.Write([]byte{ byte(num), byte(num >> 8), }) return } // WriteUint24 - записывает в io.Writer 3 байта func WriteUint24(w io.Writer, num uint32) (err error) { if num > MaxUint24 { return ErrRange } _, err = w.Write([]byte{ byte(num), byte(num >> 8), byte(num >> 16), }) return } // WriteUint32 - записывает в io.Writer 4 байта func WriteUint32(w io.Writer, num uint32) (err error) { _, err = w.Write([]byte{ byte(num), byte(num >> 8), byte(num >> 16), byte(num >> 24), }) return } // WriteUint48 - записывает в io.Writer 6 байт func WriteUint48(w io.Writer, num uint64) (err error) { if num > MaxUint48 { return ErrRange } _, err = w.Write([]byte{ byte(num), byte(num >> 8), byte(num >> 16), byte(num >> 24), byte(num >> 32), byte(num >> 40), }) return } // WriteUint64 - записывает в io.Writer 8 байт func WriteUint64(w io.Writer, num uint64) (err error) { _, err = w.Write([]byte{ byte(num), byte(num >> 8), byte(num >> 16), byte(num >> 24), byte(num >> 32), byte(num >> 40), byte(num >> 48), byte(num >> 56), }) return } // WriteFloat32 - записывает 4 байта в io.Writer func WriteFloat32(w io.Writer, num float32) error { return WriteUint32(w, math.Float32bits(num)) } // WriteFloat64 - записывает 8 байт в io.Writer func WriteFloat64(w io.Writer, num float64) error { return WriteUint64(w, math.Float64bits(num)) } func WriteString8(w io.Writer, str string) error { if len(str) > 255 { return ErrTooLong } tmp := make([]byte, 1+len(str)) PutString8(tmp, str) _, err := w.Write(tmp) return err } func WriteString16(w io.Writer, str string) error { if len(str) > math.MaxUint16 { return ErrTooLong } tmp := make([]byte, 2+len(str)) PutString16(tmp, str) _, err := w.Write(tmp) return err } // для записи timestamp-ов func WriteInt64AsUint32(w io.Writer, num int64) error { if num < 0 || num > int64(math.MaxUint32) { return ErrRange } return WriteUint32(w, uint32(num)) } // удобное кодирования длины func WriteIntAsByte(w io.Writer, num int) error { if num < 0 || num > math.MaxUint8 { return ErrRange } _, err := w.Write([]byte{ byte(num), }) return err } // удобное кодирования длины func WriteIntAsUint16(w io.Writer, num int) error { if num < 0 || num > math.MaxUint16 { return ErrRange } return WriteUint16(w, uint16(num)) } // удобное кодирования длины func WriteIntAsUint24(w io.Writer, num int) error { if num < 0 || num > MaxUint24 { return ErrRange } return WriteUint24(w, uint32(num)) } // удобное кодирования длины func WriteIntAsUint32(w io.Writer, num int) error { if num < 0 || int64(num) > int64(math.MaxUint32) { return ErrRange } return WriteUint32(w, uint32(num)) } // PUT func PutInt16(a []byte, num int16) error { if len(a) < 2 { return ErrNoSpace } a[0] = byte(num) a[1] = byte(num >> 8) return nil } func PutInt24(a []byte, num int32) error { if num < MinInt24 || num > MaxInt24 { return ErrRange } if len(a) < 3 { return ErrNoSpace } var sign byte if num < 0 { sign = 128 } a[0] = byte(num) a[1] = byte(num >> 8) a[2] = byte((num>>16)&127) | sign return nil } func PutInt32(a []byte, num int32) error { if len(a) < 4 { return ErrNoSpace } a[0] = byte(num) a[1] = byte(num >> 8) a[2] = byte(num >> 16) a[3] = byte(num >> 24) return nil } func PutInt48(a []byte, num int64) error { if num < MinInt48 || num > MaxInt48 { return ErrRange } if len(a) < 6 { return ErrNoSpace } var sign byte if num < 0 { sign = 128 } a[0] = byte(num) a[1] = byte(num >> 8) a[2] = byte(num >> 16) a[3] = byte(num >> 24) a[4] = byte(num >> 32) a[5] = byte((num>>40)&127) | sign return nil } func PutInt64(a []byte, num int64) error { if len(a) < 8 { return ErrNoSpace } a[0] = byte(num) a[1] = byte(num >> 8) a[2] = byte(num >> 16) a[3] = byte(num >> 24) a[4] = byte(num >> 32) a[5] = byte(num >> 40) a[6] = byte(num >> 48) a[7] = byte(num >> 56) return nil } func PutUint16(a []byte, num uint16) error { if len(a) < 2 { return ErrNoSpace } a[0] = byte(num) a[1] = byte(num >> 8) return nil } func PutUint24(a []byte, num uint32) error { if num > MaxUint24 { return ErrRange } if len(a) < 3 { return ErrNoSpace } a[0] = byte(num) a[1] = byte(num >> 8) a[2] = byte(num >> 16) return nil } func PutUint32(a []byte, num uint32) error { if len(a) < 4 { return ErrNoSpace } a[0] = byte(num) a[1] = byte(num >> 8) a[2] = byte(num >> 16) a[3] = byte(num >> 24) return nil } func PutUint48(a []byte, num uint64) error { if num > MaxUint48 { return ErrRange } if len(a) < 6 { return ErrNoSpace } a[0] = byte(num) a[1] = byte(num >> 8) a[2] = byte(num >> 16) a[3] = byte(num >> 24) a[4] = byte(num >> 32) a[5] = byte(num >> 40) return nil } func PutUint64(a []byte, num uint64) error { if len(a) < 8 { return ErrNoSpace } a[0] = byte(num) a[1] = byte(num >> 8) a[2] = byte(num >> 16) a[3] = byte(num >> 24) a[4] = byte(num >> 32) a[5] = byte(num >> 40) a[6] = byte(num >> 48) a[7] = byte(num >> 56) return nil } // PutFloat32 - записывает 4 байта в массив func PutFloat32(a []byte, num float32) error { return PutUint32(a, math.Float32bits(num)) } // PutFloat64 - записывает 8 байт в массив func PutFloat64(a []byte, num float64) error { return PutUint64(a, math.Float64bits(num)) } // PutInt64AsUint32 - записывает 4 байта в массив (для unix timestamp) func PutInt64AsUint32(a []byte, num int64) error { return PutUint32(a, uint32(num)) } // PutIntAsUint16 - записывает 2 байта в массив func PutIntAsUint16(a []byte, num int) error { return PutUint16(a, uint16(num)) } func PutString8(a []byte, str string) error { if len(str) > 255 { return ErrTooLong } if len(a) < (1 + len(str)) { return ErrNoSpace } a[0] = byte(len(str)) copy(a[1:], str) return nil } func PutString16(a []byte, str string) error { if len(str) > math.MaxUint16 { return ErrTooLong } if len(a) < (2 + len(str)) { return ErrNoSpace } PutUint16(a, uint16(len(str))) copy(a[2:], str) return nil } func PutBool(a []byte, flag bool) error { if len(a) == 0 { return ErrNoSpace } if flag { a[0] = 1 } else { a[0] = 0 } return nil } // GET // GetInt16 - читает из массива 2 байта и декодирует их в int16. func GetInt16(a []byte) (num int16, err error) { if len(a) < 2 { return 0, io.ErrUnexpectedEOF } num = int16(a[0]) num |= int16(a[1]) << 8 return } // GetInt24 - читает из массива 3 байта и декодирует их в int32. func GetInt24(a []byte) (num int32, err error) { if len(a) < 3 { return 0, io.ErrUnexpectedEOF } tmp := uint32(a[0]) tmp |= uint32(a[1]) << 8 tmp |= uint32(a[2]&127) << 16 if a[2] > 127 { // для отрицательного числа старшие 9 бит выставляю в единицы tmp |= (1<<9 - 1) << 23 } return int32(tmp), nil } // GetInt32 - читает из массива 4 байта и декодирует их в int32. func GetInt32(a []byte) (num int32, err error) { if len(a) < 4 { return 0, io.ErrUnexpectedEOF } num = int32(a[0]) num |= int32(a[1]) << 8 num |= int32(a[2]) << 16 num |= int32(a[3]) << 24 return } // GetInt48 - читает из массива 6 байт и декодирует их в int64. func GetInt48(a []byte) (int64, error) { if len(a) < 6 { return 0, io.ErrUnexpectedEOF } tmp := uint64(a[0]) tmp |= uint64(a[1]) << 8 tmp |= uint64(a[2]) << 16 tmp |= uint64(a[3]) << 24 tmp |= uint64(a[4]) << 32 tmp |= uint64(a[5]&127) << 40 if a[5] > 127 { // для отрицательного числа старшие 17 бит выставляю в единицы tmp |= (1<<17 - 1) << 47 } return int64(tmp), nil } // GetInt64 - читает из массива 8 байт и декодирует их в int64. func GetInt64(a []byte) (num int64, err error) { if len(a) < 8 { return 0, io.ErrUnexpectedEOF } num = int64(a[0]) num |= int64(a[1]) << 8 num |= int64(a[2]) << 16 num |= int64(a[3]) << 24 num |= int64(a[4]) << 32 num |= int64(a[5]) << 40 num |= int64(a[6]) << 48 num |= int64(a[7]) << 56 return } // GetUint16 - читает из массива 2 байта и декодирует их в uint16. func GetUint16(a []byte) (num uint16, err error) { if len(a) < 2 { return 0, io.ErrUnexpectedEOF } num = uint16(a[0]) num |= uint16(a[1]) << 8 return } // GetUint24 - читает из массива 3 байта и декодирует их в uint32. func GetUint24(a []byte) (num uint32, err error) { if len(a) < 3 { return 0, io.ErrUnexpectedEOF } num = uint32(a[0]) num |= uint32(a[1]) << 8 num |= uint32(a[2]) << 16 return } // GetUint32 - читает из массива 4 байта и декодирует их в uint32. func GetUint32(a []byte) (num uint32, err error) { if len(a) < 4 { return 0, io.ErrUnexpectedEOF } num = uint32(a[0]) num |= uint32(a[1]) << 8 num |= uint32(a[2]) << 16 num |= uint32(a[3]) << 24 return } // GetUint48 - читает из массива 6 байт и декодирует их в uint64. func GetUint48(a []byte) (num uint64, err error) { if len(a) < 6 { return 0, io.ErrUnexpectedEOF } num = uint64(a[0]) num |= uint64(a[1]) << 8 num |= uint64(a[2]) << 16 num |= uint64(a[3]) << 24 num |= uint64(a[4]) << 32 num |= uint64(a[5]) << 40 return } // GetUint64 - читает из массива 8 байт и декодирует их в uint64. func GetUint64(a []byte) (num uint64, err error) { if len(a) < 8 { return 0, io.ErrUnexpectedEOF } num = uint64(a[0]) num |= uint64(a[1]) << 8 num |= uint64(a[2]) << 16 num |= uint64(a[3]) << 24 num |= uint64(a[4]) << 32 num |= uint64(a[5]) << 40 num |= uint64(a[6]) << 48 num |= uint64(a[7]) << 56 return } // GetFloat32 - читает из массива 4 байта и декодирует их в float32. func GetFloat32(a []byte) (float32, error) { tmp, err := GetUint32(a) if err != nil { return 0, err } return math.Float32frombits(tmp), nil } // GetFloat64 - читает из массива 8 байт и декодирует их в float64. func GetFloat64(a []byte) (float64, error) { tmp, err := GetUint64(a) if err != nil { return 0, err } return math.Float64frombits(tmp), nil } func GetString8(a []byte) (string, error) { pSize := 1 if len(a) < pSize { return "", io.ErrUnexpectedEOF } length := int(a[0]) end := pSize + length if len(a) < end { return "", io.ErrUnexpectedEOF } return string(a[pSize:end]), nil } func GetString16(a []byte) (string, error) { pSize := 2 if len(a) < pSize { return "", io.ErrUnexpectedEOF } length, err := GetUint16(a) if err != nil { return "", err } end := pSize + int(length) if len(a) < end { return "", io.ErrUnexpectedEOF } return string(a[pSize:end]), nil } func GetBool(a []byte) (bool, error) { if len(a) == 0 { return false, io.ErrUnexpectedEOF } if a[0] == 1 { return true, nil } else { return false, nil } } func WriteBool(w io.Writer, flag bool) (err error) { var b byte if flag { b = 1 } _, err = w.Write([]byte{b}) return } func ReadBool(src io.Reader) (bool, error) { b, err := ReadByte(src) if err != nil { return false, err } return b == 1, nil } // WRITE & READ VAR INT/UINT // WriteVarUint32 - записывает в Writer от 1 до 5 байт, возвращает количество // записанных байт. Порядок байт - от младшего к старшему. Значение последнего // байта всегда >= 128, остальных < 128. func WriteVarUint32(w io.Writer, num uint32) (i int) { a := make([]byte, 5) for ; i < 5; i++ { a[i] = byte(num & 127) num >>= 7 if num == 0 { break } } a[i] |= 128 i++ w.Write(a[:i]) return } // ReadVarUint32 - читает из io.Reader от 1 до 5 байт, и декодирует их в uint32. func ReadVarUint32(src io.Reader) (num uint32, err error) { var b byte for i := range 5 { b, err = ReadByte(src) if err != nil { return } if b >= 128 { num |= uint32(b&127) << uint(i*7) return } num |= uint32(b) << uint(i*7) } err = fmt.Errorf("value encoded as VarUint32 not found") return } // WriteVarUint64 - записывает в Writer от 1 до 9 байт, возвращает количество // записанных байт. Порядок байт - от младшего к старшему. В 9м байте все биты // значащие. func WriteVarUint64(w io.Writer, num uint64) (int, error) { a := make([]byte, 9) for i := range 8 { a[i] = byte(num & 127) num >>= 7 if num == 0 { a[i] |= 128 i++ return w.Write(a[:i]) } } // в последнем 9м байте все биты значащие a[8] = byte(num) return w.Write(a) } // ReadVarUint64 - читает из io.Reader от 1 до 9 байт, и декодирует их в uint64. func ReadVarUint64(src io.Reader) (num uint64, err error) { var b byte for i := range 8 { b, err = ReadByte(src) if err != nil { return } if b >= 128 { num |= uint64(b&127) << uint(i*7) return } num |= uint64(b) << uint(i*7) } b, err = ReadByte(src) if err != nil { return } // в последнем 9м байте все биты значащие num |= uint64(b) << 56 return } func WriteVarInt64(w io.Writer, num int64) (int, error) { return WriteVarUint64(w, EncodeZigZag(num)) } func ReadVarInt64(r io.Reader) (int64, error) { u64, err := ReadVarUint64(r) if err != nil { return 0, err } return DecodeZigZag(u64), nil } // READ/WRITE VAR SIZE func WriteVarSize(w io.Writer, n int) (int, error) { if n < 0 { return 0, ErrNegativeSize } var ( num = uint64(n) a = make([]byte, 9) ) for i := range 8 { a[i] = byte(num & 127) num >>= 7 if num == 0 { a[i] |= 128 i++ return w.Write(a[:i]) } } // в последнем 9м байте все биты значащие a[8] = byte(num) return w.Write(a) } func ReadVarSize(src io.Reader) (_ int, err error) { var ( b byte num uint64 ) for i := range 8 { b, err = ReadByte(src) if err != nil { return } if b >= 128 { num |= uint64(b&127) << uint(i*7) return int(num), nil } num |= uint64(b) << uint(i*7) } b, err = ReadByte(src) if err != nil { return } // в последнем 9м байте все биты значащие num |= uint64(b) << 56 return int(num), nil } var varUint32Cutoffs = []uint32{ 1 << 7, 1 << 14, 1 << 21, 1 << 28, } func CountVarUint32(n uint32) int { for i, cutoff := range varUint32Cutoffs { if n < cutoff { return i + 1 } } return 5 } var varUint64Cutoffs = []uint64{ 1 << 7, 1 << 14, 1 << 21, 1 << 28, 1 << 35, 1 << 42, 1 << 49, 1 << 56, } func CountVarUint64(n uint64) int { for i, cutoff := range varUint64Cutoffs { if n < cutoff { return i + 1 } } return 9 } var varInt64PlusCutoffs = []int64{ 1 << 6, 1 << 13, 1 << 20, 1 << 27, 1 << 34, 1 << 41, 1 << 48, 1 << 55, } var varInt64MinusCutoffs = []int64{ -1 << 6, -1 << 13, -1 << 20, -1 << 27, -1 << 34, -1 << 41, -1 << 48, -1 << 55, } func CountVarInt64(n int64) int { if n >= 0 { for i, cutoff := range varInt64PlusCutoffs { if n < cutoff { return i + 1 } } } else { for i, cutoff := range varInt64MinusCutoffs { if n >= cutoff { return i + 1 } } } return 9 } func CountVarSize(n int) int { u64 := uint64(n) for i, cutoff := range varUint64Cutoffs { if u64 < cutoff { return i + 1 } } return 9 } // PUT/GET VAR SIZE func PutVarUint64(a []byte, num uint64) (int, error) { var tmp [9]byte for i := range 8 { if i < len(a) { if num < 128 { tmp[i] = byte(num) | 128 q := i + 1 copy(a, tmp[:q]) return q, nil } tmp[i] = byte(num & 127) num >>= 7 } else { return 0, ErrNoSpace } } if len(a) < 9 { return 0, ErrNoSpace } tmp[8] = byte(num) copy(a, tmp[:]) return 9, nil } func GetVarUint64(a []byte) (uint64, int, error) { var num uint64 for i := range 8 { if i < len(a) { b := a[i] num |= uint64(b&127) << uint(i*7) if b >= 128 { return num, i + 1, nil } } else { return 0, 0, ErrNoSpace } } if len(a) < 9 { return 0, 0, ErrNoSpace } num |= uint64(a[8]) << 56 return num, 9, nil } func PutVarSize(arr []byte, n int) (int, error) { if n < 0 { return 0, ErrNegativeSize } return PutVarUint64(arr, uint64(n)) } func GetVarSize(arr []byte) (int, error) { num, _, err := GetVarUint64(arr) if err != nil { return 0, err } return int(num), nil } func PutVarInt64(arr []byte, num int64) (int, error) { return PutVarUint64(arr, EncodeZigZag(num)) } func GetVarInt64(arr []byte) (int64, int, error) { u64, n, err := GetVarUint64(arr) if err != nil { return 0, 0, err } return DecodeZigZag(u64), n, nil } // REVERSE // func reverseCopy(dst []byte, src []byte) error { // if len(dst) >= len(src) { // i := len(dst) - 1 // for _, b := range src { // dst[i] = b // i-- // } // return nil // } // return ErrNoSpace // } func copyReversed(dst []byte, src []byte) error { if len(dst) >= len(src) { j := 0 for i := len(src) - 1; i >= 0; i-- { dst[j] = src[i] j++ } return nil } return ErrNoSpace } // ReversePutVarUint64 - записує закодоване значення як PutVarUint64, але із оберненим // порядком байт. Прочитати значення можна функцією ReverseGetVarUint64, вказавши правильне // початкове зміщення справа. func ReversePutVarUint64(arr []byte, num uint64) (int, error) { var tmp [9]byte for i := range 8 { tmp[i] = byte(num & 127) num >>= 7 if num == 0 { tmp[i] |= 128 n := i + 1 err := copyReversed(arr, tmp[:n]) if err != nil { return 0, err } return n, nil } } tmp[8] = byte(num) err := copyReversed(arr, tmp[:]) if err != nil { return 0, err } return 9, nil } // ReverseGetVarUint64 - читає значення, закодоване функцією ReversePutVarUint64. // Останній байт arr - це молодший байт закодованного значення. func ReverseGetVarUint64(arr []byte) (uint64, int, error) { var ( num uint64 j = len(arr) - 1 ) for i := range 8 { if j >= 0 { b := arr[j] num |= uint64(b&127) << uint(i*7) if b >= 128 { return num, i + 1, nil } j-- } else { return 0, 0, io.EOF } } if j >= 0 { num |= uint64(arr[j]) << 56 return num, 9, nil } return 0, 0, io.EOF } // ReversePutVarInt64 - записує закодоване значення як PutVarInt64, але із оберненим // порядком байт. Прочитати значення можна функцією ReverseGetVarInt64, вказавши правильне // початкове зміщення справа. func ReversePutVarInt64(arr []byte, num int64) (int, error) { return ReversePutVarUint64(arr, EncodeZigZag(num)) } // ReverseGetVarInt64 - читає значення, закодоване функцією ReversePutVarInt64. // Останній байт arr - це молодший байт закодованного значення. func ReverseGetVarInt64(arr []byte) (int64, int, error) { u64, n, err := ReverseGetVarUint64(arr) if err != nil { return 0, 0, err } return DecodeZigZag(u64), n, nil } // TailPutVarUint64 - записує закодоване значення в кінці arr. // Прочитати значення можна функцією GetVarUint64, вказавши правильне // початкове зміщення зліва. func TailPutVarUint64(arr []byte, num uint64) (int, error) { var tmp [9]byte for i := range 8 { tmp[i] = byte(num & 127) num >>= 7 if num == 0 { tmp[i] |= 128 n := i + 1 if len(arr) < n { return 0, ErrNoSpace } copy(arr[len(arr)-n:], tmp[:n]) return n, nil } } tmp[8] = byte(num) if len(arr) < 9 { return 0, ErrNoSpace } copy(arr[len(arr)-9:], tmp[:]) return 9, nil } // TailPutVarInt64 - записує закодоване значення в кінці arr. // Прочитати значення можна функцією GetVarInt64, вказавши правильне // початкове зміщення зліва. func TailPutVarInt64(arr []byte, num int64) (int, error) { return TailPutVarUint64(arr, EncodeZigZag(num)) } // ZigZag encoding: int64 -> uint64 func EncodeZigZag(x int64) uint64 { return uint64(x<<1) ^ uint64(x>>63) } // ZigZag decoding: uint64 -> int64 func DecodeZigZag(u uint64) int64 { return int64(u>>1) ^ -(int64(u & 1)) } func WriteVarSized(w io.Writer, arr []byte) (err error) { _, err = WriteVarSize(w, len(arr)) if err != nil { return } _, err = w.Write(arr) return } func ReadVarSized(src io.Reader) ([]byte, error) { size, err := ReadVarSize(src) if err != nil { return nil, err } return ReadN(src, size) }