From 58ba84ff93fc82d9f77c583ddeee56a5e44899c4 Mon Sep 17 00:00:00 2001 From: Mattias Wadman Date: Mon, 1 Nov 2021 17:35:37 +0100 Subject: [PATCH] decode,interp: Add RecoverableErrorer interface instead of enumerate --- pkg/decode/decode.go | 103 ++++++------------------------ pkg/decode/errors.go | 90 ++++++++++++++++++++++++++ pkg/interp/testdata/decode.fqtest | 13 ++++ 3 files changed, 121 insertions(+), 85 deletions(-) create mode 100644 pkg/decode/errors.go diff --git a/pkg/decode/decode.go b/pkg/decode/decode.go index b76c67ae..98a72f6d 100644 --- a/pkg/decode/decode.go +++ b/pkg/decode/decode.go @@ -11,83 +11,11 @@ import ( "io/ioutil" "strings" - "github.com/wader/fq/internal/num" "github.com/wader/fq/internal/recoverfn" "github.com/wader/fq/pkg/bitio" "github.com/wader/fq/pkg/ranges" ) -type FormatsError struct { - Errs []FormatError -} - -func (de FormatsError) Error() string { - var errs []string - for _, err := range de.Errs { - errs = append(errs, err.Error()) - } - return strings.Join(errs, ", ") -} - -type FormatError struct { - Err error - Format *Format - Stacktrace recoverfn.Raw -} - -func (fe FormatError) Error() string { - // var fns []string - // for _, f := range fe.Stacktrace.Frames() { - // fns = append(fns, fmt.Sprintf("%s:%d:%s", f.File, f.Line, f.Function)) - // } - - return fe.Err.Error() -} - -func (fe FormatError) Value() interface{} { - var st []interface{} - for _, f := range fe.Stacktrace.Frames() { - st = append(st, f.Function) - } - - return map[string]interface{}{ - "format": fe.Format.Name, - "error": fe.Err.Error(), - "stacktrace": st, - } -} - -type IOError struct { - Err error - Name string - Op string - ReadSize int64 - SeekPos int64 - Pos int64 -} - -func (e IOError) Error() string { - var prefix string - if e.Name != "" { - prefix = e.Op + "(" + e.Name + ")" - } else { - prefix = e.Op - } - - return fmt.Sprintf("%s: failed at position %s (read size %s seek pos %s): %s", - prefix, num.Bits(e.Pos).StringByteBits(10), num.Bits(e.ReadSize).StringByteBits(10), num.Bits(e.SeekPos).StringByteBits(10), e.Err) -} -func (e IOError) Unwrap() error { return e.Err } - -type ValidateError struct { - Reason string - Pos int64 -} - -func (e ValidateError) Error() string { - return fmt.Sprintf("failed to validate at position %s: %s", num.Bits(e.Pos).StringByteBits(16), e.Reason) -} - type Endian int const ( @@ -144,9 +72,8 @@ func decode(ctx context.Context, bb *bitio.Buffer, formats []*Format, opts Optio } if !rOk { - switch panicV := r.RecoverV.(type) { - case IOError, ValidateError, FormatsError: - panicErr, _ := panicV.(error) + if re, ok := r.RecoverV.(RecoverableErrorer); ok && re.IsRecoverableError() { + panicErr, _ := re.(error) formatErr := FormatError{ Err: panicErr, Format: f, @@ -159,7 +86,7 @@ func decode(ctx context.Context, bb *bitio.Buffer, formats []*Format, opts Optio if !forceOne { continue } - default: + } else { r.RePanic() } } @@ -720,18 +647,24 @@ func (d *D) FieldValidateUFn(name string, v uint64, fn func() uint64) { } } -func (d *D) FieldValidateUTF8Fn(name string, v string, fn func() string) { +func (d *D) ValidateUTF8Any(name string, nBytes int, vs []string) { pos := d.Pos() + found := false s := d.FieldStrFn(name, func() (string, string) { - str := fn() - s := "Correct" - if str != v { - s = "Incorrect" + str, err := d.TryUTF8(nBytes) + if err != nil { + panic(IOError{Err: err, Name: name, Op: "FieldValidateUTF8", ReadSize: int64(nBytes) * 8, Pos: d.Pos()}) } - return str, s + for _, v := range vs { + if v == str { + found = true + return str, "Correct" + } + } + return str, "Incorrect" }) - if s != v { - panic(ValidateError{Pos: pos}) + if !found { + panic(ValidateError{Reason: fmt.Sprintf("expected any of %q found %q", vs, s), Pos: pos}) } } @@ -752,7 +685,7 @@ func (d *D) FieldValidateUTF8Any(name string, nBytes int, vs []string) { return str, "Incorrect" }) if !found { - panic(ValidateError{Reason: fmt.Sprintf("expected any of %v found %s", vs, s), Pos: pos}) + panic(ValidateError{Reason: fmt.Sprintf("expected any of %q found %q", vs, s), Pos: pos}) } } diff --git a/pkg/decode/errors.go b/pkg/decode/errors.go new file mode 100644 index 00000000..68959f66 --- /dev/null +++ b/pkg/decode/errors.go @@ -0,0 +1,90 @@ +package decode + +import ( + "fmt" + "strings" + + "github.com/wader/fq/internal/num" + "github.com/wader/fq/internal/recoverfn" +) + +type RecoverableErrorer interface { + IsRecoverableError() bool +} + +type FormatError struct { + Err error + Format *Format + Stacktrace recoverfn.Raw +} + +type FormatsError struct { + Errs []FormatError +} + +func (fe FormatsError) Error() string { + var errs []string + for _, err := range fe.Errs { + errs = append(errs, err.Error()) + } + return strings.Join(errs, ", ") +} + +func (fe FormatError) Error() string { + // var fns []string + // for _, f := range fe.Stacktrace.Frames() { + // fns = append(fns, fmt.Sprintf("%s:%d:%s", f.File, f.Line, f.Function)) + // } + + return fe.Err.Error() +} + +func (fe FormatError) Value() interface{} { + var st []interface{} + for _, f := range fe.Stacktrace.Frames() { + st = append(st, f.Function) + } + + return map[string]interface{}{ + "format": fe.Format.Name, + "error": fe.Err.Error(), + "stacktrace": st, + } +} + +func (FormatsError) IsRecoverableError() bool { return true } + +type IOError struct { + Err error + Name string + Op string + ReadSize int64 + SeekPos int64 + Pos int64 +} + +func (e IOError) Error() string { + var prefix string + if e.Name != "" { + prefix = e.Op + "(" + e.Name + ")" + } else { + prefix = e.Op + } + + return fmt.Sprintf("%s: failed at position %s (read size %s seek pos %s): %s", + prefix, num.Bits(e.Pos).StringByteBits(10), num.Bits(e.ReadSize).StringByteBits(10), num.Bits(e.SeekPos).StringByteBits(10), e.Err) +} +func (e IOError) Unwrap() error { return e.Err } + +func (IOError) IsRecoverableError() bool { return true } + +type ValidateError struct { + Reason string + Pos int64 +} + +func (e ValidateError) Error() string { + return fmt.Sprintf("failed to validate at position %s: %s", num.Bits(e.Pos).StringByteBits(16), e.Reason) +} + +func (ValidateError) IsRecoverableError() bool { return true } diff --git a/pkg/interp/testdata/decode.fqtest b/pkg/interp/testdata/decode.fqtest index 4e9a6d87..03b4fcf6 100644 --- a/pkg/interp/testdata/decode.fqtest +++ b/pkg/interp/testdata/decode.fqtest @@ -40,3 +40,16 @@ mp3> probe({}) * |until 0x283.7 (end) (599) | | | | | footers: [0] mp3> ^D +$ fq -d raw 'png | d' /test.mp3 + |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f|0123456789abcdef|.: {} (png) + | | | error: png: failed to validate at position 0x0: expected any of ["\x89PNG\r\n\x1a\n"] found "ID3\x04\x00\x00\x00\x00" +0x000|49 44 33 04 00 00 00 00 |ID3..... | signature: "ID3\x04\x00\x00\x00\x00" (Incorrect) +0x000| 00 23 54 53 53 45 00 00| .#TSSE..| unknown0: 0023545353450000000f0000034c6176... +0x010|00 0f 00 00 03 4c 61 76 66 35 38 2e 34 35 2e 31|.....Lavf58.45.1| +* |until 0x283.7 (end) (636) | | +$ fq -d raw 'tobytes[0:1] | png | d' /test.mp3 + |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f|0123456789abcdef|.: {} (png) + | | | error: png: FieldValidateUTF8(signature): failed at position 1 (read size 8 seek pos 0): unexpected EOF +0x0|49 |I | unknown0: 49 +$ fq -d raw 'tobytes[0:1] | try probe catch . | type' /test.mp3 +"array"