1
0
mirror of https://github.com/Mrs4s/go-cqhttp.git synced 2025-05-05 03:23:49 +08:00
go-cqhttp/db/leveldb/reader.go
wdvxdr 2a66896d43
coolq: new package cqcode
move cqcode escape&unescape to new package
2022-02-16 01:14:35 +08:00

132 lines
2.9 KiB
Go

package leveldb
import (
"encoding/binary"
"io"
"strconv"
"strings"
"github.com/pkg/errors"
"github.com/Mrs4s/go-cqhttp/global"
)
type intReader struct {
data string
*strings.Reader
}
func newIntReader(s string) intReader {
return intReader{
data: s,
Reader: strings.NewReader(s),
}
}
func (r *intReader) varint() int64 {
i, _ := binary.ReadVarint(r)
return i
}
func (r *intReader) uvarint() uint64 {
i, _ := binary.ReadUvarint(r)
return i
}
// reader implements the index read.
// data format is the same as the writer's
type reader struct {
data intReader
strings intReader
stringIndex map[uint64]string
}
func (r *reader) coder() coder { o, _ := r.data.ReadByte(); return coder(o) }
func (r *reader) varint() int64 { return r.data.varint() }
func (r *reader) uvarint() uint64 { return r.data.uvarint() }
func (r *reader) int32() int32 { return int32(r.varint()) }
func (r *reader) int64() int64 { return r.varint() }
func (r *reader) uint64() uint64 { return r.uvarint() }
// func (r *reader) uint32() uint32 { return uint32(r.uvarint()) }
// func (r *reader) int() int { return int(r.varint()) }
// func (r *reader) uint() uint { return uint(r.uvarint()) }
func (r *reader) string() string {
off := r.data.uvarint()
if s, ok := r.stringIndex[off]; ok {
return s
}
_, _ = r.strings.Seek(int64(off), io.SeekStart)
l := int64(r.strings.uvarint())
whence, _ := r.strings.Seek(0, io.SeekCurrent)
s := r.strings.data[whence : whence+l]
r.stringIndex[off] = s
return s
}
func (r *reader) msg() global.MSG {
length := r.uvarint()
msg := make(global.MSG, length)
for i := uint64(0); i < length; i++ {
s := r.string()
msg[s] = r.obj()
}
return msg
}
func (r *reader) arrayMsg() []global.MSG {
length := r.uvarint()
msgs := make([]global.MSG, length)
for i := range msgs {
msgs[i] = r.msg()
}
return msgs
}
func (r *reader) obj() interface{} {
switch coder := r.coder(); coder {
case coderNil:
return nil
case coderInt:
return int(r.varint())
case coderUint:
return uint(r.uvarint())
case coderInt32:
return int32(r.varint())
case coderUint32:
return uint32(r.uvarint())
case coderInt64:
return r.varint()
case coderUint64:
return r.uvarint()
case coderString:
return r.string()
case coderMSG:
return r.msg()
case coderArrayMSG:
return r.arrayMsg()
default:
panic("db/leveldb: invalid coder " + strconv.Itoa(int(coder)))
}
}
func newReader(data string) (*reader, error) {
in := newIntReader(data)
v := in.uvarint()
if v != dataVersion {
return nil, errors.Errorf("db/leveldb: invalid data version %d", v)
}
sl := int64(in.uvarint())
dl := int64(in.uvarint())
whence, _ := in.Seek(0, io.SeekCurrent)
sData := data[whence : whence+sl]
dData := data[whence+sl : whence+sl+dl]
r := reader{
data: newIntReader(dData),
strings: newIntReader(sData),
stringIndex: make(map[uint64]string),
}
return &r, nil
}