From 38ee83e45b4de7edf89bf9f0ef629eb4c6ad0fa8 Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Thu, 12 May 2016 23:56:07 -0400 Subject: Moving to glide --- vendor/github.com/mattermost/rsc/arq/unpack.go | 227 +++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 vendor/github.com/mattermost/rsc/arq/unpack.go (limited to 'vendor/github.com/mattermost/rsc/arq/unpack.go') 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()) +} -- cgit v1.2.3-1-g7c22