blob: 3525981ec589bcb45376c769f957f6572a321de8 [file] [log] [blame]
// Copyright 2016-2019 Alex Stocks, Wongoo
//
// 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 hessian
import (
"io"
"reflect"
)
import (
perrors "github.com/pkg/errors"
)
/////////////////////////////////////////
// List
/////////////////////////////////////////
// # list/vector
// ::= x55 type value* 'Z' # variable-length list
// ::= 'V' type int value* # fixed-length list
// ::= x57 value* 'Z' # variable-length untyped list
// ::= x58 int value* # fixed-length untyped list
// ::= [x70-77] type value* # fixed-length typed list
// ::= [x78-7f] value* # fixed-length untyped list
func (e *Encoder) encUntypedList(v interface{}) error {
var (
err error
)
value := reflect.ValueOf(v)
// check ref
if n, ok := e.checkRefMap(value); ok {
e.buffer = encRef(e.buffer, n)
return nil
}
value = UnpackPtrValue(value)
e.buffer = encByte(e.buffer, BC_LIST_FIXED_UNTYPED) // x58
e.buffer = encInt32(e.buffer, int32(value.Len()))
for i := 0; i < value.Len(); i++ {
if err = e.Encode(value.Index(i).Interface()); err != nil {
return err
}
}
return nil
}
/////////////////////////////////////////
// List
/////////////////////////////////////////
// # list/vector
// ::= x55 type value* 'Z' # variable-length list
// ::= 'V' type int value* # fixed-length list
// ::= x57 value* 'Z' # variable-length untyped list
// ::= x58 int value* # fixed-length untyped list
// ::= [x70-77] type value* # fixed-length typed list
// ::= [x78-7f] value* # fixed-length untyped list
func (d *Decoder) readBufByte() (byte, error) {
var (
err error
buf [1]byte
)
_, err = io.ReadFull(d.reader, buf[:1])
if err != nil {
return 0, perrors.WithStack(err)
}
return buf[0], nil
}
func listFixedTypedLenTag(tag byte) bool {
return tag >= _listFixedTypedLenTagMin && tag <= _listFixedTypedLenTagMax
}
// Include 3 formats:
// list ::= x55 type value* 'Z' # variable-length list
// ::= 'V' type int value* # fixed-length list
// ::= [x70-77] type value* # fixed-length typed list
func typedListTag(tag byte) bool {
return tag == BC_LIST_FIXED || tag == BC_LIST_VARIABLE || listFixedTypedLenTag(tag)
}
func listFixedUntypedLenTag(tag byte) bool {
return tag >= _listFixedUntypedLenTagMin && tag <= _listFixedUntypedLenTagMax
}
// Include 3 formats:
// ::= x57 value* 'Z' # variable-length untyped list
// ::= x58 int value* # fixed-length untyped list
// ::= [x78-7f] value* # fixed-length untyped list
func untypedListTag(tag byte) bool {
return tag == BC_LIST_FIXED_UNTYPED || tag == BC_LIST_VARIABLE_UNTYPED || listFixedUntypedLenTag(tag)
}
//decList read list
func (d *Decoder) decList(flag int32) (interface{}, error) {
var (
err error
tag byte
)
if flag != TAG_READ {
tag = byte(flag)
} else {
tag, err = d.readByte()
if err != nil {
return nil, perrors.WithStack(err)
}
}
switch {
case tag == BC_NULL:
return nil, nil
case tag == BC_REF:
return d.decRef(int32(tag))
case typedListTag(tag):
return d.readTypedList(tag)
case untypedListTag(tag):
return d.readUntypedList(tag)
default:
return nil, perrors.Errorf("error list tag: 0x%x", tag)
}
}
// readTypedList read typed list
// Include 3 formats:
// list ::= x55 type value* 'Z' # variable-length list
// ::= 'V' type int value* # fixed-length list
// ::= [x70-77] type value* # fixed-length typed list
func (d *Decoder) readTypedList(tag byte) (interface{}, error) {
listTyp, err := d.decString(TAG_READ)
if err != nil {
return nil, perrors.Errorf("error to read list type[%s]: %v", listTyp, err)
}
isVariableArr := tag == BC_LIST_VARIABLE
length := -1
if listFixedTypedLenTag(tag) {
length = int(tag - _listFixedTypedLenTagMin)
} else if tag == BC_LIST_FIXED {
ii, err := d.decInt32(TAG_READ)
if err != nil {
return nil, perrors.WithStack(err)
}
length = int(ii)
} else if isVariableArr {
length = 0
} else {
return nil, perrors.Errorf("error typed list tag: 0x%x", tag)
}
// return when no element
if length < 0 {
return nil, nil
}
arr := make([]interface{}, length)
aryValue := reflect.ValueOf(arr)
holder := d.appendRefs(aryValue)
for j := 0; j < length || isVariableArr; j++ {
it, err := d.DecodeValue()
if err != nil {
if err == io.EOF && isVariableArr {
break
}
return nil, perrors.WithStack(err)
}
if it == nil {
break
}
v := EnsureRawValue(it)
if isVariableArr {
aryValue = reflect.Append(aryValue, v)
holder.change(aryValue)
} else {
SetValue(aryValue.Index(j), v)
}
}
return holder, nil
}
//readUntypedList read untyped list
// Include 3 formats:
// ::= x57 value* 'Z' # variable-length untyped list
// ::= x58 int value* # fixed-length untyped list
// ::= [x78-7f] value* # fixed-length untyped list
func (d *Decoder) readUntypedList(tag byte) (interface{}, error) {
isVariableArr := tag == BC_LIST_VARIABLE_UNTYPED
var length int
if listFixedUntypedLenTag(tag) {
length = int(tag - _listFixedUntypedLenTagMin)
} else if tag == BC_LIST_FIXED_UNTYPED {
ii, err := d.decInt32(TAG_READ)
if err != nil {
return nil, perrors.WithStack(err)
}
length = int(ii)
} else if isVariableArr {
length = 0
} else {
return nil, perrors.Errorf("error untyped list tag: %x", tag)
}
ary := make([]interface{}, length)
aryValue := reflect.ValueOf(ary)
holder := d.appendRefs(aryValue)
for j := 0; j < length || isVariableArr; j++ {
it, err := d.DecodeValue()
if err != nil {
if err == io.EOF && isVariableArr {
break
}
return nil, perrors.WithStack(err)
}
if isVariableArr {
aryValue = reflect.Append(aryValue, EnsureRawValue(it))
holder.change(aryValue)
} else {
ary[j] = it
}
}
return holder, nil
}