diff --git a/decode.go b/decode.go index 25e69c43..6dce72c1 100644 --- a/decode.go +++ b/decode.go @@ -35,13 +35,22 @@ func parseLocalDate(b []byte) (LocalDate, error) { return date, newDecodeError(b, "dates are expected to have the format YYYY-MM-DD") } - date.Year = parseDecimalDigits(b[0:4]) + var err error - v := parseDecimalDigits(b[5:7]) + date.Year, err = parseDecimalDigits(b[0:4]) + if err != nil { + return LocalDate{}, err + } - date.Month = v + date.Month, err = parseDecimalDigits(b[5:7]) + if err != nil { + return LocalDate{}, err + } - date.Day = parseDecimalDigits(b[8:10]) + date.Day, err = parseDecimalDigits(b[8:10]) + if err != nil { + return LocalDate{}, err + } if !isValidDate(date.Year, date.Month, date.Day) { return LocalDate{}, newDecodeError(b, "impossible date") @@ -50,15 +59,18 @@ func parseLocalDate(b []byte) (LocalDate, error) { return date, nil } -func parseDecimalDigits(b []byte) int { +func parseDecimalDigits(b []byte) (int, error) { v := 0 - for _, c := range b { + for i, c := range b { + if c < '0' || c > '9' { + return 0, newDecodeError(b[i:i+1], "expected digit (0-9)") + } v *= 10 v += int(c - '0') } - return v + return v, nil } func parseDateTime(b []byte) (time.Time, error) { @@ -159,7 +171,13 @@ func parseLocalTime(b []byte) (LocalTime, []byte, error) { return t, nil, newDecodeError(b, "times are expected to have the format HH:MM:SS[.NNNNNN]") } - t.Hour = parseDecimalDigits(b[0:2]) + var err error + + t.Hour, err = parseDecimalDigits(b[0:2]) + if err != nil { + return t, nil, err + } + if t.Hour > 23 { return t, nil, newDecodeError(b[0:2], "hour cannot be greater 23") } @@ -167,7 +185,10 @@ func parseLocalTime(b []byte) (LocalTime, []byte, error) { return t, nil, newDecodeError(b[2:3], "expecting colon between hours and minutes") } - t.Minute = parseDecimalDigits(b[3:5]) + t.Minute, err = parseDecimalDigits(b[3:5]) + if err != nil { + return t, nil, err + } if t.Minute > 59 { return t, nil, newDecodeError(b[3:5], "minutes cannot be greater 59") } @@ -175,7 +196,11 @@ func parseLocalTime(b []byte) (LocalTime, []byte, error) { return t, nil, newDecodeError(b[5:6], "expecting colon between minutes and seconds") } - t.Second = parseDecimalDigits(b[6:8]) + t.Second, err = parseDecimalDigits(b[6:8]) + if err != nil { + return t, nil, err + } + if t.Second > 59 { return t, nil, newDecodeError(b[3:5], "seconds cannot be greater 59") } @@ -204,6 +229,10 @@ func parseLocalTime(b []byte) (LocalTime, []byte, error) { digits++ } + if digits == 0 { + return t, nil, newDecodeError(b[minLengthWithFrac-1:minLengthWithFrac], "nanoseconds need at least one digit") + } + t.Nanosecond = frac * nspow[digits] t.Precision = digits diff --git a/unmarshaler_test.go b/unmarshaler_test.go index 6259b3a6..24185ccc 100644 --- a/unmarshaler_test.go +++ b/unmarshaler_test.go @@ -2002,7 +2002,7 @@ world'`, { desc: "invalid minutes value", data: `a=1979-05-27T23:+2:99`, - msg: `minutes cannot be greater 59`, + msg: `expected digit (0-9)`, }, { desc: "invalid seconds value", @@ -2183,6 +2183,34 @@ world'`, data: `A = 2021-02-29T23:59:00`, msg: `impossible date`, }, + { + desc: `missing minute digit`, + data: `a=17:4::01`, + }, + { + desc: `invalid space in year`, + data: `i=19 7-12-21T10:32:00`, + }, + { + desc: `missing nanoseconds digits`, + data: `a=17:45:56.`, + }, + { + desc: `minutes over 60`, + data: `a=17:99:00`, + }, + { + desc: `invalid second`, + data: `a=17:00::0`, + }, + { + desc: `invalid hour`, + data: `a=1::00:00`, + }, + { + desc: `invalid month`, + data: `a=2021-0--29`, + }, } for _, e := range examples {