summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/mattermost/rsc/arq/unpack.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/mattermost/rsc/arq/unpack.go')
-rw-r--r--vendor/github.com/mattermost/rsc/arq/unpack.go227
1 files changed, 227 insertions, 0 deletions
diff --git a/vendor/github.com/mattermost/rsc/arq/unpack.go b/vendor/github.com/mattermost/rsc/arq/unpack.go
new file mode 100644
index 000000000..ec4296a7c
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/arq/unpack.go
@@ -0,0 +1,227 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parsing of Arq's binary data structures.
+
+package arq
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "reflect"
+ "time"
+)
+
+var errMalformed = fmt.Errorf("malformed data")
+var tagType = reflect.TypeOf(tag(""))
+var timeType = reflect.TypeOf(time.Time{})
+var scoreType = reflect.TypeOf(score{})
+
+func unpack(data []byte, v interface{}) error {
+ data, err := unpackValue(data, reflect.ValueOf(v).Elem(), "")
+ if err != nil {
+ return err
+ }
+ if len(data) != 0 {
+ if len(data) > 100 {
+ return fmt.Errorf("more data than expected: %x...", data[:100])
+ }
+ return fmt.Errorf("more data than expected: %x", data)
+ }
+ return nil
+}
+
+func unpackValue(data []byte, v reflect.Value, tag string) ([]byte, error) {
+ //println("unpackvalue", v.Type().String(), len(data))
+ switch v.Kind() {
+ case reflect.String:
+ if v.Type() == tagType {
+ if tag == "" {
+ panic("arqfs: missing reflect tag on Tag field")
+ }
+ if len(data) < len(tag) || !bytes.Equal(data[:len(tag)], []byte(tag)) {
+ return nil, errMalformed
+ }
+ data = data[len(tag):]
+ return data, nil
+ }
+ if len(data) < 1 {
+ return nil, errMalformed
+ }
+ if data[0] == 0 {
+ data = data[1:]
+ v.SetString("")
+ return data, nil
+ }
+ if data[0] != 1 || len(data) < 1+8 {
+ return nil, errMalformed
+ }
+ n := binary.BigEndian.Uint64(data[1:])
+ data = data[1+8:]
+ if n >= uint64(len(data)) {
+ return nil, errMalformed
+ }
+ str := data[:n]
+ data = data[n:]
+ v.SetString(string(str))
+ return data, nil
+
+ case reflect.Uint32:
+ if len(data) < 4 {
+ return nil, errMalformed
+ }
+ v.SetUint(uint64(binary.BigEndian.Uint32(data)))
+ data = data[4:]
+ return data, nil
+
+ case reflect.Int32:
+ if len(data) < 4 {
+ return nil, errMalformed
+ }
+ v.SetInt(int64(binary.BigEndian.Uint32(data)))
+ data = data[4:]
+ return data, nil
+
+ case reflect.Uint8:
+ if len(data) < 1 {
+ return nil, errMalformed
+ }
+ v.SetUint(uint64(data[0]))
+ data = data[1:]
+ return data, nil
+
+ case reflect.Uint64:
+ if len(data) < 8 {
+ return nil, errMalformed
+ }
+ v.SetUint(binary.BigEndian.Uint64(data))
+ data = data[8:]
+ return data, nil
+
+ case reflect.Int64:
+ if len(data) < 8 {
+ return nil, errMalformed
+ }
+ v.SetInt(int64(binary.BigEndian.Uint64(data)))
+ data = data[8:]
+ return data, nil
+
+ case reflect.Ptr:
+ v.Set(reflect.New(v.Type().Elem()))
+ return unpackValue(data, v.Elem(), tag)
+
+ case reflect.Slice:
+ var n int
+ if tag == "count32" {
+ n32 := binary.BigEndian.Uint32(data)
+ n = int(n32)
+ if uint32(n) != n32 {
+ return nil, errMalformed
+ }
+ data = data[4:]
+ } else {
+ if len(data) < 8 {
+ return nil, errMalformed
+ }
+ n64 := binary.BigEndian.Uint64(data)
+ n = int(n64)
+ if uint64(n) != n64 {
+ return nil, errMalformed
+ }
+ data = data[8:]
+ }
+ v.Set(v.Slice(0, 0))
+ if v.Type().Elem().Kind() == reflect.Uint8 {
+ // Fast case for []byte
+ if len(data) < n {
+ return nil, errMalformed
+ }
+ v.Set(reflect.AppendSlice(v, reflect.ValueOf(data[:n])))
+ return data[n:], nil
+ }
+ for i := 0; i < n; i++ {
+ elem := reflect.New(v.Type().Elem()).Elem()
+ var err error
+ data, err = unpackValue(data, elem, "")
+ if err != nil {
+ return nil, err
+ }
+ v.Set(reflect.Append(v, elem))
+ }
+ return data, nil
+
+ case reflect.Array:
+ if v.Type() == scoreType && tag == "HexScore" {
+ var s string
+ data, err := unpackValue(data, reflect.ValueOf(&s).Elem(), "")
+ if err != nil {
+ return nil, err
+ }
+ if len(s) != 0 {
+ v.Set(reflect.ValueOf(hexScore(s)))
+ }
+ return data, nil
+ }
+ n := v.Len()
+ if v.Type().Elem().Kind() == reflect.Uint8 {
+ // Fast case for [n]byte
+ if len(data) < n {
+ return nil, errMalformed
+ }
+ reflect.Copy(v, reflect.ValueOf(data))
+ data = data[n:]
+ return data, nil
+ }
+ for i := 0; i < n; i++ {
+ var err error
+ data, err = unpackValue(data, v.Index(i), "")
+ if err != nil {
+ return nil, err
+ }
+ }
+ return data, nil
+
+ case reflect.Bool:
+ if len(data) < 1 || data[0] > 1 {
+ if len(data) >= 1 {
+ println("badbool", data[0])
+ }
+ return nil, errMalformed
+ }
+ v.SetBool(data[0] == 1)
+ data = data[1:]
+ return data, nil
+
+ case reflect.Struct:
+ if v.Type() == timeType {
+ if len(data) < 1 || data[0] > 1 {
+ return nil, errMalformed
+ }
+ if data[0] == 0 {
+ v.Set(reflect.ValueOf(time.Time{}))
+ return data[1:], nil
+ }
+ data = data[1:]
+ if len(data) < 8 {
+ return nil, errMalformed
+ }
+ ms := binary.BigEndian.Uint64(data)
+ v.Set(reflect.ValueOf(time.Unix(int64(ms/1e3), int64(ms%1e3)*1e6)))
+ return data[8:], nil
+ }
+ for i := 0; i < v.NumField(); i++ {
+ f := v.Type().Field(i)
+ fv := v.Field(i)
+ var err error
+ data, err = unpackValue(data, fv, f.Tag.Get("arq"))
+ if err != nil {
+ return nil, err
+ }
+ }
+ return data, nil
+ }
+
+ panic("arqfs: unexpected type in unpackValue: " + v.Type().String())
+}