blob: 70ca2b312474ccd426ab55b5c361699b5dfe5af0 [file] [log] [blame]
// Copyright 2016-2019 Alex Stocks
//
// 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"
)
import (
perrors "github.com/pkg/errors"
)
/////////////////////////////////////////
// Binary, []byte
/////////////////////////////////////////
// # 8-bit binary data split into 64k chunks
// ::= x41(A) b1 b0 <binary-data> binary # non-final chunk
// ::= x42(B) b1 b0 <binary-data> # final chunk
// ::= [x20-x2f] <binary-data> # binary data of length 0-15
// ::= [x34-x37] <binary-data> # binary data of length 0-1023
func encBinary(b []byte, v []byte) []byte {
var (
length uint16
vLength int
)
if len(v) == 0 {
//return encByte(b, BC_BINARY_DIRECT)
return encByte(b, BC_NULL)
}
vLength = len(v)
for vLength > 0 {
if vLength > CHUNK_SIZE {
length = CHUNK_SIZE
b = encByte(b, BC_BINARY_CHUNK, byte(length>>8), byte(length))
} else {
length = uint16(vLength)
if vLength <= int(BINARY_DIRECT_MAX) {
b = encByte(b, byte(int(BC_BINARY_DIRECT)+vLength))
} else if vLength <= int(BINARY_SHORT_MAX) {
b = encByte(b, byte(int(BC_BINARY_SHORT)+vLength>>8), byte(vLength))
} else {
b = encByte(b, BC_BINARY, byte(vLength>>8), byte(vLength))
}
}
b = append(b, v[:length]...)
v = v[length:]
vLength = len(v)
}
return b
}
/////////////////////////////////////////
// Binary, []byte
/////////////////////////////////////////
// # 8-bit binary data split into 64k chunks
// ::= x41('A') b1 b0 <binary-data> binary # non-final chunk
// ::= x42('B') b1 b0 <binary-data> # final chunk
// ::= [x20-x2f] <binary-data> # binary data of length 0-15
// ::= [x34-x37] <binary-data> # binary data of length 0-1023
func (d *Decoder) getBinaryLength(tag byte) (int, error) {
var (
err error
buf [2]byte
)
if tag >= BC_BINARY_DIRECT && tag <= INT_DIRECT_MAX { // [0x20, 0x2f]
return int(tag - BC_BINARY_DIRECT), nil
}
if tag >= BC_BINARY_SHORT && tag <= byte(0x37) { // [0x34, 0x37]
_, err = io.ReadFull(d.reader, buf[:1])
if err != nil {
return 0, perrors.WithStack(err)
}
return int(tag-BC_BINARY_SHORT)<<8 + int(buf[0]), nil
}
if tag != BC_BINARY_CHUNK && tag != BC_BINARY {
return 0, perrors.Errorf("illegal binary tag:%d", tag)
}
_, err = io.ReadFull(d.reader, buf[:2])
if err != nil {
return 0, perrors.WithStack(err)
}
return int(buf[0])<<8 + int(buf[1]), nil
}
func (d *Decoder) decBinary(flag int32) ([]byte, error) {
var (
err error
tag byte
length int
)
if flag != TAG_READ {
tag = byte(flag)
} else {
tag, err = d.readBufByte()
if err != nil {
return nil, perrors.WithStack(err)
}
}
if tag == BC_NULL {
return []byte(""), nil
}
data := make([]byte, 0)
buf := make([]byte, 65536)
for {
length, err = d.getBinaryLength(tag)
if err != nil {
return nil, perrors.WithStack(err)
}
_, err = io.ReadFull(d.reader, buf[:length])
if err != nil {
return nil, perrors.WithStack(err)
}
data = append(data, buf[:length]...)
if tag != BC_BINARY_CHUNK {
break
}
tag, err = d.readBufByte()
if err != nil {
return nil, perrors.WithStack(err)
}
}
return data, nil
}