117 lines
2.1 KiB
Go
117 lines
2.1 KiB
Go
package navicat
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
type reader struct {
|
|
buf []byte
|
|
off int
|
|
}
|
|
|
|
func newReader(b []byte) *reader {
|
|
return &reader{buf: b}
|
|
}
|
|
|
|
func (r *reader) remaining() int {
|
|
return len(r.buf) - r.off
|
|
}
|
|
|
|
func (r *reader) peek() (byte, error) {
|
|
if r.off >= len(r.buf) {
|
|
return 0, io.EOF
|
|
}
|
|
return r.buf[r.off], nil
|
|
}
|
|
|
|
func (r *reader) readByte() (byte, error) {
|
|
if r.off >= len(r.buf) {
|
|
return 0, io.ErrUnexpectedEOF
|
|
}
|
|
b := r.buf[r.off]
|
|
r.off++
|
|
return b, nil
|
|
}
|
|
|
|
func (r *reader) readN(n int) ([]byte, error) {
|
|
if n < 0 {
|
|
return nil, fmt.Errorf("negative length")
|
|
}
|
|
if r.off+n > len(r.buf) {
|
|
return nil, io.ErrUnexpectedEOF
|
|
}
|
|
s := r.buf[r.off : r.off+n]
|
|
r.off += n
|
|
return s, nil
|
|
}
|
|
|
|
func (r *reader) u16() (uint16, error) {
|
|
b, err := r.readN(2)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return binary.BigEndian.Uint16(b), nil
|
|
}
|
|
|
|
func (r *reader) u32() (uint32, error) {
|
|
b, err := r.readN(4)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return binary.BigEndian.Uint32(b), nil
|
|
}
|
|
|
|
// block reads GetBlock. nullable allows 0xFF as SQL NULL (EchoData only).
|
|
func (r *reader) block(nullable bool) (val []byte, isNull bool, err error) {
|
|
if r.off >= len(r.buf) {
|
|
return nil, false, io.ErrUnexpectedEOF
|
|
}
|
|
first := r.buf[r.off]
|
|
if nullable && first == markNull {
|
|
r.off++
|
|
return nil, true, nil
|
|
}
|
|
r.off++
|
|
var n int
|
|
if first < 254 {
|
|
n = int(first)
|
|
} else if first == markLong {
|
|
ln, err := r.u32()
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
if ln > 64<<20 {
|
|
return nil, false, fmt.Errorf("block length %d exceeds 64MiB limit", ln)
|
|
}
|
|
n = int(ln)
|
|
} else {
|
|
return nil, false, fmt.Errorf("invalid block marker 0x%02x", first)
|
|
}
|
|
b, err := r.readN(n)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
return b, false, nil
|
|
}
|
|
|
|
func (r *reader) blockBytes() ([]byte, error) {
|
|
b, isNull, err := r.block(false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if isNull {
|
|
return nil, fmt.Errorf("unexpected NULL block")
|
|
}
|
|
return b, nil
|
|
}
|
|
|
|
func (r *reader) blockString() (string, error) {
|
|
b, err := r.blockBytes()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return string(b), nil
|
|
}
|