1
1
mirror of https://github.com/wader/fq.git synced 2024-12-02 04:05:35 +03:00
fq/pkg/decode/decode.go
Mattias Wadman f4480c6fe5 decode,interp: Support for format specific options
interp: Refactor format help and also include options
interp: Add -o name=@path to load file content as value (not documented yet, might change)
interp,decode: Expose decode out value as _out (might change)
interp: Refactor foramts.jq into format_{decode,func,include}.jq
interp: Refactor torepr into _format_func for generic format function overloading
interp: Refactor -o options parsing to be more generic and collect unknowns options to be used as format options
decode of decode alises
func for format overloaded functions
include for format specific jq functions (also _help, torepr etc)
flac_frame: Add bits_per_sample option
mp3: Add max_unique_header_config and max_sync_seek options
mp4: Add decode_samples and allow_truncate options
avc_au: Has length_size option
hevc_au: Has length_size option
aac_frame: Has object_typee option
doc: Rewrite format doc generation, less hack more jq
2022-05-01 17:08:30 +02:00

1245 lines
29 KiB
Go

package decode
import (
"bytes"
"context"
"fmt"
"io"
"io/ioutil"
"math/big"
"github.com/wader/fq/internal/bitioextra"
"github.com/wader/fq/internal/mathextra"
"github.com/wader/fq/internal/recoverfn"
"github.com/wader/fq/pkg/bitio"
"github.com/wader/fq/pkg/ranges"
"github.com/wader/fq/pkg/scalar"
)
//go:generate sh -c "cat decode_gen.go.tmpl | go run ../../dev/tmpl.go types.json | gofmt > decode_gen.go"
type Endian int
const (
// BigEndian byte order
BigEndian = iota
// LittleEndian byte order
LittleEndian
)
type Options struct {
Name string
Description string
Force bool
FillGaps bool
IsRoot bool
Range ranges.Range // if zero use whole buffer
FormatInArg interface{}
FormatInArgFn func(f Format) (interface{}, error)
ReadBuf *[]byte
}
// Decode try decode group and return first success and all other decoder errors
func Decode(ctx context.Context, br bitio.ReaderAtSeeker, group Group, opts Options) (*Value, interface{}, error) {
return decode(ctx, br, group, opts)
}
func decode(ctx context.Context, br bitio.ReaderAtSeeker, group Group, opts Options) (*Value, interface{}, error) {
brLen, err := bitioextra.Len(br)
if err != nil {
return nil, nil, err
}
decodeRange := opts.Range
if decodeRange.IsZero() {
decodeRange = ranges.Range{Len: brLen}
}
if group == nil {
panic("group is nil, failed to register format?")
}
formatsErr := FormatsError{}
for _, f := range group {
var formatInArg interface{}
if opts.FormatInArgFn != nil {
var err error
formatInArg, err = opts.FormatInArgFn(f)
if err != nil {
return nil, nil, err
}
} else {
formatInArg = opts.FormatInArg
if formatInArg == nil {
formatInArg = f.DecodeInArg
}
}
cBR, err := bitioextra.Range(br, decodeRange.Start, decodeRange.Len)
if err != nil {
return nil, nil, IOError{Err: err, Op: "BitBufRange", ReadSize: decodeRange.Len, Pos: decodeRange.Start}
}
d := newDecoder(ctx, f, cBR, opts)
var decodeV interface{}
r, rOk := recoverfn.Run(func() {
decodeV = f.DecodeFn(d, 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,
}
formatsErr.Errs = append(formatsErr.Errs, formatErr)
switch vv := d.Value.V.(type) {
case *Compound:
// TODO: hack, changes V
vv.Err = formatErr
d.Value.V = vv
}
if len(group) != 1 {
continue
}
} else {
r.RePanic()
}
}
// TODO: maybe move to Format* funcs?
if opts.FillGaps {
d.FillGaps(ranges.Range{Start: 0, Len: decodeRange.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 += decodeRange.Start
v.RootReader = br
return nil
}); err != nil {
return nil, nil, err
}
d.Value.Range = ranges.Range{Start: decodeRange.Start, Len: minMaxRange.Len}
if opts.IsRoot {
d.Value.postProcess()
}
if len(formatsErr.Errs) > 0 {
return d.Value, decodeV, formatsErr
}
return d.Value, decodeV, nil
}
return nil, nil, formatsErr
}
type D struct {
Ctx context.Context
Endian Endian
Value *Value
Options Options
bitBuf bitio.ReaderAtSeeker
readBuf *[]byte
}
// TODO: new struct decoder?
// note br is assumed to be a non-shared buffer
func newDecoder(ctx context.Context, format Format, br bitio.ReaderAtSeeker, opts Options) *D {
name := format.RootName
if opts.Name != "" {
name = opts.Name
}
rootV := &Compound{
IsArray: format.RootArray,
Children: nil,
Description: opts.Description,
Format: &format,
}
return &D{
Ctx: ctx,
Endian: BigEndian,
Value: &Value{
Name: name,
V: rootV,
RootReader: br,
Range: ranges.Range{Start: 0, Len: 0},
IsRoot: opts.IsRoot,
},
Options: opts,
bitBuf: br,
readBuf: opts.ReadBuf,
}
}
func (d *D) FieldDecoder(name string, bitBuf bitio.ReaderAtSeeker, 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},
RootReader: bitBuf,
},
Options: d.Options,
bitBuf: bitBuf,
readBuf: d.readBuf,
}
}
func (d *D) CopyBits(w io.Writer, r bitio.Reader) (int64, error) {
// TODO: what size? now same as io.Copy
buf := d.SharedReadBuf(32 * 1024)
return bitioextra.CopyBitsBuffer(w, r, buf)
}
func (d *D) MustCopyBits(w io.Writer, r bitio.Reader) int64 {
n, err := d.CopyBits(w, r)
if err != nil {
d.IOPanic(err, "MustCopy: Copy")
}
return n
}
func (d *D) Copy(w io.Writer, r io.Reader) (int64, error) {
// TODO: what size? now same as io.Copy
buf := d.SharedReadBuf(32 * 1024)
return io.CopyBuffer(w, r, buf)
}
func (d *D) MustCopy(w io.Writer, r io.Reader) int64 {
n, err := d.Copy(w, r)
if err != nil {
d.IOPanic(err, "MustCopy: Copy")
}
return n
}
func (d *D) MustClone(br bitio.ReaderAtSeeker) bitio.ReaderAtSeeker {
br, err := bitioextra.Clone(br)
if err != nil {
d.IOPanic(err, "MustClone")
}
return br
}
func (d *D) MustNewBitBufFromReader(r io.Reader) bitio.ReaderAtSeeker {
b := &bytes.Buffer{}
d.MustCopy(b, r)
return bitio.NewBitReader(b.Bytes(), -1)
}
func (d *D) ReadAllBits(r bitio.Reader) ([]byte, error) {
bb := &bytes.Buffer{}
buf := d.SharedReadBuf(32 * 1024)
if _, err := bitioextra.CopyBitsBuffer(bb, r, buf); err != nil {
return nil, err
}
return bb.Bytes(), nil
}
func (d *D) MustReadAllBits(r bitio.Reader) []byte {
buf, err := d.ReadAllBits(r)
if err != nil {
d.IOPanic(err, "Bytes ReadAllBytes")
}
return buf
}
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 {
br, err := bitioextra.Range(d.bitBuf, gap.Start, gap.Len)
if err != nil {
d.IOPanic(err, "FillGaps: Range")
}
v := &Value{
Name: fmt.Sprintf("%s%d", namePrefix, i),
V: &scalar.S{
Actual: br,
Unknown: true,
},
RootReader: d.bitBuf,
Range: gap,
}
d.AddChild(v)
}
}
// Errorf stops decode with a reason unless forced
func (d *D) Errorf(format string, a ...interface{}) {
if !d.Options.Force {
panic(DecoderError{Reason: fmt.Sprintf(format, a...), Pos: d.Pos()})
}
}
// Fatalf stops decode with a reason regardless of forced
func (d *D) Fatalf(format string, a ...interface{}) {
panic(DecoderError{Reason: fmt.Sprintf(format, a...), Pos: d.Pos()})
}
func (d *D) IOPanic(err error, op string) {
panic(IOError{Err: err, Pos: d.Pos(), Op: op})
}
// Bits reads nBits bits from buffer
func (d *D) bits(nBits int) (uint64, error) {
if nBits < 0 || nBits > 64 {
return 0, fmt.Errorf("nBits must be 0-64 (%d)", nBits)
}
// 64 bits max, 9 byte worse case if not byte aligned
buf := d.SharedReadBuf(9)
_, err := bitio.ReadFull(d.bitBuf, buf, int64(nBits)) // TODO: int64?
if err != nil {
return 0, err
}
return bitio.Read64(buf[:], 0, int64(nBits)), nil // TODO: int64
}
// 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) TryPeekBytes(nBytes int) ([]byte, error) {
start, err := d.bitBuf.SeekBits(0, io.SeekCurrent)
if err != nil {
return nil, err
}
bs, err := d.TryBytesLen(nBytes)
if _, err := d.bitBuf.SeekBits(start, io.SeekStart); err != nil {
return nil, err
}
return bs, err
}
func (d *D) PeekBytes(nBytes int) []byte {
bs, err := d.TryPeekBytes(nBytes)
if err != nil {
panic(IOError{Err: err, Op: "PeekBytes", ReadSize: int64(nBytes) * 8, Pos: d.Pos()})
}
return bs
}
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
}
var count int64
if seekBits < 0 {
count = int64(-nBits)
if _, err := d.bitBuf.SeekBits(start+count, io.SeekStart); err != nil {
return 0, 0, err
}
}
found := false
var v uint64
for {
if (seekBits > 0 && maxLen > 0 && count >= maxLen) || (seekBits < 0 && 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) PeekFind(nBits int, seekBits int64, maxLen int64, fn func(v uint64) bool) (int64, uint64) {
peekBits, v, err := d.TryPeekFind(nBits, seekBits, maxLen, fn)
if err != nil {
d.IOPanic(err, "PeekFind: TryPeekFind")
}
if peekBits == -1 {
d.Errorf("peek not found")
}
return peekBits, v
}
// BytesRange reads nBytes bytes starting bit position start
// Does not update current position.
// TODO: nBytes -1?
func (d *D) TryBytesRange(bitOffset int64, nBytes int) ([]byte, error) {
buf := make([]byte, nBytes)
n, err := bitio.ReadAtFull(d.bitBuf, buf, int64(nBytes)*8, bitOffset)
if n == int64(nBytes)*8 {
err = nil
}
return buf, err
}
func (d *D) BytesRange(firstBit int64, nBytes int) []byte {
bs, err := d.TryBytesRange(firstBit, nBytes)
if err != nil {
panic(IOError{Err: err, Op: "BytesRange", ReadSize: int64(nBytes) * 8, Pos: firstBit})
}
return bs
}
func (d *D) TryBytesLen(nBytes int) ([]byte, error) {
buf := make([]byte, nBytes)
_, err := bitio.ReadFull(d.bitBuf, buf, int64(nBytes)*8)
return buf, err
}
func (d *D) BytesLen(nBytes int) []byte {
bs, err := d.TryBytesLen(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) TryBitBufRange(firstBit int64, nBits int64) (bitio.ReaderAtSeeker, error) {
return bitioextra.Range(d.bitBuf, firstBit, nBits)
}
func (d *D) BitBufRange(firstBit int64, nBits int64) bitio.ReaderAtSeeker {
br, err := bitioextra.Range(d.bitBuf, firstBit, nBits)
if err != nil {
panic(IOError{Err: err, Op: "BitBufRange", ReadSize: nBits, Pos: firstBit})
}
return br
}
func (d *D) TryPos() (int64, error) {
return d.bitBuf.SeekBits(0, io.SeekCurrent)
}
func (d *D) Pos() int64 {
bPos, err := d.TryPos()
if err != nil {
panic(IOError{Err: err, Op: "Pos", ReadSize: 0, Pos: bPos})
}
return bPos
}
func (d *D) TryLen() (int64, error) {
return bitioextra.Len(d.bitBuf)
}
func (d *D) Len() int64 {
l, err := d.TryLen()
if err != nil {
panic(IOError{Err: err, Op: "Len"})
}
return l
}
////
// BitBufLen reads nBits
func (d *D) TryBitBufLen(nBits int64) (bitio.ReaderAtSeeker, error) {
bPos, err := d.TryPos()
if err != nil {
return nil, err
}
br, err := d.TryBitBufRange(bPos, nBits)
if err != nil {
return nil, err
}
if _, err := d.TrySeekRel(nBits); err != nil {
return nil, err
}
return br, nil
}
// End is true if current position is at the end
func (d *D) TryEnd() (bool, error) {
bPos, err := d.TryPos()
if err != nil {
return false, err
}
bLen, err := d.TryLen()
if err != nil {
return false, err
}
return bPos >= bLen, nil
}
func (d *D) End() bool {
bEnd, err := d.TryEnd()
if err != nil {
panic(IOError{Err: err, Op: "End", ReadSize: 0, Pos: d.Pos()})
}
return bEnd
}
func (d *D) NotEnd() bool { return !d.End() }
// BitsLeft number of bits left until end
func (d *D) TryBitsLeft() (int64, error) {
bPos, err := d.TryPos()
if err != nil {
return 0, err
}
bLen, err := d.TryLen()
if err != nil {
return 0, err
}
return bLen - bPos, nil
}
func (d *D) BitsLeft() int64 {
bBitsLeft, err := d.TryBitsLeft()
if err != nil {
panic(IOError{Err: err, Op: "BitsLeft", ReadSize: 0, Pos: d.Pos()})
}
return bBitsLeft
}
// AlignBits number of bits to next nBits align
func (d *D) TryAlignBits(nBits int) (int, error) {
bPos, err := d.TryPos()
if err != nil {
return 0, err
}
return int((int64(nBits) - (bPos % int64(nBits))) % int64(nBits)), nil
}
func (d *D) AlignBits(nBits int) int {
bByteAlignBits, err := d.TryAlignBits(nBits)
if err != nil {
panic(IOError{Err: err, Op: "AlignBits", ReadSize: 0, Pos: d.Pos()})
}
return bByteAlignBits
}
// ByteAlignBits number of bits to next byte align
func (d *D) TryByteAlignBits() (int, error) {
return d.TryAlignBits(8)
}
func (d *D) ByteAlignBits() int {
bByteAlignBits, err := d.TryByteAlignBits()
if err != nil {
panic(IOError{Err: err, Op: "ByteAlignBits", ReadSize: 0, Pos: d.Pos()})
}
return bByteAlignBits
}
// BytePos byte position of current bit position
func (d *D) TryBytePos() (int64, error) {
bPos, err := d.TryPos()
if err != nil {
return 0, err
}
return bPos & 0x7, nil
}
func (d *D) BytePos() int64 {
bBytePos, err := d.TryBytePos()
if err != nil {
panic(IOError{Err: err, Op: "BytePos", ReadSize: 0, Pos: d.Pos()})
}
return bBytePos
}
func (d *D) trySeekAbs(pos int64, fns ...func(d *D)) (int64, error) {
var oldPos int64
if len(fns) > 0 {
oldPos = d.Pos()
}
pos, err := d.bitBuf.SeekBits(pos, io.SeekStart)
if err != nil {
return 0, err
}
if len(fns) > 0 {
for _, fn := range fns {
fn(d)
}
_, err := d.bitBuf.SeekBits(oldPos, io.SeekStart)
if err != nil {
return 0, err
}
}
return pos, nil
}
// SeekRel seeks relative to current bit position
func (d *D) TrySeekRel(delta int64, fns ...func(d *D)) (int64, error) {
return d.trySeekAbs(d.Pos()+delta, fns...)
}
func (d *D) SeekRel(delta int64, fns ...func(d *D)) int64 {
n, err := d.trySeekAbs(d.Pos()+delta, fns...)
if err != nil {
d.IOPanic(err, "SeekRel")
}
return n
}
// SeekAbs seeks to absolute position
func (d *D) TrySeekAbs(pos int64, fns ...func(d *D)) (int64, error) {
return d.trySeekAbs(pos, fns...)
}
func (d *D) SeekAbs(pos int64, fns ...func(d *D)) int64 {
n, err := d.trySeekAbs(pos, fns...)
if err != nil {
d.IOPanic(err, "SeekAbs")
}
return n
}
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.Fatalf("%q already exist in struct %s", v.Name, d.Value.Name)
}
}
}
fv.Children = append(fv.Children, v)
}
}
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, fn func(d *D), sms ...scalar.Mapper) *D {
cd := d.FieldDecoder(name, d.bitBuf, &Compound{IsArray: true})
d.AddChild(cd.Value)
fn(cd)
return cd
}
func (d *D) FieldArrayValue(name string) *D {
return d.FieldArray(name, func(d *D) {})
}
func (d *D) FieldStruct(name string, fn func(d *D)) *D {
cd := d.FieldDecoder(name, d.bitBuf, &Compound{})
d.AddChild(cd.Value)
fn(cd)
return cd
}
func (d *D) FieldStructValue(name string) *D {
return d.FieldStruct(name, func(d *D) {})
}
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.RootReader = d.bitBuf
v.Range = ranges.Range{Start: firstBit, Len: nBits}
d.AddChild(v)
return v
}
func (d *D) AssertAtLeastBitsLeft(nBits int64) {
if d.Options.Force {
return
}
bl := d.BitsLeft()
if bl < nBits {
// TODO:
panic(DecoderError{Reason: fmt.Sprintf("expected bits left %d, found %d", nBits, bl), Pos: d.Pos()})
}
}
func (d *D) AssertLeastBytesLeft(nBytes int64) {
if d.Options.Force {
return
}
bl := d.BitsLeft()
if bl < nBytes*8 {
// TODO:
panic(DecoderError{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, sms ...scalar.Mapper) {
d.FieldScalarFn(name, func(_ scalar.S) (scalar.S, error) { return scalar.S{Actual: a}, nil }, sms...)
}
func (d *D) FieldValueS(name string, a int64, sms ...scalar.Mapper) {
d.FieldScalarFn(name, func(_ scalar.S) (scalar.S, error) { return scalar.S{Actual: a}, nil }, sms...)
}
func (d *D) FieldValueBigInt(name string, a *big.Int, sms ...scalar.Mapper) {
d.FieldScalarFn(name, func(_ scalar.S) (scalar.S, error) { return scalar.S{Actual: a}, nil }, sms...)
}
func (d *D) FieldValueBool(name string, a bool, sms ...scalar.Mapper) {
d.FieldScalarFn(name, func(_ scalar.S) (scalar.S, error) { return scalar.S{Actual: a}, nil }, sms...)
}
func (d *D) FieldValueFloat(name string, a float64, sms ...scalar.Mapper) {
d.FieldScalarFn(name, func(_ scalar.S) (scalar.S, error) { return scalar.S{Actual: a}, nil }, sms...)
}
func (d *D) FieldValueStr(name string, a string, sms ...scalar.Mapper) {
d.FieldScalarFn(name, func(_ scalar.S) (scalar.S, error) { return scalar.S{Actual: a}, nil }, sms...)
}
func (d *D) FieldValueNil(name string, sms ...scalar.Mapper) {
d.FieldScalarFn(name, func(_ scalar.S) (scalar.S, error) { return scalar.S{Actual: nil}, nil }, sms...)
}
func (d *D) FieldValueRaw(name string, a []byte, sms ...scalar.Mapper) {
d.FieldScalarFn(name, func(_ scalar.S) (scalar.S, error) {
return scalar.S{Actual: bitio.NewBitReader(a, -1)}, nil
}, sms...)
}
// FramedFn decode from current position nBits forward. When done position will be nBits forward.
func (d *D) FramedFn(nBits int64, fn func(d *D)) int64 {
if nBits < 0 {
d.Fatalf("%d nBits < 0", nBits)
}
decodeLen := d.RangeFn(d.Pos(), nBits, fn)
d.SeekRel(nBits)
return decodeLen
}
// LimitedFn decode from current position nBits forward. When done position will be set to last bit decoded.
func (d *D) LimitedFn(nBits int64, fn func(d *D)) int64 {
if nBits < 0 {
d.Fatalf("%d nBits < 0", nBits)
}
decodeLen := d.RangeFn(d.Pos(), nBits, fn)
d.SeekRel(decodeLen)
return decodeLen
}
// RangeFn decode from current position nBits forward. Position will not be changed.
func (d *D) RangeFn(firstBit int64, nBits int64, fn func(d *D)) int64 {
var subV interface{}
switch vv := d.Value.V.(type) {
case *Compound:
subV = &Compound{IsArray: vv.IsArray}
default:
panic("unreachable")
}
if nBits < 0 {
nBits = d.Len() - firstBit
}
// TODO: do some kind of DecodeLimitedLen/RangeFn?
br := d.BitBufRange(0, firstBit+nBits)
if _, err := br.SeekBits(firstBit, io.SeekStart); err != nil {
d.IOPanic(err, "RangeFn: SeekAbs")
}
sd := d.FieldDecoder("", br, subV)
startPos := d.Pos()
endPos := startPos
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.RootReader = d.Value.RootReader
endPos = mathextra.MaxInt64(endPos, v.Range.Stop())
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")
}
return endPos - startPos
}
func (d *D) Format(group Group, inArg interface{}) interface{} {
dv, v, err := decode(d.Ctx, d.bitBuf, group, Options{
Force: d.Options.Force,
FillGaps: false,
IsRoot: false,
Range: ranges.Range{Start: d.Pos(), Len: d.BitsLeft()},
FormatInArg: inArg,
ReadBuf: d.readBuf,
})
if dv == nil || dv.Errors() != nil {
d.IOPanic(err, "Format: decode")
}
switch vv := dv.V.(type) {
case *Compound:
for _, f := range vv.Children {
d.AddChild(f)
}
default:
panic("unreachable")
}
if _, err := d.bitBuf.SeekBits(dv.Range.Len, io.SeekCurrent); err != nil {
d.IOPanic(err, "Format: SeekRel")
}
return v
}
func (d *D) TryFieldFormat(name string, group Group, inArg interface{}) (*Value, interface{}, error) {
dv, v, err := decode(d.Ctx, d.bitBuf, group, Options{
Name: name,
Force: d.Options.Force,
FillGaps: false,
IsRoot: false,
Range: ranges.Range{Start: d.Pos(), Len: d.BitsLeft()},
FormatInArg: inArg,
ReadBuf: d.readBuf,
})
if dv == nil || dv.Errors() != nil {
return nil, nil, err
}
d.AddChild(dv)
if _, err := d.bitBuf.SeekBits(dv.Range.Len, io.SeekCurrent); err != nil {
d.IOPanic(err, "TryFieldFormat: SeekRel")
}
return dv, v, err
}
func (d *D) FieldFormat(name string, group Group, inArg interface{}) (*Value, interface{}) {
dv, v, err := d.TryFieldFormat(name, group, inArg)
if dv == nil || dv.Errors() != nil {
d.IOPanic(err, "FieldFormat: TryFieldFormat")
}
return dv, v
}
func (d *D) FieldFormatOrRaw(name string, group Group, inArg interface{}) (*Value, interface{}) {
dv, v, _ := d.TryFieldFormat(name, group, inArg)
if dv == nil {
d.FieldRawLen(name, d.BitsLeft())
}
return dv, v
}
func (d *D) TryFieldFormatLen(name string, nBits int64, group Group, inArg interface{}) (*Value, interface{}, error) {
dv, v, err := decode(d.Ctx, d.bitBuf, group, Options{
Name: name,
Force: d.Options.Force,
FillGaps: true,
IsRoot: false,
Range: ranges.Range{Start: d.Pos(), Len: nBits},
FormatInArg: inArg,
ReadBuf: d.readBuf,
})
if dv == nil || dv.Errors() != nil {
return nil, nil, err
}
d.AddChild(dv)
if _, err := d.bitBuf.SeekBits(nBits, io.SeekCurrent); err != nil {
d.IOPanic(err, "TryFieldFormatLen: SeekRel")
}
return dv, v, err
}
func (d *D) FieldFormatLen(name string, nBits int64, group Group, inArg interface{}) (*Value, interface{}) {
dv, v, err := d.TryFieldFormatLen(name, nBits, group, inArg)
if dv == nil || dv.Errors() != nil {
d.IOPanic(err, "FieldFormatLen: TryFieldFormatLen")
}
return dv, v
}
func (d *D) FieldFormatOrRawLen(name string, nBits int64, group Group, inArg interface{}) (*Value, interface{}) {
dv, v, _ := d.TryFieldFormatLen(name, nBits, group, inArg)
if dv == nil {
d.FieldRawLen(name, nBits)
}
return dv, v
}
// TODO: return decooder?
func (d *D) TryFieldFormatRange(name string, firstBit int64, nBits int64, group Group, inArg interface{}) (*Value, interface{}, error) {
dv, v, err := decode(d.Ctx, d.bitBuf, group, Options{
Name: name,
Force: d.Options.Force,
FillGaps: true,
IsRoot: false,
Range: ranges.Range{Start: firstBit, Len: nBits},
FormatInArg: inArg,
ReadBuf: d.readBuf,
})
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, group Group, inArg interface{}) (*Value, interface{}) {
dv, v, err := d.TryFieldFormatRange(name, firstBit, nBits, group, inArg)
if dv == nil || dv.Errors() != nil {
d.IOPanic(err, "FieldFormatRange: TryFieldFormatRange")
}
return dv, v
}
func (d *D) TryFieldFormatBitBuf(name string, br bitio.ReaderAtSeeker, group Group, inArg interface{}) (*Value, interface{}, error) {
dv, v, err := decode(d.Ctx, br, group, Options{
Name: name,
Force: d.Options.Force,
FillGaps: true,
IsRoot: true,
FormatInArg: inArg,
ReadBuf: d.readBuf,
})
if dv == nil || dv.Errors() != nil {
return nil, nil, err
}
dv.Range.Start = d.Pos()
d.AddChild(dv)
return dv, v, err
}
func (d *D) FieldFormatBitBuf(name string, br bitio.ReaderAtSeeker, group Group, inArg interface{}) (*Value, interface{}) {
dv, v, err := d.TryFieldFormatBitBuf(name, br, group, inArg)
if dv == nil || dv.Errors() != nil {
d.IOPanic(err, "FieldFormatBitBuf: TryFieldFormatBitBuf")
}
return dv, v
}
// TODO: rethink these
func (d *D) FieldRootBitBuf(name string, br bitio.ReaderAtSeeker, sms ...scalar.Mapper) *Value {
brLen, err := bitioextra.Len(br)
if err != nil {
d.IOPanic(err, "br Len")
}
v := &Value{}
v.V = &scalar.S{Actual: br}
v.Name = name
v.RootReader = br
v.IsRoot = true
v.Range = ranges.Range{Start: d.Pos(), Len: brLen}
if err := v.TryScalarFn(sms...); err != nil {
d.Fatalf("%v", err)
}
d.AddChild(v)
return v
}
func (d *D) FieldArrayRootBitBufFn(name string, br bitio.ReaderAtSeeker, fn func(d *D)) *Value {
cd := d.FieldDecoder(name, br, &Compound{IsArray: true})
cd.Value.IsRoot = true
d.AddChild(cd.Value)
fn(cd)
cd.Value.postProcess()
return cd.Value
}
func (d *D) FieldStructRootBitBufFn(name string, br bitio.ReaderAtSeeker, fn func(d *D)) *Value {
cd := d.FieldDecoder(name, br, &Compound{})
cd.Value.IsRoot = true
d.AddChild(cd.Value)
fn(cd)
cd.Value.postProcess()
return cd.Value
}
// TODO: range?
func (d *D) FieldFormatReaderLen(name string, nBits int64, fn func(r io.Reader) (io.ReadCloser, error), group Group) (*Value, interface{}) {
br, err := d.TryBitBufLen(nBits)
if err != nil {
d.IOPanic(err, "FieldFormatReaderLen: BitBufLen")
}
bbBR := bitio.NewIOReader(br)
r, err := fn(bbBR)
if err != nil {
d.IOPanic(err, "FieldFormatReaderLen: fn")
}
rBuf, err := ioutil.ReadAll(r)
if err != nil {
d.IOPanic(err, "FieldFormatReaderLen: ReadAll")
}
rBR := bitio.NewBitReader(rBuf, -1)
return d.FieldFormatBitBuf(name, rBR, group, nil)
}
// TODO: too mant return values
func (d *D) TryFieldReaderRangeFormat(name string, startBit int64, nBits int64, fn func(r io.Reader) io.Reader, group Group, inArg interface{}) (int64, bitio.ReaderAtSeeker, *Value, interface{}, error) {
bitLen := nBits
if bitLen == -1 {
bitLen = d.BitsLeft()
}
br, err := d.TryBitBufRange(startBit, bitLen)
if err != nil {
return 0, nil, nil, nil, err
}
r := bitio.NewIOReadSeeker(br)
rb, err := ioutil.ReadAll(fn(r))
if err != nil {
return 0, nil, nil, nil, err
}
cz, err := r.Seek(0, io.SeekCurrent)
rbr := bitio.NewBitReader(rb, -1)
if err != nil {
return 0, nil, nil, nil, err
}
dv, v, err := d.TryFieldFormatBitBuf(name, rbr, group, inArg)
return cz * 8, rbr, dv, v, err
}
func (d *D) FieldReaderRangeFormat(name string, startBit int64, nBits int64, fn func(r io.Reader) io.Reader, group Group, inArg interface{}) (int64, bitio.ReaderAtSeeker, *Value, interface{}) {
cz, rBR, dv, v, err := d.TryFieldReaderRangeFormat(name, startBit, nBits, fn, group, inArg)
if err != nil {
d.IOPanic(err, "TryFieldReaderRangeFormat")
}
return cz, rBR, dv, v
}
func (d *D) TryFieldValue(name string, fn func() (*Value, error)) (*Value, error) {
start := d.Pos()
v, err := fn()
stop := d.Pos()
v.Name = name
v.RootReader = d.bitBuf
v.Range = ranges.Range{Start: start, Len: stop - start}
if err != nil {
return nil, err
}
d.AddChild(v)
return v, err
}
func (d *D) FieldValue(name string, fn func() *Value) *Value {
v, err := d.TryFieldValue(name, func() (*Value, error) { return fn(), nil })
if err != nil {
d.IOPanic(err, "FieldValue: TryFieldValue")
}
return v
}
// looks a bit weird to force at least one ScalarFn arg
func (d *D) TryFieldScalarFn(name string, sfn scalar.Fn, sms ...scalar.Mapper) (*scalar.S, error) {
v, err := d.TryFieldValue(name, func() (*Value, error) {
s, err := sfn(scalar.S{})
if err != nil {
return &Value{V: &s}, err
}
for _, sm := range sms {
s, err = sm.MapScalar(s)
if err != nil {
return &Value{V: &s}, err
}
}
return &Value{V: &s}, nil
})
if err != nil {
return &scalar.S{}, err
}
sr, ok := v.V.(*scalar.S)
if !ok {
panic("not a scalar value")
}
return sr, nil
}
func (d *D) FieldScalarFn(name string, sfn scalar.Fn, sms ...scalar.Mapper) *scalar.S {
v, err := d.TryFieldScalarFn(name, sfn, sms...)
if err != nil {
d.IOPanic(err, "FieldScalarFn: TryFieldScalarFn")
}
return v
}