From bbaae540cee3ea04d3a9e4a521397c5a7ec0d4ac Mon Sep 17 00:00:00 2001 From: Thomas Pelletier Date: Tue, 30 Nov 2021 13:01:15 -0500 Subject: [PATCH] Decoder: check timezones start with +,-,z,Z (#688) Also simplifies local time seconds scanning. Fixes #686 --- decode.go | 30 +++++++++++++++++------------- parser.go | 1 - unmarshaler_test.go | 4 ++++ 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/decode.go b/decode.go index 0223ebe..4b0c509 100644 --- a/decode.go +++ b/decode.go @@ -99,9 +99,14 @@ func parseDateTime(b []byte) (time.Time, error) { if len(b) != dateTimeByteLen { return time.Time{}, newDecodeError(b, "invalid date-time timezone") } - direction := 1 - if b[0] == '-' { + var direction int + switch b[0] { + case '-': direction = -1 + case '+': + direction = +1 + default: + return time.Time{}, newDecodeError(b[:1], "invalid timezone offset character") } hours := digitsToInt(b[1:3]) @@ -202,26 +207,26 @@ func parseLocalTime(b []byte) (LocalTime, []byte, error) { } if t.Second > 59 { - return t, nil, newDecodeError(b[3:5], "seconds cannot be greater 59") + return t, nil, newDecodeError(b[6:8], "seconds cannot be greater 59") } - const minLengthWithFrac = 9 - if len(b) >= minLengthWithFrac && b[minLengthWithFrac-1] == '.' { + b = b[8:] + + if len(b) >= 1 && b[0] == '.' { frac := 0 digits := 0 - for i, c := range b[minLengthWithFrac:] { + for i, c := range b[1:] { if !isDigit(c) { if i == 0 { - return t, nil, newDecodeError(b[i:i+1], "need at least one digit after fraction point") + return t, nil, newDecodeError(b[0:1], "need at least one digit after fraction point") } - break } const maxFracPrecision = 9 if i >= maxFracPrecision { - return t, nil, newDecodeError(b[i:i+1], "maximum precision for date time is nanosecond") + return t, nil, newDecodeError(b[i-1:i], "maximum precision for date time is nanosecond") } frac *= 10 @@ -230,16 +235,15 @@ func parseLocalTime(b []byte) (LocalTime, []byte, error) { } if digits == 0 { - return t, nil, newDecodeError(b[minLengthWithFrac-1:minLengthWithFrac], "nanoseconds need at least one digit") + return t, nil, newDecodeError(b[:1], "nanoseconds need at least one digit") } t.Nanosecond = frac * nspow[digits] t.Precision = digits - return t, b[9+digits:], nil + return t, b[1+digits:], nil } - - return t, b[8:], nil + return t, b, nil } //nolint:cyclop diff --git a/parser.go b/parser.go index b304182..86b5fd2 100644 --- a/parser.go +++ b/parser.go @@ -862,7 +862,6 @@ func (p *parser) parseIntOrFloatOrDateTime(b []byte) (ast.Reference, []byte, err return p.scanIntOrFloat(b) } - //nolint:gomnd if len(b) < 3 { return p.scanIntOrFloat(b) } diff --git a/unmarshaler_test.go b/unmarshaler_test.go index 6f0b910..534cfc9 100644 --- a/unmarshaler_test.go +++ b/unmarshaler_test.go @@ -2628,6 +2628,10 @@ world'`, desc: `zero is an invalid month`, data: `a=2021-00-11`, }, + { + desc: `invalid number of seconds digits with trailling digit`, + data: `a=0000-01-01 00:00:000000Z3`, + }, { desc: `carriage return inside basic key`, data: "\"\r\"=42",