482 lines
12 KiB
Go
482 lines
12 KiB
Go
// Copyright 2019 The ebml-go authors.
|
|
//
|
|
// 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 ebml
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"errors"
|
|
"io"
|
|
"math"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
// DateEpochInUnixtime is the Unixtime of EBML date epoch.
|
|
DateEpochInUnixtime = 978307200
|
|
// SizeUnknown is the longest unknown size value.
|
|
SizeUnknown = 0xffffffffffffff
|
|
)
|
|
|
|
// ErrInvalidFloatSize means that a element size is invalid for float type. Float must be 4 or 8 bytes.
|
|
var ErrInvalidFloatSize = errors.New("invalid float size")
|
|
|
|
// ErrInvalidType means that a value is not convertible to the element data.
|
|
var ErrInvalidType = errors.New("invalid type")
|
|
|
|
// ErrUnsupportedElementID means that a value is out of range of EBML encoding.
|
|
var ErrUnsupportedElementID = errors.New("unsupported Element ID")
|
|
|
|
// ErrOutOfRange means that a value is out of range of the data type.
|
|
var ErrOutOfRange = errors.New("out of range")
|
|
|
|
// valueDecoder is a value decoder sharing internal buffer.
|
|
// Member functions must not called concurrently.
|
|
type valueDecoder struct {
|
|
bs [1]byte
|
|
}
|
|
|
|
func (d *valueDecoder) decode(t DataType, r io.Reader, n uint64) (interface{}, error) {
|
|
switch t {
|
|
case DataTypeInt:
|
|
return d.readInt(r, n)
|
|
case DataTypeUInt:
|
|
return d.readUInt(r, n)
|
|
case DataTypeDate:
|
|
return d.readDate(r, n)
|
|
case DataTypeFloat:
|
|
return d.readFloat(r, n)
|
|
case DataTypeBinary:
|
|
return d.readBinary(r, n)
|
|
case DataTypeString:
|
|
return d.readString(r, n)
|
|
case DataTypeBlock:
|
|
return d.readBlock(r, n)
|
|
}
|
|
panic("invalid data type")
|
|
}
|
|
|
|
func (d *valueDecoder) readDataSize(r io.Reader) (uint64, int, error) {
|
|
v, n, err := d.readVUInt(r)
|
|
if v == (uint64(0xFFFFFFFFFFFFFFFF) >> uint(64-n*7)) {
|
|
return SizeUnknown, n, err
|
|
}
|
|
return v, n, err
|
|
}
|
|
|
|
func (d *valueDecoder) readVUInt(r io.Reader) (uint64, int, error) {
|
|
bytesRead, err := r.Read(d.bs[:])
|
|
switch err {
|
|
case nil:
|
|
case io.EOF:
|
|
return 0, bytesRead, io.ErrUnexpectedEOF
|
|
default:
|
|
return 0, bytesRead, err
|
|
}
|
|
|
|
var vc int
|
|
var value uint64
|
|
|
|
b := d.bs[0]
|
|
switch {
|
|
case b&0x80 == 0x80:
|
|
vc = 0
|
|
value = uint64(b & 0x7F)
|
|
case b&0xC0 == 0x40:
|
|
vc = 1
|
|
value = uint64(b & 0x3F)
|
|
case b&0xE0 == 0x20:
|
|
vc = 2
|
|
value = uint64(b & 0x1F)
|
|
case b&0xF0 == 0x10:
|
|
vc = 3
|
|
value = uint64(b & 0x0F)
|
|
case b&0xF8 == 0x08:
|
|
vc = 4
|
|
value = uint64(b & 0x07)
|
|
case b&0xFC == 0x04:
|
|
vc = 5
|
|
value = uint64(b & 0x03)
|
|
case b&0xFE == 0x02:
|
|
vc = 6
|
|
value = uint64(b & 0x01)
|
|
case b == 0x01:
|
|
vc = 7
|
|
value = 0
|
|
}
|
|
|
|
for {
|
|
if vc == 0 {
|
|
return value, bytesRead, nil
|
|
}
|
|
|
|
n, err := r.Read(d.bs[:])
|
|
switch err {
|
|
case nil:
|
|
case io.EOF:
|
|
return 0, bytesRead, io.ErrUnexpectedEOF
|
|
default:
|
|
return 0, bytesRead, err
|
|
}
|
|
bytesRead += n
|
|
value = value<<8 | uint64(d.bs[0])
|
|
vc--
|
|
}
|
|
}
|
|
|
|
func (d *valueDecoder) readVInt(r io.Reader) (int64, int, error) {
|
|
u, n, err := d.readVUInt(r)
|
|
if err != nil {
|
|
return 0, n, err
|
|
}
|
|
v := int64(u)
|
|
switch n {
|
|
case 1:
|
|
v -= 0x3F
|
|
case 2:
|
|
v -= 0x1FFF
|
|
case 3:
|
|
v -= 0x0FFFFF
|
|
case 4:
|
|
v -= 0x07FFFFFF
|
|
case 5:
|
|
v -= 0x03FFFFFFFF
|
|
case 6:
|
|
v -= 0x01FFFFFFFFFF
|
|
case 7:
|
|
v -= 0x00FFFFFFFFFFFF
|
|
default:
|
|
v -= 0x007FFFFFFFFFFFFF
|
|
}
|
|
return v, n, nil
|
|
}
|
|
|
|
func (d *valueDecoder) readBinary(r io.Reader, n uint64) (interface{}, error) {
|
|
bs := make([]byte, n)
|
|
|
|
switch _, err := io.ReadFull(r, bs); err {
|
|
case nil:
|
|
return bs, nil
|
|
case io.EOF:
|
|
return bs, io.ErrUnexpectedEOF
|
|
default:
|
|
return []byte{}, err
|
|
}
|
|
}
|
|
|
|
func (d *valueDecoder) readString(r io.Reader, n uint64) (interface{}, error) {
|
|
bs, err := d.readBinary(r, n)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
s := string(bs.([]byte))
|
|
// Remove trailing null characters
|
|
ss := strings.Split(s, "\x00")
|
|
return ss[0], nil
|
|
}
|
|
|
|
func (d *valueDecoder) readInt(r io.Reader, n uint64) (interface{}, error) {
|
|
v, err := d.readUInt(r, n)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
v64 := v.(uint64)
|
|
if n != 8 && (v64&(1<<(n*8-1))) != 0 {
|
|
// negative value
|
|
for i := n; i < 8; i++ {
|
|
v64 |= 0xFF << (i * 8)
|
|
}
|
|
}
|
|
return int64(v64), nil
|
|
}
|
|
|
|
func (d *valueDecoder) readUInt(r io.Reader, n uint64) (interface{}, error) {
|
|
bs := make([]byte, n)
|
|
|
|
switch _, err := io.ReadFull(r, bs); err {
|
|
case nil:
|
|
case io.EOF:
|
|
return 0, io.ErrUnexpectedEOF
|
|
default:
|
|
return 0, err
|
|
}
|
|
|
|
var v uint64
|
|
for _, b := range bs {
|
|
v = v<<8 | uint64(b)
|
|
}
|
|
return v, nil
|
|
}
|
|
|
|
func (d *valueDecoder) readDate(r io.Reader, n uint64) (interface{}, error) {
|
|
i, err := d.readInt(r, n)
|
|
if err != nil {
|
|
return time.Unix(0, 0), err
|
|
}
|
|
return time.Unix(DateEpochInUnixtime, i.(int64)), nil
|
|
}
|
|
|
|
func (d *valueDecoder) readFloat(r io.Reader, n uint64) (interface{}, error) {
|
|
bs := make([]byte, n)
|
|
|
|
switch _, err := io.ReadFull(r, bs); err {
|
|
case nil:
|
|
case io.EOF:
|
|
return bs, io.ErrUnexpectedEOF
|
|
default:
|
|
return []byte{}, err
|
|
}
|
|
|
|
switch n {
|
|
case 4:
|
|
return float64(math.Float32frombits(binary.BigEndian.Uint32(bs))), nil
|
|
case 8:
|
|
return math.Float64frombits(binary.BigEndian.Uint64(bs)), nil
|
|
default:
|
|
return 0.0, wrapErrorf(ErrInvalidFloatSize, "reading %d bytes float", n)
|
|
}
|
|
}
|
|
|
|
func (d *valueDecoder) readBlock(r io.Reader, n uint64) (interface{}, error) {
|
|
b, err := UnmarshalBlock(r, int64(n))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return *b, nil
|
|
}
|
|
|
|
var perTypeEncoder = map[DataType]func(interface{}, uint64) ([]byte, error){
|
|
DataTypeInt: encodeInt,
|
|
DataTypeUInt: encodeUInt,
|
|
DataTypeDate: encodeDate,
|
|
DataTypeFloat: encodeFloat,
|
|
DataTypeBinary: encodeBinary,
|
|
DataTypeString: encodeString,
|
|
DataTypeBlock: encodeBlock,
|
|
}
|
|
|
|
func encodeDataSize(v, n uint64) []byte {
|
|
switch {
|
|
case v < 0x80-1 && n < 2:
|
|
return []byte{byte(v) | 0x80}
|
|
case v < 0x4000-1 && n < 3:
|
|
return []byte{byte(v>>8) | 0x40, byte(v)}
|
|
case v < 0x200000-1 && n < 4:
|
|
return []byte{byte(v>>16) | 0x20, byte(v >> 8), byte(v)}
|
|
case v < 0x10000000-1 && n < 5:
|
|
return []byte{byte(v>>24) | 0x10, byte(v >> 16), byte(v >> 8), byte(v)}
|
|
case v < 0x800000000-1 && n < 6:
|
|
return []byte{byte(v>>32) | 0x8, byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)}
|
|
case v < 0x40000000000-1 && n < 7:
|
|
return []byte{byte(v>>40) | 0x4, byte(v >> 32), byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)}
|
|
case v < 0x2000000000000-1 && n < 8:
|
|
return []byte{byte(v>>48) | 0x2, byte(v >> 40), byte(v >> 32), byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)}
|
|
case v < SizeUnknown:
|
|
return []byte{0x1, byte(v >> 48), byte(v >> 40), byte(v >> 32), byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)}
|
|
default:
|
|
return []byte{0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
|
|
}
|
|
}
|
|
|
|
func encodeElementID(v uint64) ([]byte, error) {
|
|
switch {
|
|
case v < 0x80:
|
|
return []byte{byte(v) | 0x80}, nil
|
|
case v < 0x4000:
|
|
return []byte{byte(v>>8) | 0x40, byte(v)}, nil
|
|
case v < 0x200000:
|
|
return []byte{byte(v>>16) | 0x20, byte(v >> 8), byte(v)}, nil
|
|
case v < 0x10000000:
|
|
return []byte{byte(v>>24) | 0x10, byte(v >> 16), byte(v >> 8), byte(v)}, nil
|
|
case v < 0x800000000:
|
|
return []byte{byte(v>>32) | 0x8, byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)}, nil
|
|
case v < 0x40000000000:
|
|
return []byte{byte(v>>40) | 0x4, byte(v >> 32), byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)}, nil
|
|
case v < 0x2000000000000:
|
|
return []byte{byte(v>>48) | 0x2, byte(v >> 40), byte(v >> 32), byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)}, nil
|
|
}
|
|
return nil, ErrUnsupportedElementID
|
|
}
|
|
|
|
func encodeVInt(v int64) ([]byte, error) {
|
|
switch {
|
|
case -0x3F <= v && v <= 0x3F:
|
|
v += 0x3F
|
|
return encodeDataSize(uint64(v), 1), nil
|
|
case -0x1FFF <= v && v <= 0x1FFF:
|
|
v += 0x1FFF
|
|
return encodeDataSize(uint64(v), 2), nil
|
|
case -0xFFFFF <= v && v <= 0xFFFFF:
|
|
v += 0xFFFFF
|
|
return encodeDataSize(uint64(v), 3), nil
|
|
case -0x7FFFFFF <= v && v <= 0x7FFFFFF:
|
|
v += 0x7FFFFFF
|
|
return encodeDataSize(uint64(v), 4), nil
|
|
case -0x3FFFFFFFF <= v && v <= 0x3FFFFFFFF:
|
|
v += 0x3FFFFFFFF
|
|
return encodeDataSize(uint64(v), 5), nil
|
|
case -0x1FFFFFFFFFF <= v && v <= 0x1FFFFFFFFFF:
|
|
v += 0x1FFFFFFFFFF
|
|
return encodeDataSize(uint64(v), 6), nil
|
|
case -0xFFFFFFFFFFFF <= v && v <= 0xFFFFFFFFFFFF:
|
|
v += 0xFFFFFFFFFFFF
|
|
return encodeDataSize(uint64(v), 7), nil
|
|
case -0x7FFFFFFFFFFFFF <= v && v <= 0x7FFFFFFFFFFFFF:
|
|
v += 0x7FFFFFFFFFFFFF
|
|
return encodeDataSize(uint64(v), 8), nil
|
|
default:
|
|
return nil, ErrOutOfRange
|
|
}
|
|
}
|
|
|
|
func encodeBinary(i interface{}, n uint64) ([]byte, error) {
|
|
v, ok := i.([]byte)
|
|
if !ok {
|
|
return []byte{}, ErrInvalidType
|
|
}
|
|
if uint64(len(v)) >= n {
|
|
return v, nil
|
|
}
|
|
return append(v, bytes.Repeat([]byte{0x00}, int(n)-len(v))...), nil
|
|
}
|
|
|
|
func encodeString(i interface{}, n uint64) ([]byte, error) {
|
|
v, ok := i.(string)
|
|
if !ok {
|
|
return []byte{}, wrapErrorf(ErrInvalidType, "writing %T as string", i)
|
|
}
|
|
if uint64(len(v)) >= n {
|
|
return []byte(v), nil
|
|
}
|
|
return append([]byte(v), bytes.Repeat([]byte{0x00}, int(n)-len(v))...), nil
|
|
}
|
|
|
|
func encodeInt(i interface{}, n uint64) ([]byte, error) {
|
|
var v int64
|
|
switch v2 := i.(type) {
|
|
case int:
|
|
v = int64(v2)
|
|
case int8:
|
|
v = int64(v2)
|
|
case int16:
|
|
v = int64(v2)
|
|
case int32:
|
|
v = int64(v2)
|
|
case int64:
|
|
v = v2
|
|
default:
|
|
return []byte{}, wrapErrorf(ErrInvalidType, "writing %T as int", i)
|
|
}
|
|
return encodeUInt(uint64(v), n)
|
|
}
|
|
|
|
func encodeUInt(i interface{}, n uint64) ([]byte, error) {
|
|
var v uint64
|
|
switch v2 := i.(type) {
|
|
case uint:
|
|
v = uint64(v2)
|
|
case uint8:
|
|
v = uint64(v2)
|
|
case uint16:
|
|
v = uint64(v2)
|
|
case uint32:
|
|
v = uint64(v2)
|
|
case uint64:
|
|
v = v2
|
|
default:
|
|
return []byte{}, wrapErrorf(ErrInvalidType, "writing %T as uint", i)
|
|
}
|
|
switch {
|
|
case v < 0x100 && n < 2:
|
|
return []byte{byte(v)}, nil
|
|
case v < 0x10000 && n < 3:
|
|
return []byte{byte(v >> 8), byte(v)}, nil
|
|
case v < 0x1000000 && n < 4:
|
|
return []byte{byte(v >> 16), byte(v >> 8), byte(v)}, nil
|
|
case v < 0x100000000 && n < 5:
|
|
return []byte{byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)}, nil
|
|
case v < 0x10000000000 && n < 6:
|
|
return []byte{byte(v >> 32), byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)}, nil
|
|
case v < 0x1000000000000 && n < 7:
|
|
return []byte{byte(v >> 40), byte(v >> 32), byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)}, nil
|
|
case v < 0x100000000000000 && n < 8:
|
|
return []byte{byte(v >> 48), byte(v >> 40), byte(v >> 32), byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)}, nil
|
|
default:
|
|
return []byte{byte(v >> 56), byte(v >> 48), byte(v >> 40), byte(v >> 32), byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)}, nil
|
|
}
|
|
}
|
|
|
|
func encodeDate(i interface{}, n uint64) ([]byte, error) {
|
|
v, ok := i.(time.Time)
|
|
if !ok {
|
|
return []byte{}, wrapErrorf(ErrInvalidType, "writing %T as date", i)
|
|
}
|
|
dtns := v.Sub(time.Unix(DateEpochInUnixtime, 0)).Nanoseconds()
|
|
return encodeInt(int64(dtns), n)
|
|
}
|
|
|
|
func encodeFloat32(i float32) ([]byte, error) {
|
|
b := make([]byte, 4)
|
|
binary.BigEndian.PutUint32(b, math.Float32bits(i))
|
|
return b, nil
|
|
}
|
|
|
|
func encodeFloat64(i float64) ([]byte, error) {
|
|
b := make([]byte, 8)
|
|
binary.BigEndian.PutUint64(b, math.Float64bits(i))
|
|
return b, nil
|
|
}
|
|
|
|
func encodeFloat(i interface{}, n uint64) ([]byte, error) {
|
|
switch v := i.(type) {
|
|
case float64:
|
|
switch n {
|
|
case 0:
|
|
return encodeFloat64(v)
|
|
case 4:
|
|
return encodeFloat32(float32(v))
|
|
case 8:
|
|
return encodeFloat64(v)
|
|
default:
|
|
return []byte{}, wrapErrorf(ErrInvalidFloatSize, "writing %d bytes float", n)
|
|
}
|
|
case float32:
|
|
switch n {
|
|
case 0:
|
|
return encodeFloat32(v)
|
|
case 4:
|
|
return encodeFloat32(v)
|
|
case 8:
|
|
return encodeFloat64(float64(v))
|
|
default:
|
|
return []byte{}, wrapErrorf(ErrInvalidFloatSize, "writing %d bytes float", n)
|
|
}
|
|
default:
|
|
return []byte{}, wrapErrorf(ErrInvalidType, "writing %T as float", i)
|
|
}
|
|
}
|
|
|
|
func encodeBlock(i interface{}, n uint64) ([]byte, error) {
|
|
v, ok := i.(Block)
|
|
if !ok {
|
|
return []byte{}, wrapErrorf(ErrInvalidType, "writing %T as block", i)
|
|
}
|
|
var b bytes.Buffer
|
|
if err := MarshalBlock(&v, &b); err != nil {
|
|
return []byte{}, err
|
|
}
|
|
return b.Bytes(), nil
|
|
}
|