Skip to content

Commit 45d1769

Browse files
committed
Fix messages of errors when parsing invalid java.time.Duration values
1 parent 8192daf commit 45d1769

File tree

4 files changed

+132
-147
lines changed

4 files changed

+132
-147
lines changed

jsoniter-scala-core/js/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala

+23-26
Original file line numberDiff line numberDiff line change
@@ -2922,28 +2922,27 @@ final class JsonReader private[jsoniter_scala](
29222922
if (x < -153722867280912930L || x > 153722867280912930L) durationError(pos) // -153722867280912930L == Long.MinValue / 60
29232923
seconds = sumSeconds(x * 60, seconds, pos)
29242924
state = 2
2925-
} else if (b == '.') {
2926-
pos += 1
2925+
} else if (b == 'S' || b == '.') {
29272926
seconds = sumSeconds(x, seconds, pos)
2928-
var nanoDigitWeight = 100000000
2929-
while ({
2930-
if (pos >= tail) {
2931-
pos = loadMoreOrError(pos)
2932-
buf = this.buf
2933-
}
2934-
b = buf(pos)
2935-
(b >= '0' && b <= '9') && nanoDigitWeight != 0
2936-
}) {
2937-
nano += (b - '0') * nanoDigitWeight
2938-
nanoDigitWeight /= 10
2927+
state = 3
2928+
if (b == '.') {
29392929
pos += 1
2930+
var nanoDigitWeight = 100000000
2931+
while ({
2932+
if (pos >= tail) {
2933+
pos = loadMoreOrError(pos)
2934+
buf = this.buf
2935+
}
2936+
b = buf(pos)
2937+
(b >= '0' && b <= '9') && nanoDigitWeight != 0
2938+
}) {
2939+
nano += (b - '0') * nanoDigitWeight
2940+
nanoDigitWeight /= 10
2941+
pos += 1
2942+
}
2943+
if (b != 'S') nanoError(nanoDigitWeight, 'S', pos)
2944+
nano = (nano ^ sx) - sx
29402945
}
2941-
if (b != 'S') nanoError(nanoDigitWeight, 'S', pos)
2942-
nano = (nano ^ sx) - sx
2943-
state = 3
2944-
} else if (b == 'S') {
2945-
seconds = sumSeconds(x, seconds, pos)
2946-
state = 3
29472946
} else durationError(state, pos)
29482947
b = nextByte(pos + 1)
29492948
b != '"'
@@ -3170,10 +3169,8 @@ final class JsonReader private[jsoniter_scala](
31703169
}) periodError(pos)
31713170
pos += 1
31723171
}
3173-
if (sx == 0) {
3174-
if (x == -2147483648) periodError(pos)
3175-
x = -x
3176-
}
3172+
x = sx - (x ^ sx)
3173+
if ((sx | x) == -2147483648) periodError(pos)
31773174
if (b == 'Y' && state <= 0) {
31783175
years = x
31793176
state = 1
@@ -3390,9 +3387,9 @@ final class JsonReader private[jsoniter_scala](
33903387

33913388
private[this] def durationError(state: Int, pos: Int): Nothing = decodeError(state match {
33923389
case -1 => "expected 'D' or digit"
3393-
case 0 => "expected 'H' or 'M' or 'S or '.' or digit"
3394-
case 1 => "expected 'M' or 'S or '.' or digit"
3395-
case _ => "expected 'S or '.' or digit"
3390+
case 0 => "expected 'H' or 'M' or 'S' or '.' or digit"
3391+
case 1 => "expected 'M' or 'S' or '.' or digit"
3392+
case _ => "expected 'S' or '.' or digit"
33963393
}, pos)
33973394

33983395
private[this] def yearError(t: Byte, maxDigits: Int, pos: Int, isNeg: Boolean, yearDigits: Int): Nothing = {

jsoniter-scala-core/jvm/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala

+53-59
Original file line numberDiff line numberDiff line change
@@ -2921,67 +2921,63 @@ final class JsonReader private[jsoniter_scala](
29212921
}) durationError(pos)
29222922
pos += 1
29232923
}
2924-
if (sx == 0) {
2925-
if (x == -9223372036854775808L) durationError(pos)
2926-
x = -x
2927-
}
29282924
if (b == 'D' && state < 0) {
2929-
if (x < -106751991167300L || x > 106751991167300L) durationError(pos) // -106751991167300L == Long.MinValue / 86400
2930-
seconds = x * 86400
2925+
if (x < -106751991167300L) durationError(pos) // -106751991167300L == Long.MinValue / 86400
2926+
seconds = (sx - (x ^ sx)) * 86400
29312927
state = 0
29322928
} else if (b == 'H' && state <= 0) {
2933-
if (x < -2562047788015215L || x > 2562047788015215L) durationError(pos) // -2562047788015215L == Long.MinValue / 3600
2934-
seconds = sumSeconds(x * 3600, seconds, pos)
2929+
if (x < -2562047788015215L) durationError(pos) // -2562047788015215L == Long.MinValue / 3600
2930+
seconds = sumSeconds((sx - (x ^ sx)) * 3600, seconds, pos)
29352931
state = 1
29362932
} else if (b == 'M' && state <= 1) {
2937-
if (x < -153722867280912930L || x > 153722867280912930L) durationError(pos) // -153722867280912930L == Long.MinValue / 60
2938-
seconds = sumSeconds(x * 60, seconds, pos)
2933+
if (x < -153722867280912930L) durationError(pos) // -153722867280912930L == Long.MinValue / 60
2934+
seconds = sumSeconds((sx - (x ^ sx)) * 60, seconds, pos)
29392935
state = 2
2940-
} else if (b == '.') {
2941-
pos += 1
2942-
seconds = sumSeconds(x, seconds, pos)
2943-
var nanoDigitWeight = 100000000
2944-
var bs = 0
2945-
if (pos + 9 < tail && {
2946-
bs = ByteArrayAccess.getInt(buf, pos) - 0x303030
2947-
((bs + 0x767676 | bs) & 0x808080) == 0
2948-
} && {
2949-
nano = ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000000
2950-
pos += 3
2951-
bs = ByteArrayAccess.getInt(buf, pos) - 0x303030
2952-
nanoDigitWeight = 100000
2953-
((bs + 0x767676 | bs) & 0x808080) == 0
2954-
} && {
2955-
nano += ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000
2956-
pos += 3
2957-
bs = ByteArrayAccess.getInt(buf, pos) - 0x303030
2958-
nanoDigitWeight = 100
2959-
((bs + 0x767676 | bs) & 0x808080) == 0
2960-
}) {
2961-
nano += (bs * 2561 & 0xFF00FF) * 6553601 >> 16
2962-
pos += 3
2963-
b = (bs >> 24).toByte
2964-
nanoDigitWeight = 0
2965-
} else {
2966-
while ({
2967-
if (pos >= tail) {
2968-
pos = loadMoreOrError(pos)
2969-
buf = this.buf
2970-
}
2971-
b = buf(pos)
2972-
(b >= '0' && b <= '9') && nanoDigitWeight != 0
2936+
} else if (b == 'S' || b == '.') {
2937+
if ((sx | x) == -9223372036854775808L) durationError(pos)
2938+
seconds = sumSeconds(sx - (x ^ sx), seconds, pos)
2939+
state = 3
2940+
if (b == '.') {
2941+
pos += 1
2942+
var nanoDigitWeight = 100000000
2943+
var bs = 0
2944+
if (pos + 9 < tail && {
2945+
bs = ByteArrayAccess.getInt(buf, pos) - 0x303030
2946+
((bs + 0x767676 | bs) & 0x808080) == 0
2947+
} && {
2948+
nano = ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000000
2949+
pos += 3
2950+
bs = ByteArrayAccess.getInt(buf, pos) - 0x303030
2951+
nanoDigitWeight = 100000
2952+
((bs + 0x767676 | bs) & 0x808080) == 0
2953+
} && {
2954+
nano += ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000
2955+
pos += 3
2956+
bs = ByteArrayAccess.getInt(buf, pos) - 0x303030
2957+
nanoDigitWeight = 100
2958+
((bs + 0x767676 | bs) & 0x808080) == 0
29732959
}) {
2974-
nano += (b - '0') * nanoDigitWeight
2975-
nanoDigitWeight = (nanoDigitWeight * 429496730L >> 32).toInt // divide a small positive int by 10
2976-
pos += 1
2960+
nano += (bs * 2561 & 0xFF00FF) * 6553601 >> 16
2961+
pos += 3
2962+
b = (bs >> 24).toByte
2963+
nanoDigitWeight = 0
2964+
} else {
2965+
while ({
2966+
if (pos >= tail) {
2967+
pos = loadMoreOrError(pos)
2968+
buf = this.buf
2969+
}
2970+
b = buf(pos)
2971+
(b >= '0' && b <= '9') && nanoDigitWeight != 0
2972+
}) {
2973+
nano += (b - '0') * nanoDigitWeight
2974+
nanoDigitWeight = (nanoDigitWeight * 429496730L >> 32).toInt // divide a small positive int by 10
2975+
pos += 1
2976+
}
29772977
}
2978+
if (b != 'S') nanoError(nanoDigitWeight, 'S', pos)
2979+
nano = (nano ^ sx) - sx
29782980
}
2979-
if (b != 'S') nanoError(nanoDigitWeight, 'S', pos)
2980-
nano = (nano ^ sx) - sx
2981-
state = 3
2982-
} else if (b == 'S') {
2983-
seconds = sumSeconds(x, seconds, pos)
2984-
state = 3
29852981
} else durationError(state, pos)
29862982
b = nextByte(pos + 1)
29872983
b != '"'
@@ -3516,10 +3512,8 @@ final class JsonReader private[jsoniter_scala](
35163512
}) periodError(pos)
35173513
pos += 1
35183514
}
3519-
if (sx == 0) {
3520-
if (x == -2147483648) periodError(pos)
3521-
x = -x
3522-
}
3515+
x = sx - (x ^ sx)
3516+
if ((sx | x) == -2147483648) periodError(pos)
35233517
if (b == 'Y' && state <= 0) {
35243518
years = x
35253519
state = 1
@@ -3824,9 +3818,9 @@ final class JsonReader private[jsoniter_scala](
38243818

38253819
private[this] def durationError(state: Int, pos: Int): Nothing = decodeError(state match {
38263820
case -1 => "expected 'D' or digit"
3827-
case 0 => "expected 'H' or 'M' or 'S or '.' or digit"
3828-
case 1 => "expected 'M' or 'S or '.' or digit"
3829-
case _ => "expected 'S or '.' or digit"
3821+
case 0 => "expected 'H' or 'M' or 'S' or '.' or digit"
3822+
case 1 => "expected 'M' or 'S' or '.' or digit"
3823+
case _ => "expected 'S' or '.' or digit"
38303824
}, pos)
38313825

38323826
private[this] def yearError(t: Byte, maxDigits: Int, pos: Int, isNeg: Boolean, yearDigits: Int): Nothing = {

jsoniter-scala-core/native/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala

+53-59
Original file line numberDiff line numberDiff line change
@@ -2917,67 +2917,63 @@ final class JsonReader private[jsoniter_scala](
29172917
}) durationError(pos)
29182918
pos += 1
29192919
}
2920-
if (sx == 0) {
2921-
if (x == -9223372036854775808L) durationError(pos)
2922-
x = -x
2923-
}
29242920
if (b == 'D' && state < 0) {
2925-
if (x < -106751991167300L || x > 106751991167300L) durationError(pos) // -106751991167300L == Long.MinValue / 86400
2926-
seconds = x * 86400
2921+
if (x < -106751991167300L) durationError(pos) // -106751991167300L == Long.MinValue / 86400
2922+
seconds = (sx - (x ^ sx)) * 86400
29272923
state = 0
29282924
} else if (b == 'H' && state <= 0) {
2929-
if (x < -2562047788015215L || x > 2562047788015215L) durationError(pos) // -2562047788015215L == Long.MinValue / 3600
2930-
seconds = sumSeconds(x * 3600, seconds, pos)
2925+
if (x < -2562047788015215L) durationError(pos) // -2562047788015215L == Long.MinValue / 3600
2926+
seconds = sumSeconds((sx - (x ^ sx)) * 3600, seconds, pos)
29312927
state = 1
29322928
} else if (b == 'M' && state <= 1) {
2933-
if (x < -153722867280912930L || x > 153722867280912930L) durationError(pos) // -153722867280912930L == Long.MinValue / 60
2934-
seconds = sumSeconds(x * 60, seconds, pos)
2929+
if (x < -153722867280912930L) durationError(pos) // -153722867280912930L == Long.MinValue / 60
2930+
seconds = sumSeconds((sx - (x ^ sx)) * 60, seconds, pos)
29352931
state = 2
2936-
} else if (b == '.') {
2937-
pos += 1
2938-
seconds = sumSeconds(x, seconds, pos)
2939-
var nanoDigitWeight = 100000000
2940-
var bs = 0
2941-
if (pos + 9 < tail && {
2942-
bs = ByteArrayAccess.getInt(buf, pos) - 0x303030
2943-
((bs + 0x767676 | bs) & 0x808080) == 0
2944-
} && {
2945-
nano = ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000000
2946-
pos += 3
2947-
bs = ByteArrayAccess.getInt(buf, pos) - 0x303030
2948-
nanoDigitWeight = 100000
2949-
((bs + 0x767676 | bs) & 0x808080) == 0
2950-
} && {
2951-
nano += ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000
2952-
pos += 3
2953-
bs = ByteArrayAccess.getInt(buf, pos) - 0x303030
2954-
nanoDigitWeight = 100
2955-
((bs + 0x767676 | bs) & 0x808080) == 0
2956-
}) {
2957-
nano += (bs * 2561 & 0xFF00FF) * 6553601 >> 16
2958-
pos += 3
2959-
b = (bs >> 24).toByte
2960-
nanoDigitWeight = 0
2961-
} else {
2962-
while ({
2963-
if (pos >= tail) {
2964-
pos = loadMoreOrError(pos)
2965-
buf = this.buf
2966-
}
2967-
b = buf(pos)
2968-
(b >= '0' && b <= '9') && nanoDigitWeight != 0
2932+
} else if (b == 'S' || b == '.') {
2933+
if ((sx | x) == -9223372036854775808L) durationError(pos)
2934+
seconds = sumSeconds(sx - (x ^ sx), seconds, pos)
2935+
state = 3
2936+
if (b == '.') {
2937+
pos += 1
2938+
var nanoDigitWeight = 100000000
2939+
var bs = 0
2940+
if (pos + 9 < tail && {
2941+
bs = ByteArrayAccess.getInt(buf, pos) - 0x303030
2942+
((bs + 0x767676 | bs) & 0x808080) == 0
2943+
} && {
2944+
nano = ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000000
2945+
pos += 3
2946+
bs = ByteArrayAccess.getInt(buf, pos) - 0x303030
2947+
nanoDigitWeight = 100000
2948+
((bs + 0x767676 | bs) & 0x808080) == 0
2949+
} && {
2950+
nano += ((bs * 2561 & 0xFF00FF) * 6553601 >> 16) * 1000
2951+
pos += 3
2952+
bs = ByteArrayAccess.getInt(buf, pos) - 0x303030
2953+
nanoDigitWeight = 100
2954+
((bs + 0x767676 | bs) & 0x808080) == 0
29692955
}) {
2970-
nano += (b - '0') * nanoDigitWeight
2971-
nanoDigitWeight = (nanoDigitWeight * 429496730L >> 32).toInt // divide a small positive int by 10
2972-
pos += 1
2956+
nano += (bs * 2561 & 0xFF00FF) * 6553601 >> 16
2957+
pos += 3
2958+
b = (bs >> 24).toByte
2959+
nanoDigitWeight = 0
2960+
} else {
2961+
while ({
2962+
if (pos >= tail) {
2963+
pos = loadMoreOrError(pos)
2964+
buf = this.buf
2965+
}
2966+
b = buf(pos)
2967+
(b >= '0' && b <= '9') && nanoDigitWeight != 0
2968+
}) {
2969+
nano += (b - '0') * nanoDigitWeight
2970+
nanoDigitWeight = (nanoDigitWeight * 429496730L >> 32).toInt // divide a small positive int by 10
2971+
pos += 1
2972+
}
29732973
}
2974+
if (b != 'S') nanoError(nanoDigitWeight, 'S', pos)
2975+
nano = (nano ^ sx) - sx
29742976
}
2975-
if (b != 'S') nanoError(nanoDigitWeight, 'S', pos)
2976-
nano = (nano ^ sx) - sx
2977-
state = 3
2978-
} else if (b == 'S') {
2979-
seconds = sumSeconds(x, seconds, pos)
2980-
state = 3
29812977
} else durationError(state, pos)
29822978
b = nextByte(pos + 1)
29832979
b != '"'
@@ -3512,10 +3508,8 @@ final class JsonReader private[jsoniter_scala](
35123508
}) periodError(pos)
35133509
pos += 1
35143510
}
3515-
if (sx == 0) {
3516-
if (x == -2147483648) periodError(pos)
3517-
x = -x
3518-
}
3511+
x = sx - (x ^ sx)
3512+
if ((sx | x) == -2147483648) periodError(pos)
35193513
if (b == 'Y' && state <= 0) {
35203514
years = x
35213515
state = 1
@@ -3820,9 +3814,9 @@ final class JsonReader private[jsoniter_scala](
38203814

38213815
private[this] def durationError(state: Int, pos: Int): Nothing = decodeError(state match {
38223816
case -1 => "expected 'D' or digit"
3823-
case 0 => "expected 'H' or 'M' or 'S or '.' or digit"
3824-
case 1 => "expected 'M' or 'S or '.' or digit"
3825-
case _ => "expected 'S or '.' or digit"
3817+
case 0 => "expected 'H' or 'M' or 'S' or '.' or digit"
3818+
case 1 => "expected 'M' or 'S' or '.' or digit"
3819+
case _ => "expected 'S' or '.' or digit"
38263820
}, pos)
38273821

38283822
private[this] def yearError(t: Byte, maxDigits: Int, pos: Int, isNeg: Boolean, yearDigits: Int): Nothing = {

jsoniter-scala-core/shared/src/test/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReaderSpec.scala

+3-3
Original file line numberDiff line numberDiff line change
@@ -845,7 +845,7 @@ class JsonReaderSpec extends AnyWordSpec with Matchers with ScalaCheckPropertyCh
845845
checkError(""""P1DX1H"""", """expected 'T' or '"', offset: 0x00000004""")
846846
checkError(""""P1DTXH"""", "expected '-' or digit, offset: 0x00000005")
847847
checkError(""""P1DT-XH"""", "expected digit, offset: 0x00000006")
848-
checkError(""""P1DT1XH"""", "expected 'H' or 'M' or 'S or '.' or digit, offset: 0x00000006")
848+
checkError(""""P1DT1XH"""", "expected 'H' or 'M' or 'S' or '.' or digit, offset: 0x00000006")
849849
checkError(""""P0DT2562047788015216H"""", "illegal duration, offset: 0x00000015")
850850
checkError(""""P0DT-2562047788015216H"""", "illegal duration, offset: 0x00000016")
851851
checkError(""""P0DT153722867280912931M"""", "illegal duration, offset: 0x00000017")
@@ -855,15 +855,15 @@ class JsonReaderSpec extends AnyWordSpec with Matchers with ScalaCheckPropertyCh
855855
checkError(""""P0DT-9223372036854775809S"""", "illegal duration, offset: 0x00000018")
856856
checkError(""""P1DT1HXM"""", """expected '"' or '-' or digit, offset: 0x00000007""")
857857
checkError(""""P1DT1H-XM"""", "expected digit, offset: 0x00000008")
858-
checkError(""""P1DT1H1XM"""", "expected 'M' or 'S or '.' or digit, offset: 0x00000008")
858+
checkError(""""P1DT1H1XM"""", "expected 'M' or 'S' or '.' or digit, offset: 0x00000008")
859859
checkError(""""P0DT0H153722867280912931M"""", "illegal duration, offset: 0x00000019")
860860
checkError(""""P0DT0H-153722867280912931M"""", "illegal duration, offset: 0x0000001a")
861861
checkError(""""P0DT0H9223372036854775808S"""", "illegal duration, offset: 0x0000001a")
862862
checkError(""""P0DT0H92233720368547758000S"""", "illegal duration, offset: 0x0000001a")
863863
checkError(""""P0DT0H-9223372036854775809S"""", "illegal duration, offset: 0x0000001a")
864864
checkError(""""P1DT1H1MXS"""", """expected '"' or '-' or digit, offset: 0x00000009""")
865865
checkError(""""P1DT1H1M-XS"""", "expected digit, offset: 0x0000000a")
866-
checkError(""""P1DT1H1M0XS"""", "expected 'S or '.' or digit, offset: 0x0000000a")
866+
checkError(""""P1DT1H1M0XS"""", "expected 'S' or '.' or digit, offset: 0x0000000a")
867867
checkError(""""P1DT1H1M0.XS"""", "expected 'S' or digit, offset: 0x0000000b")
868868
checkError(""""P1DT1H1M0.012345678XS"""", "expected 'S', offset: 0x00000014")
869869
checkError(""""P1DT1H1M0.0123456789S"""", "expected 'S', offset: 0x00000014")

0 commit comments

Comments
 (0)