Skip to content

Commit d795705

Browse files
committed
#433 Possible fix for big integer overflows.
Expect this to happen when a parsed test looks like scientific notation (2+e99)
1 parent 29163c1 commit d795705

File tree

4 files changed

+264
-23
lines changed

4 files changed

+264
-23
lines changed

cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/decoders/StringDecoders.scala

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ object StringDecoders {
4343
* @param improvedNullDetection if true, return null if all bytes are zero
4444
* @return A string representation of the binary data
4545
*/
46-
def decodeEbcdicString(bytes: Array[Byte], trimmingType: Int, conversionTable: Array[Char], improvedNullDetection: Boolean): String = {
46+
final def decodeEbcdicString(bytes: Array[Byte], trimmingType: Int, conversionTable: Array[Char], improvedNullDetection: Boolean): String = {
4747
if (improvedNullDetection && isArrayNull(bytes))
4848
return null
4949

@@ -73,7 +73,7 @@ object StringDecoders {
7373
* @param improvedNullDetection if true, return null if all bytes are zero
7474
* @return A string representation of the binary data
7575
*/
76-
def decodeAsciiString(bytes: Array[Byte], trimmingType: Int, improvedNullDetection: Boolean): String = {
76+
final def decodeAsciiString(bytes: Array[Byte], trimmingType: Int, improvedNullDetection: Boolean): String = {
7777
if (improvedNullDetection && isArrayNull(bytes))
7878
return null
7979

@@ -105,7 +105,7 @@ object StringDecoders {
105105
* @param improvedNullDetection if true, return null if all bytes are zero
106106
* @return A string representation of the binary data
107107
*/
108-
def decodeUtf16String(bytes: Array[Byte], trimmingType: Int, isUtf16BigEndian: Boolean, improvedNullDetection: Boolean): String = {
108+
final def decodeUtf16String(bytes: Array[Byte], trimmingType: Int, isUtf16BigEndian: Boolean, improvedNullDetection: Boolean): String = {
109109
if (improvedNullDetection && isArrayNull(bytes))
110110
return null
111111

@@ -132,7 +132,7 @@ object StringDecoders {
132132
* @param bytes A byte array that represents the binary data
133133
* @return A HEX string representation of the binary data
134134
*/
135-
def decodeHex(bytes: Array[Byte]): String = {
135+
final def decodeHex(bytes: Array[Byte]): String = {
136136
val hexChars = new Array[Char](bytes.length * 2)
137137
var i = 0
138138
while (i < bytes.length) {
@@ -150,7 +150,7 @@ object StringDecoders {
150150
* @param bytes A byte array that represents the binary data
151151
* @return A string representation of the bytes
152152
*/
153-
def decodeRaw(bytes: Array[Byte]): Array[Byte] = bytes
153+
final def decodeRaw(bytes: Array[Byte]): Array[Byte] = bytes
154154

155155
/**
156156
* A decoder for any EBCDIC uncompressed numbers supporting
@@ -165,7 +165,7 @@ object StringDecoders {
165165
* @param improvedNullDetection if true, return null if all bytes are zero
166166
* @return A string representation of the binary data
167167
*/
168-
def decodeEbcdicNumber(bytes: Array[Byte], isUnsigned: Boolean, improvedNullDetection: Boolean): String = {
168+
final def decodeEbcdicNumber(bytes: Array[Byte], isUnsigned: Boolean, improvedNullDetection: Boolean): String = {
169169
if (improvedNullDetection && isArrayNull(bytes))
170170
return null
171171

@@ -236,7 +236,8 @@ object StringDecoders {
236236
* @param improvedNullDetection if true, return null if all bytes are zero
237237
* @return A string representation of the binary data
238238
*/
239-
def decodeAsciiNumber(bytes: Array[Byte], isUnsigned: Boolean, improvedNullDetection: Boolean): String = {
239+
final def decodeAsciiNumber(bytes: Array[Byte], isUnsigned: Boolean, improvedNullDetection: Boolean): String = {
240+
val allowedDigitChars = " 0123456789"
240241
if (improvedNullDetection && isArrayNull(bytes))
241242
return null
242243

@@ -251,7 +252,10 @@ object StringDecoders {
251252
if (char == '.' || char == ',') {
252253
buf.append('.')
253254
} else {
254-
buf.append(char)
255+
if (allowedDigitChars.contains(char))
256+
buf.append(char)
257+
else
258+
return null
255259
}
256260
}
257261
i = i + 1
@@ -269,7 +273,7 @@ object StringDecoders {
269273
* @param bytes A byte array that represents the binary data
270274
* @return A boxed integer
271275
*/
272-
def decodeEbcdicInt(bytes: Array[Byte], isUnsigned: Boolean, improvedNullDetection: Boolean): Integer = {
276+
final def decodeEbcdicInt(bytes: Array[Byte], isUnsigned: Boolean, improvedNullDetection: Boolean): Integer = {
273277
try {
274278
decodeEbcdicNumber(bytes, isUnsigned, improvedNullDetection).toInt
275279
} catch {
@@ -283,7 +287,7 @@ object StringDecoders {
283287
* @param bytes A byte array that represents the binary data
284288
* @return A boxed integer
285289
*/
286-
def decodeAsciiInt(bytes: Array[Byte], isUnsigned: Boolean, improvedNullDetection: Boolean): Integer = {
290+
final def decodeAsciiInt(bytes: Array[Byte], isUnsigned: Boolean, improvedNullDetection: Boolean): Integer = {
287291
try {
288292
decodeAsciiNumber(bytes, isUnsigned, improvedNullDetection).toInt
289293
} catch {
@@ -297,7 +301,7 @@ object StringDecoders {
297301
* @param bytes A byte array that represents the binary data
298302
* @return A boxed long
299303
*/
300-
def decodeEbcdicLong(bytes: Array[Byte], isUnsigned: Boolean, improvedNullDetection: Boolean): java.lang.Long = {
304+
final def decodeEbcdicLong(bytes: Array[Byte], isUnsigned: Boolean, improvedNullDetection: Boolean): java.lang.Long = {
301305
try {
302306
decodeEbcdicNumber(bytes, isUnsigned, improvedNullDetection).toLong
303307
} catch {
@@ -311,7 +315,7 @@ object StringDecoders {
311315
* @param bytes A byte array that represents the binary data
312316
* @return A boxed long
313317
*/
314-
def decodeAsciiLong(bytes: Array[Byte], isUnsigned: Boolean, improvedNullDetection: Boolean): java.lang.Long = {
318+
final def decodeAsciiLong(bytes: Array[Byte], isUnsigned: Boolean, improvedNullDetection: Boolean): java.lang.Long = {
315319
try {
316320
decodeAsciiNumber(bytes, isUnsigned, improvedNullDetection).toLong
317321
} catch {
@@ -327,7 +331,7 @@ object StringDecoders {
327331
* @param scaleFactor Additional zeros to be added before of after the decimal point
328332
* @return A big decimal containing a big integral number
329333
*/
330-
def decodeEbcdicBigNumber(bytes: Array[Byte], isUnsigned: Boolean, improvedNullDetection: Boolean, scale: Int = 0, scaleFactor: Int = 0): BigDecimal = {
334+
final def decodeEbcdicBigNumber(bytes: Array[Byte], isUnsigned: Boolean, improvedNullDetection: Boolean, scale: Int = 0, scaleFactor: Int = 0): BigDecimal = {
331335
try {
332336
BigDecimal(BinaryUtils.addDecimalPoint(decodeEbcdicNumber(bytes, isUnsigned, improvedNullDetection), scale, scaleFactor))
333337
} catch {
@@ -343,7 +347,7 @@ object StringDecoders {
343347
* @param scaleFactor Additional zeros to be added before of after the decimal point
344348
* @return A big decimal containing a big integral number
345349
*/
346-
def decodeAsciiBigNumber(bytes: Array[Byte], isUnsigned: Boolean, improvedNullDetection: Boolean, scale: Int = 0, scaleFactor: Int = 0): BigDecimal = {
350+
final def decodeAsciiBigNumber(bytes: Array[Byte], isUnsigned: Boolean, improvedNullDetection: Boolean, scale: Int = 0, scaleFactor: Int = 0): BigDecimal = {
347351
try {
348352
BigDecimal(BinaryUtils.addDecimalPoint(decodeAsciiNumber(bytes, isUnsigned, improvedNullDetection), scale, scaleFactor))
349353
} catch {
@@ -358,7 +362,7 @@ object StringDecoders {
358362
* @param bytes A byte array that represents the binary data
359363
* @return A big decimal containing a big integral number
360364
*/
361-
def decodeEbcdicBigDecimal(bytes: Array[Byte], isUnsigned: Boolean, improvedNullDetection: Boolean): BigDecimal = {
365+
final def decodeEbcdicBigDecimal(bytes: Array[Byte], isUnsigned: Boolean, improvedNullDetection: Boolean): BigDecimal = {
362366
try {
363367
BigDecimal(decodeEbcdicNumber(bytes, isUnsigned, improvedNullDetection))
364368
} catch {
@@ -373,7 +377,7 @@ object StringDecoders {
373377
* @param bytes A byte array that represents the binary data
374378
* @return A big decimal containing a big integral number
375379
*/
376-
def decodeAsciiBigDecimal(bytes: Array[Byte], isUnsigned: Boolean, improvedNullDetection: Boolean): BigDecimal = {
380+
final def decodeAsciiBigDecimal(bytes: Array[Byte], isUnsigned: Boolean, improvedNullDetection: Boolean): BigDecimal = {
377381
try {
378382
BigDecimal(decodeAsciiNumber(bytes, isUnsigned, improvedNullDetection))
379383
} catch {

cobol-parser/src/main/scala/za/co/absa/cobrix/cobol/parser/decoders/StringTools.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ object StringTools {
2525
* @param s A string
2626
* @return The trimmed string
2727
*/
28-
def trimLeft(s: String): String = {
28+
final def trimLeft(s: String): String = {
2929
val len = s.length
3030
var st = 0
3131
val v = s.toCharArray
@@ -46,7 +46,7 @@ object StringTools {
4646
* @param s A string
4747
* @return The trimmed string
4848
*/
49-
def trimRight(s: String): String = {
49+
final def trimRight(s: String): String = {
5050
var len = s.length
5151
val st = 0
5252
val v = s.toCharArray
@@ -60,7 +60,7 @@ object StringTools {
6060
else s
6161
}
6262

63-
def isArrayNull(bytes: Array[Byte]): Boolean = {
63+
final def isArrayNull(bytes: Array[Byte]): Boolean = {
6464
var i = 0
6565
val size = bytes.length
6666
while (i < size) {

cobol-parser/src/test/scala/za/co/absa/cobrix/cobol/parser/decoders/StringDecodersSpec.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -273,8 +273,8 @@ class StringDecodersSpec extends WordSpec {
273273
assert(decodeAsciiNumber("100,00-".getBytes, isUnsigned = false, improvedNullDetection = false) == "-100.00")
274274
}
275275

276-
"return trimmed string if non-digit characters are encountered" in {
277-
assert(decodeAsciiNumber("AAABBBCCC".getBytes, isUnsigned = false, improvedNullDetection = false) == "AAABBBCCC")
276+
"return null if non-digit characters are encountered" in {
277+
assert(decodeAsciiNumber("AAABBBCCC".getBytes, isUnsigned = false, improvedNullDetection = false) == null)
278278
}
279279
}
280280

@@ -458,8 +458,8 @@ class StringDecodersSpec extends WordSpec {
458458
assert(decodeAsciiBigDecimal("12345678901234567890123456.12345678901234567890123456".getBytes, isUnsigned = true, improvedNullDetection = false) == BigDecimal("12345678901234567890123456.12345678901234567890123456"))
459459
}
460460

461-
"decode numbers in scientific format" in {
462-
assert(decodeAsciiBigDecimal("200E+10".getBytes, isUnsigned = false, improvedNullDetection = false) == 2.00E+12)
461+
"not decode numbers in scientific format" in {
462+
assert(decodeAsciiBigDecimal("200E+10".getBytes, isUnsigned = false, improvedNullDetection = false) == null)
463463
}
464464

465465
"return null for malformed numbers" in {

0 commit comments

Comments
 (0)