mirror of
https://github.com/wader/fq.git
synced 2024-10-04 23:48:00 +03:00
1b32b42f93
Generate more code More generic and comfortable API Improve and Update format decoder to new API Add some more format tests
821 lines
19 KiB
Go
821 lines
19 KiB
Go
package decode
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
|
|
"github.com/wader/fq/internal/recoverfn"
|
|
"github.com/wader/fq/pkg/bitio"
|
|
"github.com/wader/fq/pkg/ranges"
|
|
)
|
|
|
|
type Endian int
|
|
|
|
const (
|
|
// BigEndian byte order
|
|
BigEndian = iota
|
|
// LittleEndian byte order
|
|
LittleEndian
|
|
)
|
|
|
|
type Options struct {
|
|
Name string
|
|
Description string
|
|
FillGaps bool
|
|
IsRoot bool
|
|
Range ranges.Range // if zero use whole buffer
|
|
FormatOptions map[string]interface{}
|
|
FormatInArg interface{}
|
|
ReadBuf *[]byte
|
|
}
|
|
|
|
// Decode try decode formats and return first success and all other decoder errors
|
|
func Decode(ctx context.Context, bb *bitio.Buffer, formats []*Format, opts Options) (*Value, interface{}, error) {
|
|
return decode(ctx, bb, formats, opts)
|
|
}
|
|
|
|
func decode(ctx context.Context, bb *bitio.Buffer, formats []*Format, opts Options) (*Value, interface{}, error) {
|
|
if opts.Range.IsZero() {
|
|
opts.Range = ranges.Range{Len: bb.Len()}
|
|
}
|
|
|
|
if formats == nil {
|
|
panic("formats is nil, failed to register format?")
|
|
}
|
|
|
|
var forceOne = len(formats) == 1
|
|
|
|
decodeErr := FormatsError{}
|
|
|
|
for _, f := range formats {
|
|
cbb, err := bb.BitBufRange(opts.Range.Start, opts.Range.Len)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
d := newDecoder(ctx, f, cbb, opts)
|
|
|
|
var decodeV interface{}
|
|
r, rOk := recoverfn.Run(func() {
|
|
decodeV = f.DecodeFn(d, opts.FormatInArg)
|
|
})
|
|
|
|
if ctx != nil && ctx.Err() != nil {
|
|
return nil, nil, ctx.Err()
|
|
}
|
|
|
|
if !rOk {
|
|
if re, ok := r.RecoverV.(RecoverableErrorer); ok && re.IsRecoverableError() {
|
|
panicErr, _ := re.(error)
|
|
formatErr := FormatError{
|
|
Err: panicErr,
|
|
Format: f,
|
|
Stacktrace: r,
|
|
}
|
|
decodeErr.Errs = append(decodeErr.Errs, formatErr)
|
|
|
|
switch vv := d.Value.V.(type) {
|
|
case Compound:
|
|
// TODO: hack, changes V
|
|
vv.Err = formatErr
|
|
d.Value.V = vv
|
|
}
|
|
|
|
if !forceOne {
|
|
continue
|
|
}
|
|
} else {
|
|
r.RePanic()
|
|
}
|
|
}
|
|
|
|
// TODO: maybe move to Format* funcs?
|
|
if opts.FillGaps {
|
|
d.FillGaps(ranges.Range{Start: 0, Len: opts.Range.Len}, "unknown")
|
|
}
|
|
|
|
var minMaxRange ranges.Range
|
|
if err := d.Value.WalkRootPreOrder(func(v *Value, rootV *Value, depth int, rootDepth int) error {
|
|
minMaxRange = ranges.MinMax(minMaxRange, v.Range)
|
|
v.Range.Start += opts.Range.Start
|
|
v.RootBitBuf = bb
|
|
return nil
|
|
}); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
d.Value.Range = ranges.Range{Start: opts.Range.Start, Len: minMaxRange.Len}
|
|
|
|
if opts.IsRoot {
|
|
d.Value.postProcess()
|
|
}
|
|
|
|
return d.Value, decodeV, decodeErr
|
|
}
|
|
|
|
return nil, nil, decodeErr
|
|
}
|
|
|
|
type D struct {
|
|
Ctx context.Context
|
|
Endian Endian
|
|
Value *Value
|
|
Options map[string]interface{}
|
|
|
|
bitBuf *bitio.Buffer
|
|
|
|
readBuf *[]byte
|
|
}
|
|
|
|
// TODO: new struct decoder?
|
|
// note bb is assumed to be a non-shared buffer
|
|
func newDecoder(ctx context.Context, format *Format, bb *bitio.Buffer, opts Options) *D {
|
|
name := format.RootName
|
|
if opts.Name != "" {
|
|
name = opts.Name
|
|
}
|
|
rootV := Compound{
|
|
IsArray: format.RootArray,
|
|
Children: new([]*Value),
|
|
Description: opts.Description,
|
|
Format: format,
|
|
}
|
|
|
|
return &D{
|
|
Ctx: ctx,
|
|
Endian: BigEndian,
|
|
Value: &Value{
|
|
Name: name,
|
|
V: rootV,
|
|
RootBitBuf: bb,
|
|
Range: ranges.Range{Start: 0, Len: 0},
|
|
IsRoot: opts.IsRoot,
|
|
},
|
|
Options: opts.FormatOptions,
|
|
|
|
bitBuf: bb,
|
|
readBuf: opts.ReadBuf,
|
|
}
|
|
}
|
|
|
|
func (d *D) SharedReadBuf(n int) []byte {
|
|
if d.readBuf == nil {
|
|
d.readBuf = new([]byte)
|
|
}
|
|
if len(*d.readBuf) < n {
|
|
*d.readBuf = make([]byte, n)
|
|
}
|
|
return *d.readBuf
|
|
}
|
|
|
|
func (d *D) FillGaps(r ranges.Range, namePrefix string) {
|
|
makeWalkFn := func(fn func(iv *Value)) func(iv *Value, rootV *Value, depth int, rootDepth int) error {
|
|
return func(iv *Value, rootV *Value, depth int, rootDepth int) error {
|
|
switch iv.V.(type) {
|
|
case Compound:
|
|
default:
|
|
fn(iv)
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// TODO: redo this, tries to get rid of slice grow
|
|
// TODO: pre-sorted somehow?
|
|
n := 0
|
|
_ = d.Value.WalkRootPreOrder(makeWalkFn(func(iv *Value) { n++ }))
|
|
valueRanges := make([]ranges.Range, n)
|
|
i := 0
|
|
_ = d.Value.WalkRootPreOrder(makeWalkFn(func(iv *Value) {
|
|
valueRanges[i] = iv.Range
|
|
i++
|
|
}))
|
|
|
|
gaps := ranges.Gaps(r, valueRanges)
|
|
for i, gap := range gaps {
|
|
bb, err := d.bitBuf.BitBufRange(gap.Start, gap.Len)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
v := &Value{
|
|
Name: fmt.Sprintf("%s%d", namePrefix, i),
|
|
V: Scalar{
|
|
Actual: bb,
|
|
Unknown: true,
|
|
},
|
|
RootBitBuf: d.bitBuf,
|
|
Range: gap,
|
|
}
|
|
|
|
d.AddChild(v)
|
|
}
|
|
}
|
|
|
|
// Invalid stops decode with a reason
|
|
func (d *D) Invalid(reason string) {
|
|
panic(ValidateError{Reason: reason, Pos: d.Pos()})
|
|
}
|
|
|
|
func (d *D) IOPanic(err error) {
|
|
panic(IOError{Err: err, Pos: d.Pos()})
|
|
}
|
|
|
|
// Bits reads nBits bits from buffer
|
|
func (d *D) bits(nBits int) (uint64, error) {
|
|
// 64 bits max, 9 byte worse case if not byte aligned
|
|
buf := d.SharedReadBuf(9)
|
|
_, err := bitio.ReadFull(d.bitBuf, buf, nBits)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
return bitio.Read64(buf[:], 0, nBits), nil
|
|
}
|
|
|
|
// Bits reads nBits bits from buffer
|
|
func (d *D) Bits(nBits int) (uint64, error) {
|
|
n, err := d.bits(nBits)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return n, nil
|
|
}
|
|
|
|
func (d *D) PeekBits(nBits int) uint64 {
|
|
n, err := d.TryPeekBits(nBits)
|
|
if err != nil {
|
|
panic(IOError{Err: err, Op: "PeekBits", ReadSize: int64(nBits), Pos: d.Pos()})
|
|
}
|
|
return n
|
|
}
|
|
|
|
func (d *D) PeekBytes(nBytes int) []byte {
|
|
bs, err := d.bitBuf.PeekBytes(nBytes)
|
|
if err != nil {
|
|
panic(IOError{Err: err, Op: "PeekBytes", ReadSize: int64(nBytes) * 8, Pos: d.Pos()})
|
|
}
|
|
return bs
|
|
}
|
|
|
|
func (d *D) PeekFind(nBits int, seekBits int64, fn func(v uint64) bool, maxLen int64) (int64, uint64) {
|
|
peekBits, v, err := d.TryPeekFind(nBits, seekBits, maxLen, fn)
|
|
if err != nil {
|
|
panic(IOError{Err: err, Op: "PeekFind", ReadSize: 0, Pos: d.Pos()})
|
|
}
|
|
if peekBits == -1 {
|
|
panic(IOError{Err: fmt.Errorf("not found"), Op: "PeekFind", ReadSize: 0, Pos: d.Pos()})
|
|
}
|
|
return peekBits, v
|
|
}
|
|
|
|
func (d *D) TryHasBytes(hb []byte) bool {
|
|
lenHb := len(hb)
|
|
if d.BitsLeft() < int64(lenHb*8) {
|
|
return false
|
|
}
|
|
bs := d.PeekBytes(lenHb)
|
|
return bytes.Equal(hb, bs)
|
|
}
|
|
|
|
// PeekFindByte number of bytes to next v
|
|
func (d *D) PeekFindByte(findV uint8, maxLen int64) int64 {
|
|
peekBits, _, err := d.TryPeekFind(8, 8, maxLen*8, func(v uint64) bool {
|
|
return uint64(findV) == v
|
|
})
|
|
if err != nil {
|
|
panic(IOError{Err: err, Op: "PeekFindByte", ReadSize: 0, Pos: d.Pos()})
|
|
|
|
}
|
|
return peekBits / 8
|
|
}
|
|
|
|
// PeekBits peek nBits bits from buffer
|
|
// TODO: share code?
|
|
func (d *D) TryPeekBits(nBits int) (uint64, error) {
|
|
start, err := d.bitBuf.SeekBits(0, io.SeekCurrent)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
n, err := d.bits(nBits)
|
|
if _, err := d.bitBuf.SeekBits(start, io.SeekStart); err != nil {
|
|
return 0, err
|
|
}
|
|
return n, err
|
|
}
|
|
|
|
func (d *D) TryPeekFind(nBits int, seekBits int64, maxLen int64, fn func(v uint64) bool) (int64, uint64, error) {
|
|
start, err := d.bitBuf.SeekBits(0, io.SeekCurrent)
|
|
if err != nil {
|
|
return 0, 0, err
|
|
}
|
|
|
|
found := false
|
|
var count int64
|
|
var v uint64
|
|
for {
|
|
if maxLen >= 0 && count >= maxLen {
|
|
break
|
|
}
|
|
v, err = d.TryU(nBits)
|
|
if err != nil {
|
|
if _, err := d.bitBuf.SeekBits(start, io.SeekStart); err != nil {
|
|
return 0, 0, err
|
|
}
|
|
return 0, 0, err
|
|
}
|
|
if fn(v) {
|
|
found = true
|
|
break
|
|
}
|
|
count += seekBits
|
|
if _, err := d.bitBuf.SeekBits(start+count, io.SeekStart); err != nil {
|
|
return 0, 0, err
|
|
}
|
|
}
|
|
if _, err := d.bitBuf.SeekBits(start, io.SeekStart); err != nil {
|
|
return 0, 0, err
|
|
}
|
|
|
|
if !found {
|
|
return -1, 0, nil
|
|
}
|
|
|
|
return count, v, nil
|
|
}
|
|
|
|
func (d *D) BytesRange(firstBit int64, nBytes int) []byte {
|
|
bs, err := d.bitBuf.BytesRange(firstBit, nBytes)
|
|
if err != nil {
|
|
panic(IOError{Err: err, Op: "BytesRange", ReadSize: int64(nBytes) * 8, Pos: firstBit})
|
|
}
|
|
return bs
|
|
}
|
|
|
|
func (d *D) BytesLen(nBytes int) []byte {
|
|
bs, err := d.bitBuf.BytesLen(nBytes)
|
|
if err != nil {
|
|
panic(IOError{Err: err, Op: "BytesLen", ReadSize: int64(nBytes) * 8, Pos: d.Pos()})
|
|
}
|
|
return bs
|
|
}
|
|
|
|
// TODO: rename/remove BitBuf name?
|
|
func (d *D) BitBufRange(firstBit int64, nBits int64) *bitio.Buffer {
|
|
bb, err := d.bitBuf.BitBufRange(firstBit, nBits)
|
|
if err != nil {
|
|
panic(IOError{Err: err, Op: "BitBufRange", ReadSize: nBits, Pos: firstBit})
|
|
}
|
|
return bb
|
|
}
|
|
|
|
func (d *D) Pos() int64 {
|
|
bPos, err := d.bitBuf.Pos()
|
|
if err != nil {
|
|
panic(IOError{Err: err, Op: "Pos", ReadSize: 0, Pos: bPos})
|
|
}
|
|
return bPos
|
|
}
|
|
|
|
func (d *D) Len() int64 {
|
|
return d.bitBuf.Len()
|
|
}
|
|
|
|
func (d *D) End() bool {
|
|
bEnd, err := d.bitBuf.End()
|
|
if err != nil {
|
|
panic(IOError{Err: err, Op: "Len", ReadSize: 0, Pos: d.Pos()})
|
|
}
|
|
return bEnd
|
|
}
|
|
|
|
func (d *D) NotEnd() bool { return !d.End() }
|
|
|
|
func (d *D) BitsLeft() int64 {
|
|
bBitsLeft, err := d.bitBuf.BitsLeft()
|
|
if err != nil {
|
|
panic(IOError{Err: err, Op: "BitsLeft", ReadSize: 0, Pos: d.Pos()})
|
|
}
|
|
return bBitsLeft
|
|
}
|
|
|
|
func (d *D) ByteAlignBits() int {
|
|
bByteAlignBits, err := d.bitBuf.ByteAlignBits()
|
|
if err != nil {
|
|
panic(IOError{Err: err, Op: "ByteAlignBits", ReadSize: 0, Pos: d.Pos()})
|
|
}
|
|
return bByteAlignBits
|
|
}
|
|
|
|
func (d *D) BytePos() int64 {
|
|
bBytePos, err := d.bitBuf.BytePos()
|
|
if err != nil {
|
|
panic(IOError{Err: err, Op: "BytePos", ReadSize: 0, Pos: d.Pos()})
|
|
}
|
|
return bBytePos
|
|
}
|
|
|
|
func (d *D) SeekRel(deltaBits int64) int64 {
|
|
pos, err := d.bitBuf.SeekRel(deltaBits)
|
|
if err != nil {
|
|
panic(IOError{Err: err, Op: "SeekRel", SeekPos: deltaBits, Pos: d.Pos()})
|
|
}
|
|
return pos
|
|
}
|
|
|
|
func (d *D) SeekAbs(pos int64) int64 {
|
|
pos, err := d.bitBuf.SeekAbs(pos)
|
|
if err != nil {
|
|
panic(IOError{Err: err, Op: "SeekAbs", SeekPos: pos, Pos: d.Pos()})
|
|
}
|
|
return pos
|
|
}
|
|
|
|
func (d *D) AddChild(v *Value) {
|
|
v.Parent = d.Value
|
|
|
|
switch fv := d.Value.V.(type) {
|
|
case Compound:
|
|
if !fv.IsArray {
|
|
for _, ff := range *fv.Children {
|
|
if ff.Name == v.Name {
|
|
d.Invalid(fmt.Sprintf("%q already exist in struct %s", v.Name, d.Value.Name))
|
|
}
|
|
}
|
|
}
|
|
*fv.Children = append(*fv.Children, v)
|
|
}
|
|
}
|
|
|
|
func (d *D) FieldDecoder(name string, bitBuf *bitio.Buffer, v interface{}) *D {
|
|
return &D{
|
|
Ctx: d.Ctx,
|
|
Endian: d.Endian,
|
|
Value: &Value{
|
|
Name: name,
|
|
V: v,
|
|
Range: ranges.Range{Start: d.Pos(), Len: 0},
|
|
RootBitBuf: bitBuf,
|
|
},
|
|
Options: d.Options,
|
|
|
|
bitBuf: bitBuf,
|
|
readBuf: d.readBuf,
|
|
}
|
|
}
|
|
|
|
func (d *D) FieldRemove(name string) *Value {
|
|
switch fv := d.Value.V.(type) {
|
|
case Compound:
|
|
for fi, ff := range *fv.Children {
|
|
if ff.Name == name {
|
|
*fv.Children = append((*fv.Children)[0:fi], (*fv.Children)[fi+1:]...)
|
|
d.Value.V = fv
|
|
return ff
|
|
}
|
|
}
|
|
panic(fmt.Sprintf("%s not found in struct %s", name, d.Value.Name))
|
|
default:
|
|
panic(fmt.Sprintf("%s is not a struct", d.Value.Name))
|
|
}
|
|
}
|
|
|
|
func (d *D) FieldMustRemove(name string) *Value {
|
|
if v := d.FieldRemove(name); v != nil {
|
|
return v
|
|
}
|
|
panic(fmt.Sprintf("%s not found in struct %s", name, d.Value.Name))
|
|
}
|
|
|
|
func (d *D) FieldGet(name string) *Value {
|
|
switch fv := d.Value.V.(type) {
|
|
case Compound:
|
|
for _, ff := range *fv.Children {
|
|
if ff.Name == name {
|
|
return ff
|
|
}
|
|
}
|
|
default:
|
|
panic(fmt.Sprintf("%s is not a struct", d.Value.Name))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (d *D) FieldMustGet(name string) *Value {
|
|
if v := d.FieldGet(name); v != nil {
|
|
return v
|
|
}
|
|
panic(fmt.Sprintf("%s not found in struct %s", name, d.Value.Name))
|
|
}
|
|
|
|
func (d *D) FieldArray(name string, fns ...func(d *D)) *D {
|
|
cd := d.FieldDecoder(name, d.bitBuf, Compound{IsArray: true, Children: new([]*Value)})
|
|
d.AddChild(cd.Value)
|
|
for _, fn := range fns {
|
|
fn(cd)
|
|
}
|
|
return cd
|
|
}
|
|
|
|
func (d *D) FieldStruct(name string, fns ...func(d *D)) *D {
|
|
cd := d.FieldDecoder(name, d.bitBuf, Compound{Children: new([]*Value)})
|
|
d.AddChild(cd.Value)
|
|
for _, fn := range fns {
|
|
fn(cd)
|
|
}
|
|
return cd
|
|
}
|
|
|
|
func (d *D) FieldStructArrayLoop(name string, structName string, condFn func() bool, fn func(d *D)) *D {
|
|
return d.FieldArray(name, func(d *D) {
|
|
for condFn() {
|
|
d.FieldStruct(structName, fn)
|
|
}
|
|
})
|
|
}
|
|
|
|
func (d *D) FieldArrayLoop(name string, condFn func() bool, fn func(d *D)) *D {
|
|
return d.FieldArray(name, func(d *D) {
|
|
for condFn() {
|
|
fn(d)
|
|
}
|
|
})
|
|
}
|
|
|
|
func (d *D) FieldRangeFn(name string, firstBit int64, nBits int64, fn func() *Value) *Value {
|
|
v := fn()
|
|
v.Name = name
|
|
v.RootBitBuf = d.bitBuf
|
|
v.Range = ranges.Range{Start: firstBit, Len: nBits}
|
|
d.AddChild(v)
|
|
|
|
return v
|
|
}
|
|
|
|
func (d *D) AssertAtLeastBitsLeft(nBits int64) {
|
|
bl := d.BitsLeft()
|
|
if bl < nBits {
|
|
// TODO:
|
|
panic(ValidateError{Reason: fmt.Sprintf("expected bits left %d, found %d", nBits, bl), Pos: d.Pos()})
|
|
}
|
|
}
|
|
|
|
func (d *D) AssertLeastBytesLeft(nBytes int64) {
|
|
bl := d.BitsLeft()
|
|
if bl < nBytes*8 {
|
|
// TODO:
|
|
panic(ValidateError{Reason: fmt.Sprintf("expected bytes left %d, found %d bits", nBytes, bl), Pos: d.Pos()})
|
|
}
|
|
}
|
|
|
|
// TODO: rethink
|
|
func (d *D) FieldValueU(name string, a uint64, sfns ...ScalarFn) {
|
|
d.FieldScalar(name, func(_ Scalar) (Scalar, error) { return Scalar{Actual: a}, nil }, sfns...)
|
|
}
|
|
|
|
func (d *D) FieldValueS(name string, a int64, sfns ...ScalarFn) {
|
|
d.FieldScalar(name, func(_ Scalar) (Scalar, error) { return Scalar{Actual: a}, nil }, sfns...)
|
|
}
|
|
|
|
func (d *D) FieldValueBool(name string, a bool, sfns ...ScalarFn) {
|
|
d.FieldScalar(name, func(_ Scalar) (Scalar, error) { return Scalar{Actual: a}, nil }, sfns...)
|
|
}
|
|
|
|
func (d *D) FieldValueFloat(name string, a float64, sfns ...ScalarFn) {
|
|
d.FieldScalar(name, func(_ Scalar) (Scalar, error) { return Scalar{Actual: a}, nil }, sfns...)
|
|
}
|
|
|
|
func (d *D) FieldValueStr(name string, a string, sfns ...ScalarFn) {
|
|
d.FieldScalar(name, func(_ Scalar) (Scalar, error) { return Scalar{Actual: a}, nil }, sfns...)
|
|
}
|
|
|
|
func (d *D) FieldValueRaw(name string, a []byte, sfns ...ScalarFn) {
|
|
d.FieldScalar(name, func(_ Scalar) (Scalar, error) { return Scalar{Actual: bitio.NewBufferFromBytes(a, -1)}, nil }, sfns...)
|
|
}
|
|
|
|
func (d *D) LenFn(nBits int64, fn func(d *D)) {
|
|
d.RangeFn(d.Pos(), nBits, fn)
|
|
d.SeekRel(nBits)
|
|
}
|
|
|
|
func (d *D) RangeFn(firstBit int64, nBits int64, fn func(d *D)) {
|
|
var subV interface{}
|
|
switch vv := d.Value.V.(type) {
|
|
case Compound:
|
|
subV = Compound{IsArray: vv.IsArray, Children: new([]*Value)}
|
|
default:
|
|
panic("unreachable")
|
|
}
|
|
|
|
// TODO: do some kind of DecodeLimitedLen/RangeFn?
|
|
bb := d.BitBufRange(0, firstBit+nBits)
|
|
if _, err := bb.SeekAbs(firstBit); err != nil {
|
|
panic(IOError{Err: err, Op: "SeekAbs", Pos: firstBit})
|
|
}
|
|
sd := d.FieldDecoder("", bb, subV)
|
|
|
|
fn(sd)
|
|
|
|
// TODO: refactor, similar to decode()
|
|
if err := sd.Value.WalkRootPreOrder(func(v *Value, rootV *Value, depth int, rootDepth int) error {
|
|
//v.Range.Start += firstBit
|
|
v.RootBitBuf = d.Value.RootBitBuf
|
|
|
|
return nil
|
|
}); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
switch vv := sd.Value.V.(type) {
|
|
case Compound:
|
|
for _, f := range *vv.Children {
|
|
d.AddChild(f)
|
|
}
|
|
default:
|
|
panic("unreachable")
|
|
}
|
|
}
|
|
|
|
func (d *D) Format(formats []*Format, inArg interface{}) interface{} {
|
|
dv, v, err := decode(d.Ctx, d.bitBuf, formats, Options{
|
|
ReadBuf: d.readBuf,
|
|
FillGaps: false,
|
|
IsRoot: false,
|
|
Range: ranges.Range{Start: d.Pos(), Len: d.BitsLeft()},
|
|
FormatInArg: inArg,
|
|
})
|
|
if dv == nil || dv.Errors() != nil {
|
|
panic(err)
|
|
}
|
|
|
|
switch vv := dv.V.(type) {
|
|
case Compound:
|
|
for _, f := range *vv.Children {
|
|
d.AddChild(f)
|
|
}
|
|
default:
|
|
panic("unreachable")
|
|
}
|
|
|
|
if _, err := d.bitBuf.SeekRel(dv.Range.Len); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return v
|
|
}
|
|
|
|
func (d *D) FieldTryFormat(name string, formats []*Format, inArg interface{}) (*Value, interface{}, error) {
|
|
dv, v, err := decode(d.Ctx, d.bitBuf, formats, Options{
|
|
Name: name,
|
|
ReadBuf: d.readBuf,
|
|
FillGaps: false,
|
|
IsRoot: false,
|
|
Range: ranges.Range{Start: d.Pos(), Len: d.BitsLeft()},
|
|
FormatInArg: inArg,
|
|
})
|
|
if dv == nil || dv.Errors() != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
d.AddChild(dv)
|
|
if _, err := d.bitBuf.SeekRel(dv.Range.Len); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return dv, v, err
|
|
}
|
|
|
|
func (d *D) FieldFormat(name string, formats []*Format, inArg interface{}) (*Value, interface{}) {
|
|
dv, v, err := d.FieldTryFormat(name, formats, inArg)
|
|
if dv == nil || dv.Errors() != nil {
|
|
panic(err)
|
|
}
|
|
return dv, v
|
|
}
|
|
|
|
func (d *D) FieldTryFormatLen(name string, nBits int64, formats []*Format, inArg interface{}) (*Value, interface{}, error) {
|
|
dv, v, err := decode(d.Ctx, d.bitBuf, formats, Options{
|
|
Name: name,
|
|
ReadBuf: d.readBuf,
|
|
FillGaps: true,
|
|
IsRoot: false,
|
|
Range: ranges.Range{Start: d.Pos(), Len: nBits},
|
|
FormatInArg: inArg,
|
|
})
|
|
if dv == nil || dv.Errors() != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
d.AddChild(dv)
|
|
if _, err := d.bitBuf.SeekRel(nBits); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return dv, v, err
|
|
}
|
|
|
|
func (d *D) FieldFormatLen(name string, nBits int64, formats []*Format, inArg interface{}) (*Value, interface{}) {
|
|
dv, v, err := d.FieldTryFormatLen(name, nBits, formats, inArg)
|
|
if dv == nil || dv.Errors() != nil {
|
|
panic(err)
|
|
}
|
|
return dv, v
|
|
}
|
|
|
|
// TODO: return decooder?
|
|
func (d *D) FieldTryFormatRange(name string, firstBit int64, nBits int64, formats []*Format, inArg interface{}) (*Value, interface{}, error) {
|
|
dv, v, err := decode(d.Ctx, d.bitBuf, formats, Options{
|
|
Name: name,
|
|
ReadBuf: d.readBuf,
|
|
FillGaps: true,
|
|
IsRoot: false,
|
|
Range: ranges.Range{Start: firstBit, Len: nBits},
|
|
FormatInArg: inArg,
|
|
})
|
|
if dv == nil || dv.Errors() != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
d.AddChild(dv)
|
|
|
|
return dv, v, err
|
|
}
|
|
|
|
func (d *D) FieldFormatRange(name string, firstBit int64, nBits int64, formats []*Format, inArg interface{}) (*Value, interface{}) {
|
|
dv, v, err := d.FieldTryFormatRange(name, firstBit, nBits, formats, inArg)
|
|
if dv == nil || dv.Errors() != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return dv, v
|
|
}
|
|
|
|
func (d *D) FieldTryFormatBitBuf(name string, bb *bitio.Buffer, formats []*Format, inArg interface{}) (*Value, interface{}, error) {
|
|
dv, v, err := decode(d.Ctx, bb, formats, Options{
|
|
Name: name,
|
|
ReadBuf: d.readBuf,
|
|
FillGaps: true,
|
|
IsRoot: true,
|
|
FormatInArg: inArg,
|
|
})
|
|
if dv == nil || dv.Errors() != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
d.AddChild(dv)
|
|
|
|
return dv, v, err
|
|
}
|
|
|
|
func (d *D) FieldFormatBitBuf(name string, bb *bitio.Buffer, formats []*Format, inArg interface{}) (*Value, interface{}) {
|
|
dv, v, err := d.FieldTryFormatBitBuf(name, bb, formats, inArg)
|
|
if dv == nil || dv.Errors() != nil {
|
|
panic(err)
|
|
}
|
|
return dv, v
|
|
}
|
|
|
|
// TODO: rethink this
|
|
func (d *D) FieldRootBitBuf(name string, bb *bitio.Buffer) *Value {
|
|
v := &Value{}
|
|
v.V = Scalar{Actual: bb}
|
|
v.Name = name
|
|
v.RootBitBuf = bb
|
|
v.IsRoot = true
|
|
v.Range = ranges.Range{Start: 0, Len: bb.Len()}
|
|
d.AddChild(v)
|
|
|
|
return v
|
|
}
|
|
|
|
func (d *D) FieldStructRootBitBufFn(name string, bb *bitio.Buffer, fn func(d *D)) *Value {
|
|
cd := d.FieldDecoder(name, bb, Compound{Children: new([]*Value)})
|
|
cd.Value.IsRoot = true
|
|
d.AddChild(cd.Value)
|
|
fn(cd)
|
|
|
|
return cd.Value
|
|
}
|
|
|
|
// TODO: range?
|
|
func (d *D) FieldFormatReaderLen(name string, nBits int64, fn func(r io.Reader) (io.ReadCloser, error), formats []*Format) (*Value, interface{}) {
|
|
bb, err := d.bitBuf.BitBufLen(nBits)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
zr, err := fn(bb)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
zd, err := ioutil.ReadAll(zr)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
zbb := bitio.NewBufferFromBytes(zd, -1)
|
|
|
|
return d.FieldFormatBitBuf(name, zbb, formats, nil)
|
|
}
|