mirror of
https://github.com/wader/fq.git
synced 2024-09-11 12:05:39 +03:00
interp,decode: Support decode group argument
Will be used for probing via -d <string> and filename
This commit is contained in:
parent
ee729c2d61
commit
684a083813
@ -1,6 +1,11 @@
|
||||
package format
|
||||
|
||||
import "github.com/wader/fq/pkg/decode"
|
||||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/wader/fq/pkg/decode"
|
||||
)
|
||||
|
||||
// TODO: do before-format somehow and topology sort?
|
||||
const (
|
||||
@ -12,9 +17,36 @@ const (
|
||||
|
||||
// TODO: move to group package somehow?
|
||||
|
||||
type Probe_In struct {
|
||||
IsProbe bool
|
||||
Filename string
|
||||
}
|
||||
|
||||
// Use HasExt("cer", "CeR", ...)
|
||||
func (pi Probe_In) HasExt(ss ...string) bool {
|
||||
ext := filepath.Ext(pi.Filename)
|
||||
if ext == "" {
|
||||
return false
|
||||
}
|
||||
ext = ext[1:]
|
||||
for _, s := range ss {
|
||||
if strings.EqualFold(s, ext) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type Probe_Args_In struct {
|
||||
IsProbeArgs bool
|
||||
Filename string
|
||||
DecodeGroup string
|
||||
}
|
||||
|
||||
var (
|
||||
Image = &decode.Group{Name: "image"}
|
||||
Probe = &decode.Group{Name: "probe"}
|
||||
Probe = &decode.Group{Name: "probe", DefaultInArg: Probe_In{}}
|
||||
Probe_Args = &decode.Group{Name: "probe_args", DefaultInArg: Probe_Args_In{}}
|
||||
Link_Frame = &decode.Group{Name: "link_frame", DefaultInArg: Link_Frame_In{}} // ex: ethernet
|
||||
INET_Packet = &decode.Group{Name: "inet_packet", DefaultInArg: INET_Packet_In{}} // ex: ipv4
|
||||
IP_Packet = &decode.Group{Name: "ip_packet", DefaultInArg: INET_Packet_In{}} // ex: tcp
|
||||
|
@ -90,3 +90,7 @@ func (r *Reader) Seek(offset int64, whence int) (int64, error) {
|
||||
|
||||
return absOff, nil
|
||||
}
|
||||
|
||||
func (r *Reader) Unwrap() any {
|
||||
return r.rs
|
||||
}
|
||||
|
@ -87,3 +87,7 @@ func (r *Reader) Close() (err error) {
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *Reader) Unwrap() any {
|
||||
return r.rs
|
||||
}
|
||||
|
@ -54,3 +54,15 @@ func (o DiscardCtxWriter) Write(p []byte) (n int, err error) {
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func Unwrap(r any) any {
|
||||
for {
|
||||
u, ok := r.(interface {
|
||||
Unwrap() any
|
||||
})
|
||||
if !ok {
|
||||
return r
|
||||
}
|
||||
r = u.Unwrap()
|
||||
}
|
||||
}
|
||||
|
@ -64,3 +64,7 @@ func (prs *Reader) Seek(offset int64, whence int) (int64, error) {
|
||||
prs.pos = pos
|
||||
return pos, err
|
||||
}
|
||||
|
||||
func (prs *Reader) Unwrap() any {
|
||||
return prs.rs
|
||||
}
|
||||
|
@ -100,3 +100,7 @@ func (r *IOBitReadSeeker) CloneReadAtSeeker() (ReadAtSeeker, error) {
|
||||
func (r *IOBitReadSeeker) CloneReaderAtSeeker() (ReaderAtSeeker, error) {
|
||||
return NewIOBitReadSeeker(r.rs), nil
|
||||
}
|
||||
|
||||
func (r *IOBitReadSeeker) Unwrap() any {
|
||||
return r.rs
|
||||
}
|
||||
|
@ -62,3 +62,7 @@ func (w *IOBitWriter) Flush() error {
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *IOBitWriter) Unwrap() any {
|
||||
return w.w
|
||||
}
|
||||
|
@ -73,3 +73,7 @@ func (r *IOReader) ReadByte() (byte, error) {
|
||||
_, err := r.Read(rb[:])
|
||||
return rb[0], err
|
||||
}
|
||||
|
||||
func (r *IOReader) Unwrap() any {
|
||||
return r.r
|
||||
}
|
||||
|
@ -36,3 +36,7 @@ func (r *IOReadSeeker) Seek(offset int64, whence int) (int64, error) {
|
||||
|
||||
return n / 8, err
|
||||
}
|
||||
|
||||
func (r *IOReadSeeker) Unwrap() any {
|
||||
return r.IOReader
|
||||
}
|
||||
|
@ -33,3 +33,7 @@ func (l *LimitReader) CloneReader() (Reader, error) {
|
||||
}
|
||||
return &LimitReader{r: rc, n: l.n}, nil
|
||||
}
|
||||
|
||||
func (r *LimitReader) Unwrap() any {
|
||||
return r.r
|
||||
}
|
||||
|
@ -80,3 +80,7 @@ func (r *SectionReader) CloneReaderAtSeeker() (ReaderAtSeeker, error) {
|
||||
bitLimit: r.bitLimit,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *SectionReader) Unwrap() any {
|
||||
return r.r
|
||||
}
|
||||
|
@ -29,15 +29,15 @@ const (
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
Name string
|
||||
Description string
|
||||
Force bool
|
||||
FillGaps bool
|
||||
IsRoot bool
|
||||
Range ranges.Range // if zero use whole buffer
|
||||
InArg any
|
||||
FormatInArgFn func(init any) any
|
||||
ReadBuf *[]byte
|
||||
Name string
|
||||
Description string
|
||||
Force bool
|
||||
FillGaps bool
|
||||
IsRoot bool
|
||||
Range ranges.Range // if zero use whole buffer
|
||||
InArg any
|
||||
ParseOptsFn func(init any) any
|
||||
ReadBuf *[]byte
|
||||
}
|
||||
|
||||
// Decode try decode group and return first success and all other decoder errors
|
||||
@ -60,6 +60,15 @@ func decode(ctx context.Context, br bitio.ReaderAtSeeker, group *Group, opts Opt
|
||||
panic("group is nil, failed to register format?")
|
||||
}
|
||||
|
||||
hasGroupOpts := false
|
||||
groupArg := group.DefaultInArg
|
||||
if opts.ParseOptsFn != nil && groupArg != nil {
|
||||
if groupOptArg := opts.ParseOptsFn(groupArg); groupOptArg != nil {
|
||||
hasGroupOpts = true
|
||||
groupArg = groupOptArg
|
||||
}
|
||||
}
|
||||
|
||||
formatsErr := FormatsError{}
|
||||
|
||||
for _, f := range group.Formats {
|
||||
@ -68,9 +77,8 @@ func decode(ctx context.Context, br bitio.ReaderAtSeeker, group *Group, opts Opt
|
||||
// figure out if there are format specific arg passed as options
|
||||
hasFormatOpts := false
|
||||
formatArg := f.DefaultInArg
|
||||
if formatArg != nil && opts.FormatInArgFn != nil {
|
||||
formatOptArg := opts.FormatInArgFn(formatArg)
|
||||
if formatOptArg != nil {
|
||||
if opts.ParseOptsFn != nil && formatArg != nil {
|
||||
if formatOptArg := opts.ParseOptsFn(formatArg); formatOptArg != nil {
|
||||
hasFormatOpts = true
|
||||
formatArg = formatOptArg
|
||||
}
|
||||
@ -87,6 +95,10 @@ func decode(ctx context.Context, br bitio.ReaderAtSeeker, group *Group, opts Opt
|
||||
inArgs = append(inArgs, f.DefaultInArg)
|
||||
}
|
||||
|
||||
if hasGroupOpts {
|
||||
inArgs = append(inArgs, groupArg)
|
||||
}
|
||||
|
||||
cBR, err := bitioex.Range(br, decodeRange.Start, decodeRange.Len)
|
||||
if err != nil {
|
||||
return nil, nil, IOError{Err: err, Op: "BitBufRange", ReadSize: decodeRange.Len, Pos: decodeRange.Start}
|
||||
@ -953,13 +965,13 @@ func (d *D) RangeFn(firstBit int64, nBits int64, fn func(d *D)) int64 {
|
||||
|
||||
func (d *D) Format(group *Group, inArg any) any {
|
||||
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()},
|
||||
InArg: inArg,
|
||||
FormatInArgFn: d.Options.FormatInArgFn,
|
||||
ReadBuf: d.readBuf,
|
||||
Force: d.Options.Force,
|
||||
FillGaps: false,
|
||||
IsRoot: false,
|
||||
Range: ranges.Range{Start: d.Pos(), Len: d.BitsLeft()},
|
||||
InArg: inArg,
|
||||
ParseOptsFn: d.Options.ParseOptsFn,
|
||||
ReadBuf: d.readBuf,
|
||||
})
|
||||
if dv == nil || dv.Errors() != nil {
|
||||
d.IOPanic(err, "Format: decode")
|
||||
@ -983,14 +995,14 @@ func (d *D) Format(group *Group, inArg any) any {
|
||||
|
||||
func (d *D) TryFieldFormat(name string, group *Group, inArg any) (*Value, any, 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()},
|
||||
InArg: inArg,
|
||||
FormatInArgFn: d.Options.FormatInArgFn,
|
||||
ReadBuf: d.readBuf,
|
||||
Name: name,
|
||||
Force: d.Options.Force,
|
||||
FillGaps: false,
|
||||
IsRoot: false,
|
||||
Range: ranges.Range{Start: d.Pos(), Len: d.BitsLeft()},
|
||||
InArg: inArg,
|
||||
ParseOptsFn: d.Options.ParseOptsFn,
|
||||
ReadBuf: d.readBuf,
|
||||
})
|
||||
if dv == nil || dv.Errors() != nil {
|
||||
return nil, nil, err
|
||||
@ -1022,14 +1034,14 @@ func (d *D) FieldFormatOrRaw(name string, group *Group, inArg any) (*Value, any)
|
||||
|
||||
func (d *D) TryFieldFormatLen(name string, nBits int64, group *Group, inArg any) (*Value, any, 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},
|
||||
InArg: inArg,
|
||||
FormatInArgFn: d.Options.FormatInArgFn,
|
||||
ReadBuf: d.readBuf,
|
||||
Name: name,
|
||||
Force: d.Options.Force,
|
||||
FillGaps: true,
|
||||
IsRoot: false,
|
||||
Range: ranges.Range{Start: d.Pos(), Len: nBits},
|
||||
InArg: inArg,
|
||||
ParseOptsFn: d.Options.ParseOptsFn,
|
||||
ReadBuf: d.readBuf,
|
||||
})
|
||||
if dv == nil || dv.Errors() != nil {
|
||||
return nil, nil, err
|
||||
@ -1062,14 +1074,14 @@ func (d *D) FieldFormatOrRawLen(name string, nBits int64, group *Group, inArg an
|
||||
// TODO: return decooder?
|
||||
func (d *D) TryFieldFormatRange(name string, firstBit int64, nBits int64, group *Group, inArg any) (*Value, any, 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},
|
||||
InArg: inArg,
|
||||
FormatInArgFn: d.Options.FormatInArgFn,
|
||||
ReadBuf: d.readBuf,
|
||||
Name: name,
|
||||
Force: d.Options.Force,
|
||||
FillGaps: true,
|
||||
IsRoot: false,
|
||||
Range: ranges.Range{Start: firstBit, Len: nBits},
|
||||
InArg: inArg,
|
||||
ParseOptsFn: d.Options.ParseOptsFn,
|
||||
ReadBuf: d.readBuf,
|
||||
})
|
||||
if dv == nil || dv.Errors() != nil {
|
||||
return nil, nil, err
|
||||
@ -1091,13 +1103,13 @@ func (d *D) FieldFormatRange(name string, firstBit int64, nBits int64, group *Gr
|
||||
|
||||
func (d *D) TryFieldFormatBitBuf(name string, br bitio.ReaderAtSeeker, group *Group, inArg any) (*Value, any, error) {
|
||||
dv, v, err := decode(d.Ctx, br, group, Options{
|
||||
Name: name,
|
||||
Force: d.Options.Force,
|
||||
FillGaps: true,
|
||||
IsRoot: true,
|
||||
InArg: inArg,
|
||||
FormatInArgFn: d.Options.FormatInArgFn,
|
||||
ReadBuf: d.readBuf,
|
||||
Name: name,
|
||||
Force: d.Options.Force,
|
||||
FillGaps: true,
|
||||
IsRoot: true,
|
||||
InArg: inArg,
|
||||
ParseOptsFn: d.Options.ParseOptsFn,
|
||||
ReadBuf: d.readBuf,
|
||||
})
|
||||
if dv == nil || dv.Errors() != nil {
|
||||
return nil, nil, err
|
||||
|
@ -293,11 +293,12 @@ func (Binary) ExtType() string { return "binary" }
|
||||
|
||||
func (Binary) ExtKeys() []string {
|
||||
return []string{
|
||||
"bits",
|
||||
"bytes",
|
||||
"name",
|
||||
"size",
|
||||
"start",
|
||||
"stop",
|
||||
"bits",
|
||||
"bytes",
|
||||
}
|
||||
}
|
||||
|
||||
@ -338,6 +339,24 @@ func (b Binary) JQValueSlice(start int, end int) any {
|
||||
}
|
||||
func (b Binary) JQValueKey(name string) any {
|
||||
switch name {
|
||||
case "bits":
|
||||
if b.unit == 1 {
|
||||
return b
|
||||
}
|
||||
return Binary{br: b.br, r: b.r, unit: 1}
|
||||
case "bytes":
|
||||
if b.unit == 8 {
|
||||
return b
|
||||
}
|
||||
return Binary{br: b.br, r: b.r, unit: 8}
|
||||
|
||||
case "name":
|
||||
f := ioex.Unwrap(b.br)
|
||||
// this exploits the fact that *os.File has Name()
|
||||
if n, ok := f.(interface{ Name() string }); ok {
|
||||
return n.Name()
|
||||
}
|
||||
return nil
|
||||
case "size":
|
||||
return new(big.Int).SetInt64(b.r.Len / int64(b.unit))
|
||||
case "start":
|
||||
@ -349,16 +368,6 @@ func (b Binary) JQValueKey(name string) any {
|
||||
stopUnits++
|
||||
}
|
||||
return new(big.Int).SetInt64(stopUnits)
|
||||
case "bits":
|
||||
if b.unit == 1 {
|
||||
return b
|
||||
}
|
||||
return Binary{br: b.br, r: b.r, unit: 1}
|
||||
case "bytes":
|
||||
if b.unit == 8 {
|
||||
return b
|
||||
}
|
||||
return Binary{br: b.br, r: b.r, unit: 8}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -244,7 +244,7 @@ func (i *Interp) _decode(c any, format string, opts decodeOpts) any {
|
||||
Force: opts.Force,
|
||||
Range: bv.r,
|
||||
Description: filename,
|
||||
FormatInArgFn: func(init any) any {
|
||||
ParseOptsFn: func(init any) any {
|
||||
v, err := copystructure.Copy(init)
|
||||
if err != nil {
|
||||
return nil
|
||||
|
@ -35,20 +35,40 @@ def _decode_progress:
|
||||
|
||||
def decode($name; $decode_opts):
|
||||
( options as $opts
|
||||
| _decode(
|
||||
$name;
|
||||
( {
|
||||
progress: (
|
||||
if $opts.decode_progress and $opts.repl and stdout_tty.is_terminal then
|
||||
| ( { progress:
|
||||
( if $opts.decode_progress and $opts.repl and stdout_tty.is_terminal then
|
||||
"_decode_progress"
|
||||
else null
|
||||
end
|
||||
),
|
||||
}
|
||||
)
|
||||
}
|
||||
+ $opts
|
||||
+ $decode_opts
|
||||
) as $common_opts
|
||||
| if _registry.groups | has($name) then
|
||||
_decode(
|
||||
$name;
|
||||
( $common_opts
|
||||
# is_probe is to include Probe_In argument
|
||||
+ if $name == "probe" then
|
||||
{ is_probe: true
|
||||
, filename: (tobytes?.name // null)
|
||||
}
|
||||
else {}
|
||||
end
|
||||
)
|
||||
)
|
||||
)
|
||||
else
|
||||
# is_probe_args is to include Probe_Args_In argument
|
||||
_decode(
|
||||
"probe_args";
|
||||
( $common_opts
|
||||
+ { is_probe_args: true
|
||||
, decode_group: $name
|
||||
}
|
||||
)
|
||||
)
|
||||
end
|
||||
);
|
||||
def decode($name): decode($name; {});
|
||||
def decode: decode(options.decode_group; {});
|
||||
|
Loading…
Reference in New Issue
Block a user