// Copyright © 2016 Abcum Ltd // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package keys import ( "bufio" "encoding/binary" "io" "time" ) type reader struct { *bufio.Reader } func newReader(r io.Reader) *reader { return &reader{ bufio.NewReader(r), } } func (r *reader) ReadNext(exp byte) (fnd bool) { byt, _ := r.ReadByte() if exp == byt { return true } r.UnreadByte() return false } func (r *reader) ReadUpto(exp ...byte) (byt []byte) { for i := 0; i < len(exp); i++ { if i == 0 { rng, _ := r.ReadBytes(exp[i]) byt = append(byt, rng...) } if i >= 1 { if r.ReadNext(exp[i]) { byt = append(byt, exp[i]) continue } else { i = 0 } } } return byt[:len(byt)-len(exp)] } // -------------------------------------------------- // -------------------------------------------------- // -------------------------------------------------- // -------------------------------------------------- // -------------------------------------------------- func (r *reader) FindNext() (byt byte) { byt, _ = r.ReadByte() r.UnreadByte() return } func (r *reader) FindAny() (val interface{}) { return r.ReadUpto(cEND) } func (r *reader) FindNull() (val interface{}) { if r.ReadNext(cNIL) { r.ReadNext(cEND) } return } func (r *reader) FindTime() (val time.Time) { if r.ReadNext(cTME) { var out int64 binary.Read(r.Reader, binary.BigEndian, &out) val = time.Unix(0, out).UTC() r.ReadNext(cEND) } return } func (r *reader) FindBool() (val bool) { if r.ReadNext(cVAL) { val = r.ReadNext(cVAL) r.ReadNext(cEND) } return } func (r *reader) FindBytes() (val []byte) { if r.ReadNext(cSTR) { val = r.ReadUpto(cEND, cEND) } return } func (r *reader) FindString() (val string) { if r.ReadNext(cSTR) { val = string(r.ReadUpto(cEND, cEND)) } else if r.ReadNext(cPRE) { val = Prefix r.ReadNext(cEND) } else if r.ReadNext(cSUF) { val = Suffix r.ReadNext(cEND) } return } func (r *reader) FindNumber() (val float64) { if r.ReadNext(cNUMBER) { if r.ReadNext(cNILL) { binary.Read(r.Reader, binary.BigEndian, &val) val = 0 - val r.ReadNext(cTERM) } else if r.ReadNext(cBOOL) { binary.Read(r.Reader, binary.BigEndian, &val) r.ReadNext(cTERM) } } return } func (r *reader) FindNumberInt() (val int) { return int(r.FindNumber()) } func (r *reader) FindNumberInt8() (val int8) { return int8(r.FindNumber()) } func (r *reader) FindNumberInt16() (val int16) { return int16(r.FindNumber()) } func (r *reader) FindNumberInt32() (val int32) { return int32(r.FindNumber()) } func (r *reader) FindNumberInt64() (val int64) { return int64(r.FindNumber()) } func (r *reader) FindNumberUint() (val uint) { return uint(r.FindNumber()) } func (r *reader) FindNumberUint8() (val uint8) { return uint8(r.FindNumber()) } func (r *reader) FindNumberUint16() (val uint16) { return uint16(r.FindNumber()) } func (r *reader) FindNumberUint32() (val uint32) { return uint32(r.FindNumber()) } func (r *reader) FindNumberUint64() (val uint64) { return uint64(r.FindNumber()) } func (r *reader) FindNumberFloat32() (val float32) { return float32(r.FindNumber()) } func (r *reader) FindNumberFloat64() (val float64) { return float64(r.FindNumber()) } func (r *reader) FindArray() (val []interface{}) { if r.ReadNext(cARR) { for !r.ReadNext(cEND) { switch fnd := r.FindNext(); fnd { default: val = append(val, []interface{}{r.FindAny()}...) case cNIL: val = append(val, []interface{}{r.FindNull()}...) case cVAL: val = append(val, []interface{}{r.FindBool()}...) case cTME: val = append(val, []interface{}{r.FindTime()}...) case cNEG, cPOS: val = append(val, []interface{}{r.FindNumber()}...) case cSTR, cPRE, cSUF: val = append(val, []interface{}{r.FindString()}...) case cARR: val = append(val, []interface{}{r.FindArray()}...) } } r.ReadNext(cEND) } return }