This is an automated email from the ASF dual-hosted git repository.

jadams pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/daffodil.git


The following commit(s) were added to refs/heads/main by this push:
     new eb9f4f57a Convert BigInt/Decimal to expected types for packed numbers
eb9f4f57a is described below

commit eb9f4f57a94bb63bc2b364673eacd4424fe55fc1
Author: Josh Adams <[email protected]>
AuthorDate: Fri Dec 13 09:59:11 2024 -0500

    Convert BigInt/Decimal to expected types for packed numbers
    
    Packed numbers had been represented internally as BigInt/Decimal.  This
    could cause issues when the values were referenced as part of an
    expression and would lead to class conversion errors.  This commit
    parses the packed numbers into their expected numeric type.
    
    DAFFODIL-2961
---
 .../apache/daffodil/core/dsom/ElementBase.scala    |   6 +-
 .../daffodil/runtime1/processors/BCDParsers.scala  |  27 ++---
 .../processors/IBM4690PackedDecimalParsers.scala   |  30 ++----
 .../runtime1/processors/PackedBinaryTraits.scala   |  61 ++++++-----
 .../runtime1/processors/PackedDecimalParsers.scala |  31 ++----
 .../processors/parsers/DelimitedParsers.scala      |  29 ++----
 .../section05/simple_types/SimpleTypes.tdml        |   4 +-
 .../apache/daffodil/section13/packed/packed.tdml   | 111 ++++++++++++++++++---
 .../daffodil/section13/packed/TestPacked.scala     |   6 ++
 9 files changed, 184 insertions(+), 121 deletions(-)

diff --git 
a/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/ElementBase.scala 
b/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/ElementBase.scala
index 825f69da8..0130affc9 100644
--- 
a/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/ElementBase.scala
+++ 
b/daffodil-core/src/main/scala/org/apache/daffodil/core/dsom/ElementBase.scala
@@ -772,7 +772,11 @@ trait ElementBase
     // Validate that the number of bits does not exceed the maximum number of
     // bits allowed for the type
     if (
-      result.isDefined && repElement.isSimpleType && representation == 
Representation.Binary
+      result.isDefined &&
+      repElement.isSimpleType &&
+      representation == Representation.Binary &&
+      // Don't check bit length of packed binary numbers
+      (!optionBinaryNumberRep.isDefined || (binaryNumberRep == 
BinaryNumberRep.Binary))
     ) {
       val nBits = result.get
       primType match {
diff --git 
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/BCDParsers.scala
 
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/BCDParsers.scala
index 7c6311e10..e18eecd50 100644
--- 
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/BCDParsers.scala
+++ 
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/BCDParsers.scala
@@ -34,9 +34,8 @@ class BCDDecimalKnownLengthParser(
 ) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint)
   with HasKnownLengthInBits {
 
-  override def toBigInteger(num: Array[Byte]): JBigInteger = 
DecimalUtils.bcdToBigInteger(num)
-  override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
-    DecimalUtils.bcdToBigDecimal(num, scale)
+  override def toNumber(num: Array[Byte]): JBigDecimal =
+    DecimalUtils.bcdToBigDecimal(num, binaryDecimalVirtualPoint)
 
 }
 
@@ -48,9 +47,8 @@ class BCDDecimalRuntimeLengthParser(
 ) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint)
   with HasRuntimeExplicitLength {
 
-  override def toBigInteger(num: Array[Byte]): JBigInteger = 
DecimalUtils.bcdToBigInteger(num)
-  override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
-    DecimalUtils.bcdToBigDecimal(num, scale)
+  override def toNumber(num: Array[Byte]): JBigDecimal =
+    DecimalUtils.bcdToBigDecimal(num, binaryDecimalVirtualPoint)
 
 }
 
@@ -64,9 +62,8 @@ class BCDDecimalPrefixedLengthParser(
 ) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint)
   with PrefixedLengthParserMixin {
 
-  override def toBigInteger(num: Array[Byte]): JBigInteger = 
DecimalUtils.bcdToBigInteger(num)
-  override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
-    DecimalUtils.bcdToBigDecimal(num, scale)
+  override def toNumber(num: Array[Byte]): JBigDecimal =
+    DecimalUtils.bcdToBigDecimal(num, binaryDecimalVirtualPoint)
 
   override def childProcessors: Vector[Processor] = 
Vector(prefixedLengthParser)
 
@@ -83,9 +80,7 @@ class BCDIntegerRuntimeLengthParser(
 ) extends PackedBinaryIntegerBaseParser(e)
   with HasRuntimeExplicitLength {
 
-  override def toBigInteger(num: Array[Byte]): JBigInteger = 
DecimalUtils.bcdToBigInteger(num)
-  override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
-    DecimalUtils.bcdToBigDecimal(num, scale)
+  override def toNumber(num: Array[Byte]): JBigInteger = 
DecimalUtils.bcdToBigInteger(num)
 
 }
 
@@ -93,9 +88,7 @@ class BCDIntegerKnownLengthParser(e: ElementRuntimeData, val 
lengthInBits: Int)
   extends PackedBinaryIntegerBaseParser(e)
   with HasKnownLengthInBits {
 
-  override def toBigInteger(num: Array[Byte]): JBigInteger = 
DecimalUtils.bcdToBigInteger(num)
-  override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
-    DecimalUtils.bcdToBigDecimal(num, scale)
+  override def toNumber(num: Array[Byte]): JBigInteger = 
DecimalUtils.bcdToBigInteger(num)
 
 }
 
@@ -108,9 +101,7 @@ class BCDIntegerPrefixedLengthParser(
 ) extends PackedBinaryIntegerBaseParser(e)
   with PrefixedLengthParserMixin {
 
-  override def toBigInteger(num: Array[Byte]): JBigInteger = 
DecimalUtils.bcdToBigInteger(num)
-  override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
-    DecimalUtils.bcdToBigDecimal(num, scale)
+  override def toNumber(num: Array[Byte]): JBigInteger = 
DecimalUtils.bcdToBigInteger(num)
 
   override def childProcessors: Vector[Processor] = 
Vector(prefixedLengthParser)
 
diff --git 
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/IBM4690PackedDecimalParsers.scala
 
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/IBM4690PackedDecimalParsers.scala
index dc2799262..e0a359818 100644
--- 
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/IBM4690PackedDecimalParsers.scala
+++ 
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/IBM4690PackedDecimalParsers.scala
@@ -34,10 +34,8 @@ class IBM4690PackedDecimalKnownLengthParser(
 ) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint)
   with HasKnownLengthInBits {
 
-  override def toBigInteger(num: Array[Byte]): JBigInteger =
-    DecimalUtils.ibm4690ToBigInteger(num)
-  override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
-    DecimalUtils.ibm4690ToBigDecimal(num, scale)
+  override def toNumber(num: Array[Byte]): JBigDecimal =
+    DecimalUtils.ibm4690ToBigDecimal(num, binaryDecimalVirtualPoint)
 
 }
 
@@ -49,10 +47,8 @@ class IBM4690PackedDecimalRuntimeLengthParser(
 ) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint)
   with HasRuntimeExplicitLength {
 
-  override def toBigInteger(num: Array[Byte]): JBigInteger =
-    DecimalUtils.ibm4690ToBigInteger(num)
-  override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
-    DecimalUtils.ibm4690ToBigDecimal(num, scale)
+  override def toNumber(num: Array[Byte]): JBigDecimal =
+    DecimalUtils.ibm4690ToBigDecimal(num, binaryDecimalVirtualPoint)
 
 }
 
@@ -66,10 +62,8 @@ class IBM4690PackedDecimalPrefixedLengthParser(
 ) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint)
   with PrefixedLengthParserMixin {
 
-  override def toBigInteger(num: Array[Byte]): JBigInteger =
-    DecimalUtils.ibm4690ToBigInteger(num)
-  override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
-    DecimalUtils.ibm4690ToBigDecimal(num, scale)
+  override def toNumber(num: Array[Byte]): JBigDecimal =
+    DecimalUtils.ibm4690ToBigDecimal(num, binaryDecimalVirtualPoint)
 
   override def childProcessors: Vector[Processor] = 
Vector(prefixedLengthParser)
 
@@ -86,10 +80,8 @@ class IBM4690PackedIntegerRuntimeLengthParser(
 ) extends PackedBinaryIntegerBaseParser(e)
   with HasRuntimeExplicitLength {
 
-  override def toBigInteger(num: Array[Byte]): JBigInteger =
+  override def toNumber(num: Array[Byte]): JBigInteger =
     DecimalUtils.ibm4690ToBigInteger(num)
-  override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
-    DecimalUtils.ibm4690ToBigDecimal(num, scale)
 
 }
 
@@ -99,10 +91,8 @@ class IBM4690PackedIntegerKnownLengthParser(
 ) extends PackedBinaryIntegerBaseParser(e)
   with HasKnownLengthInBits {
 
-  override def toBigInteger(num: Array[Byte]): JBigInteger =
+  override def toNumber(num: Array[Byte]): JBigInteger =
     DecimalUtils.ibm4690ToBigInteger(num)
-  override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
-    DecimalUtils.ibm4690ToBigDecimal(num, scale)
 
 }
 
@@ -115,10 +105,8 @@ class IBM4690PackedIntegerPrefixedLengthParser(
 ) extends PackedBinaryIntegerBaseParser(e)
   with PrefixedLengthParserMixin {
 
-  override def toBigInteger(num: Array[Byte]): JBigInteger =
+  override def toNumber(num: Array[Byte]): JBigInteger =
     DecimalUtils.ibm4690ToBigInteger(num)
-  override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
-    DecimalUtils.ibm4690ToBigDecimal(num, scale)
 
   override def childProcessors: Vector[Processor] = 
Vector(prefixedLengthParser)
 
diff --git 
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/PackedBinaryTraits.scala
 
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/PackedBinaryTraits.scala
index ca7bedf41..1694681b0 100644
--- 
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/PackedBinaryTraits.scala
+++ 
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/PackedBinaryTraits.scala
@@ -26,7 +26,9 @@ import org.apache.daffodil.lib.equality.TypeEqual
 import org.apache.daffodil.lib.exceptions.Assert
 import org.apache.daffodil.lib.util.Maybe
 import org.apache.daffodil.lib.util.MaybeChar
-import org.apache.daffodil.runtime1.dpath.NodeInfo
+import org.apache.daffodil.runtime1.dpath.InvalidPrimitiveDataException
+import org.apache.daffodil.runtime1.dpath.NodeInfo.PrimType
+import org.apache.daffodil.runtime1.infoset.DataValue.DataValueNumber
 import org.apache.daffodil.runtime1.processors.ElementRuntimeData
 import org.apache.daffodil.runtime1.processors.FieldDFAParseEv
 import org.apache.daffodil.runtime1.processors.ParseOrUnparseState
@@ -36,9 +38,22 @@ import 
org.apache.daffodil.runtime1.processors.dfa.TextDelimitedParserBase
 
 import passera.unsigned.ULong
 
-trait PackedBinaryConversion {
-  def toBigInteger(num: Array[Byte]): JBigInteger
-  def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal
+trait PackedBinaryConversion[A <: Number] {
+
+  /**
+   * Converts the byte array to either a BigInteger or Big Decimal as defined 
by
+   * the implementing class
+   */
+  def toNumber(num: Array[Byte]): A
+
+  def toPrimType(context: ElementRuntimeData, num: Array[Byte]): 
DataValueNumber = {
+    context.optPrimType.get match {
+      case pn: PrimType.PrimNumeric => pn.fromNumber(toNumber(num))
+      // Non-numeric types such as Time can still use these funcitons and
+      // expect BigIntegers as the output of the conversion
+      case _ => toNumber(num)
+    }
+  }
 }
 
 trait PackedBinaryLengthCheck {
@@ -74,7 +89,7 @@ abstract class PackedBinaryDecimalBaseParser(
   override val context: ElementRuntimeData,
   binaryDecimalVirtualPoint: Int
 ) extends PrimParser
-  with PackedBinaryConversion
+  with PackedBinaryConversion[JBigDecimal]
   with PackedBinaryLengthCheck {
   override lazy val runtimeDependencies = Vector()
 
@@ -95,10 +110,12 @@ abstract class PackedBinaryDecimalBaseParser(
     }
 
     try {
-      val bigDec = toBigDecimal(dis.getByteArray(nBits, start), 
binaryDecimalVirtualPoint)
-      start.simpleElement.overwriteDataValue(bigDec)
+      val dec = toPrimType(context, dis.getByteArray(nBits, start))
+      start.simpleElement.setDataValue(dec)
     } catch {
       case n: NumberFormatException => PE(start, "Error in packed data: \n%s", 
n.getMessage())
+      case i: InvalidPrimitiveDataException =>
+        PE(start, "Error in packed data: \n%s", i.getMessage())
     }
   }
 }
@@ -106,17 +123,10 @@ abstract class PackedBinaryDecimalBaseParser(
 abstract class PackedBinaryIntegerBaseParser(
   override val context: ElementRuntimeData
 ) extends PrimParser
-  with PackedBinaryConversion
+  with PackedBinaryConversion[JBigInteger]
   with PackedBinaryLengthCheck {
   override lazy val runtimeDependencies = Vector()
 
-  val signed = {
-    context.optPrimType.get match {
-      case n: NodeInfo.PrimType.PrimNumeric => n.isSigned
-      // context.optPrimType can be of type date/time via 
ConvertZonedCombinator
-      case _ => false
-    }
-  }
   protected def getBitLength(s: ParseOrUnparseState): Int
 
   def parse(start: PState): Unit = {
@@ -134,13 +144,12 @@ abstract class PackedBinaryIntegerBaseParser(
     }
 
     try {
-      val int = toBigInteger(dis.getByteArray(nBits, start))
-      if (!signed && (int.signum != 1))
-        PE(start, "Expected unsigned data but parsed a negative number")
-      else
-        start.simpleElement.overwriteDataValue(int)
+      val int = toPrimType(context, dis.getByteArray(nBits, start))
+      start.simpleElement.setDataValue(int)
     } catch {
       case n: NumberFormatException => PE(start, "Error in packed data: \n%s", 
n.getMessage())
+      case i: InvalidPrimitiveDataException =>
+        PE(start, "Error in packed data: \n%s", i.getMessage())
     }
   }
 }
@@ -158,7 +167,7 @@ abstract class PackedBinaryIntegerDelimitedBaseParser(
     fieldDFAEv,
     isDelimRequired
   )
-  with PackedBinaryConversion {
+  with PackedBinaryConversion[JBigInteger] {
 
   override def processResult(parseResult: Maybe[dfa.ParseResult], state: 
PState): Unit = {
     Assert.invariant(
@@ -177,11 +186,13 @@ abstract class PackedBinaryIntegerDelimitedBaseParser(
         return
       } else {
         try {
-          val num = toBigInteger(fieldBytes)
+          val num = toPrimType(context, fieldBytes)
           state.simpleElement.setDataValue(num)
         } catch {
           case n: NumberFormatException =>
             PE(state, "Error in packed data: \n%s", n.getMessage())
+          case i: InvalidPrimitiveDataException =>
+            PE(state, "Error in packed data: \n%s", i.getMessage())
         }
 
         if (result.matchedDelimiterValue.isDefined) 
state.saveDelimitedParseResult(parseResult)
@@ -205,7 +216,7 @@ abstract class PackedBinaryDecimalDelimitedBaseParser(
     fieldDFAEv,
     isDelimRequired
   )
-  with PackedBinaryConversion {
+  with PackedBinaryConversion[JBigDecimal] {
 
   /**
    * We are treating packed binary formats as just a string in iso-8859-1 
encoding.
@@ -236,11 +247,13 @@ abstract class PackedBinaryDecimalDelimitedBaseParser(
         return
       } else {
         try {
-          val num = toBigDecimal(fieldBytes, binaryDecimalVirtualPoint)
+          val num = toPrimType(e, fieldBytes)
           state.simpleElement.setDataValue(num)
         } catch {
           case n: NumberFormatException =>
             PE(state, "Error in packed data: \n%s", n.getMessage())
+          case i: InvalidPrimitiveDataException =>
+            PE(state, "Error in packed data: \n%s", i.getMessage())
         }
 
         if (result.matchedDelimiterValue.isDefined) 
state.saveDelimitedParseResult(parseResult)
diff --git 
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/PackedDecimalParsers.scala
 
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/PackedDecimalParsers.scala
index 6f130de9f..7e19f2d1f 100644
--- 
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/PackedDecimalParsers.scala
+++ 
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/PackedDecimalParsers.scala
@@ -35,10 +35,8 @@ class PackedDecimalKnownLengthParser(
 ) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint)
   with HasKnownLengthInBits {
 
-  override def toBigInteger(num: Array[Byte]): JBigInteger =
-    DecimalUtils.packedToBigInteger(num, packedSignCodes)
-  override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
-    DecimalUtils.packedToBigDecimal(num, scale, packedSignCodes)
+  override def toNumber(num: Array[Byte]): JBigDecimal =
+    DecimalUtils.packedToBigDecimal(num, binaryDecimalVirtualPoint, 
packedSignCodes)
 
 }
 
@@ -51,11 +49,8 @@ class PackedDecimalRuntimeLengthParser(
 ) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint)
   with HasRuntimeExplicitLength {
 
-  override def toBigInteger(num: Array[Byte]): JBigInteger =
-    DecimalUtils.packedToBigInteger(num, packedSignCodes)
-  override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
-    DecimalUtils.packedToBigDecimal(num, scale, packedSignCodes)
-
+  override def toNumber(num: Array[Byte]): JBigDecimal =
+    DecimalUtils.packedToBigDecimal(num, binaryDecimalVirtualPoint, 
packedSignCodes)
 }
 
 class PackedDecimalPrefixedLengthParser(
@@ -69,10 +64,8 @@ class PackedDecimalPrefixedLengthParser(
 ) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint)
   with PrefixedLengthParserMixin {
 
-  override def toBigInteger(num: Array[Byte]): JBigInteger =
-    DecimalUtils.packedToBigInteger(num, packedSignCodes)
-  override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
-    DecimalUtils.packedToBigDecimal(num, scale, packedSignCodes)
+  override def toNumber(num: Array[Byte]): JBigDecimal =
+    DecimalUtils.packedToBigDecimal(num, binaryDecimalVirtualPoint, 
packedSignCodes)
 
   override def childProcessors: Vector[Processor] = 
Vector(prefixedLengthParser)
 
@@ -90,10 +83,8 @@ class PackedIntegerRuntimeLengthParser(
 ) extends PackedBinaryIntegerBaseParser(e)
   with HasRuntimeExplicitLength {
 
-  override def toBigInteger(num: Array[Byte]): JBigInteger =
+  override def toNumber(num: Array[Byte]): JBigInteger =
     DecimalUtils.packedToBigInteger(num, packedSignCodes)
-  override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
-    DecimalUtils.packedToBigDecimal(num, scale, packedSignCodes)
 
 }
 
@@ -104,10 +95,8 @@ class PackedIntegerKnownLengthParser(
 ) extends PackedBinaryIntegerBaseParser(e)
   with HasKnownLengthInBits {
 
-  override def toBigInteger(num: Array[Byte]): JBigInteger =
+  override def toNumber(num: Array[Byte]): JBigInteger =
     DecimalUtils.packedToBigInteger(num, packedSignCodes)
-  override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
-    DecimalUtils.packedToBigDecimal(num, scale, packedSignCodes)
 
 }
 
@@ -121,10 +110,8 @@ class PackedIntegerPrefixedLengthParser(
 ) extends PackedBinaryIntegerBaseParser(e)
   with PrefixedLengthParserMixin {
 
-  override def toBigInteger(num: Array[Byte]): JBigInteger =
+  override def toNumber(num: Array[Byte]): JBigInteger =
     DecimalUtils.packedToBigInteger(num, packedSignCodes)
-  override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
-    DecimalUtils.packedToBigDecimal(num, scale, packedSignCodes)
 
   override def childProcessors: Vector[Processor] = 
Vector(prefixedLengthParser)
 
diff --git 
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/DelimitedParsers.scala
 
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/DelimitedParsers.scala
index edd34e825..ce07969eb 100644
--- 
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/DelimitedParsers.scala
+++ 
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/DelimitedParsers.scala
@@ -215,10 +215,8 @@ class PackedIntegerDelimitedParser(
   packedSignCodes: PackedSignCodes
 ) extends PackedBinaryIntegerDelimitedBaseParser(erd, textParser, fieldDFAEv, 
isDelimRequired) {
 
-  override def toBigInteger(num: Array[Byte]): JBigInteger =
+  override def toNumber(num: Array[Byte]): JBigInteger =
     DecimalUtils.packedToBigInteger(num, packedSignCodes)
-  override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
-    DecimalUtils.packedToBigDecimal(num, scale, packedSignCodes)
 
 }
 
@@ -237,10 +235,8 @@ class PackedDecimalDelimitedParser(
     binaryDecimalVirtualPoint
   ) {
 
-  override def toBigInteger(num: Array[Byte]): JBigInteger =
-    DecimalUtils.packedToBigInteger(num, packedSignCodes)
-  override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
-    DecimalUtils.packedToBigDecimal(num, scale, packedSignCodes)
+  override def toNumber(num: Array[Byte]): JBigDecimal =
+    DecimalUtils.packedToBigDecimal(num, binaryDecimalVirtualPoint, 
packedSignCodes)
 
 }
 
@@ -251,9 +247,7 @@ class BCDIntegerDelimitedParser(
   isDelimRequired: Boolean
 ) extends PackedBinaryIntegerDelimitedBaseParser(erd, textParser, fieldDFAEv, 
isDelimRequired) {
 
-  override def toBigInteger(num: Array[Byte]): JBigInteger = 
DecimalUtils.bcdToBigInteger(num)
-  override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
-    DecimalUtils.bcdToBigDecimal(num, scale)
+  override def toNumber(num: Array[Byte]): JBigInteger = 
DecimalUtils.bcdToBigInteger(num)
 
 }
 
@@ -271,9 +265,8 @@ class BCDDecimalDelimitedParser(
     binaryDecimalVirtualPoint
   ) {
 
-  override def toBigInteger(num: Array[Byte]): JBigInteger = 
DecimalUtils.bcdToBigInteger(num)
-  override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
-    DecimalUtils.bcdToBigDecimal(num, scale)
+  override def toNumber(num: Array[Byte]): JBigDecimal =
+    DecimalUtils.bcdToBigDecimal(num, binaryDecimalVirtualPoint)
 
 }
 
@@ -284,10 +277,8 @@ class IBM4690PackedIntegerDelimitedParser(
   isDelimRequired: Boolean
 ) extends PackedBinaryIntegerDelimitedBaseParser(erd, textParser, fieldDFAEv, 
isDelimRequired) {
 
-  override def toBigInteger(num: Array[Byte]): JBigInteger =
+  override def toNumber(num: Array[Byte]): JBigInteger =
     DecimalUtils.ibm4690ToBigInteger(num)
-  override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
-    DecimalUtils.ibm4690ToBigDecimal(num, scale)
 
 }
 
@@ -305,9 +296,7 @@ class IBM4690PackedDecimalDelimitedParser(
     binaryDecimalVirtualPoint
   ) {
 
-  override def toBigInteger(num: Array[Byte]): JBigInteger =
-    DecimalUtils.ibm4690ToBigInteger(num)
-  override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
-    DecimalUtils.ibm4690ToBigDecimal(num, scale)
+  override def toNumber(num: Array[Byte]): JBigDecimal =
+    DecimalUtils.ibm4690ToBigDecimal(num, binaryDecimalVirtualPoint)
 
 }
diff --git 
a/daffodil-test/src/test/resources/org/apache/daffodil/section05/simple_types/SimpleTypes.tdml
 
b/daffodil-test/src/test/resources/org/apache/daffodil/section05/simple_types/SimpleTypes.tdml
index bdfc5210c..f9bf50c1a 100644
--- 
a/daffodil-test/src/test/resources/org/apache/daffodil/section05/simple_types/SimpleTypes.tdml
+++ 
b/daffodil-test/src/test/resources/org/apache/daffodil/section05/simple_types/SimpleTypes.tdml
@@ -3041,7 +3041,7 @@
     </tdml:document>
     <tdml:errors>
       <tdml:error>Parse Error</tdml:error>
-      <tdml:error>Expected unsigned data but parsed a negative 
number</tdml:error>
+      <tdml:error>Unable to parse xs:date from</tdml:error>
     </tdml:errors>
   </tdml:parserTestCase>
 
@@ -3231,7 +3231,7 @@
     </tdml:document>
     <tdml:errors>
       <tdml:error>Parse Error</tdml:error>
-      <tdml:error>Expected unsigned data but parsed a negative 
number</tdml:error>
+      <tdml:error>Unable to parse xs:dateTime from</tdml:error>
     </tdml:errors>
   </tdml:parserTestCase>
 
diff --git 
a/daffodil-test/src/test/resources/org/apache/daffodil/section13/packed/packed.tdml
 
b/daffodil-test/src/test/resources/org/apache/daffodil/section13/packed/packed.tdml
index 572476206..887b920aa 100644
--- 
a/daffodil-test/src/test/resources/org/apache/daffodil/section13/packed/packed.tdml
+++ 
b/daffodil-test/src/test/resources/org/apache/daffodil/section13/packed/packed.tdml
@@ -20,6 +20,7 @@
   description="Packed Number Properties" 
xmlns:tdml="http://www.ibm.com/xmlns/dfdl/testData";
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xmlns:dfdl="http://www.ogf.org/dfdl/dfdl-1.0/";
   xmlns:xs="http://www.w3.org/2001/XMLSchema"; 
xmlns:ct="http://w3.ibm.com/xmlns/dfdl/ctInfoset";
+  xmlns:fn="http://www.w3.org/2005/xpath-functions";
   xmlns:ex="http://example.com"; xmlns="http://example.com"; 
xmlns:tns="http://example.com"; xmlns:xsd="http://www.w3.org/2001/XMLSchema";
   defaultRoundTrip="true">
 
@@ -33,12 +34,12 @@
     <xs:element name="int02" type="xs:int" dfdl:length="2" 
dfdl:textNumberPattern="'C'000;'D'000" />
 
      <xs:element name="flt01" type="xs:float" dfdl:length="2" 
dfdl:textNumberPattern="00V00"/>
-     
+
      <xs:element name="cal01" type="xs:date" dfdl:length="3"
        dfdl:calendarPatternKind="explicit" dfdl:calendarPattern="MMddyy"/>
-      
+
   </tdml:defineSchema>
-  
+
   <tdml:defineSchema name="s2">
     <xs:include 
schemaLocation="/org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>
     <dfdl:format ref="ex:GeneralFormat" lengthKind="explicit" 
encoding="X-DFDL-HEX-MSBF" occursCountKind="implicit"
@@ -272,7 +273,7 @@
     </tdml:infoset>
 
   </tdml:parserTestCase>
-  
+
   <tdml:parserTestCase name="hexCharset02" root="int02" model="s1"
     description="hex works as a charset encoding, with C and D as sign 
characters">
 
@@ -286,7 +287,7 @@
     </tdml:infoset>
 
   </tdml:parserTestCase>
-  
+
   <tdml:parserTestCase name="hexCharset03" root="flt01" model="s1"
     description="hex works as a charset encoding, P number pattern character">
 
@@ -300,7 +301,7 @@
     </tdml:infoset>
 
   </tdml:parserTestCase>
-    
+
   <tdml:parserTestCase name="hexCharset04" root="cal01" model="s1"
     description="hex works as a charset encoding for calendars">
 
@@ -313,7 +314,7 @@
       </tdml:dfdlInfoset>
     </tdml:infoset>
 
-  </tdml:parserTestCase>  
+  </tdml:parserTestCase>
 
    <tdml:parserTestCase name="packedCharset01" root="int01" model="s2"
     description="Using Packed Decimal formatted hex with C inicating a 
positive integer">
@@ -356,7 +357,7 @@
     </tdml:infoset>
 
   </tdml:parserTestCase>
- 
+
   <tdml:parserTestCase name="packedCharset04" root="cal01" model="s2"
     description="Using Packed Decimal formatted hex for a calendar">
 
@@ -369,7 +370,7 @@
       </tdml:dfdlInfoset>
     </tdml:infoset>
 
-  </tdml:parserTestCase> 
+  </tdml:parserTestCase>
 
   <tdml:parserTestCase name="packedCharset05" root="int02" model="s2"
     description="Using Packed Decimal formatted hex with an invalid sign 
nibble">
@@ -520,7 +521,7 @@
     </tdml:infoset>
 
   </tdml:parserTestCase>
- 
+
   <tdml:parserTestCase name="bcdCharset04" root="cal01" model="s3"
     description="Using BCD formatted hex for a calendar">
 
@@ -533,7 +534,7 @@
       </tdml:dfdlInfoset>
     </tdml:infoset>
 
-  </tdml:parserTestCase> 
+  </tdml:parserTestCase>
 
   <tdml:parserTestCase name="bcdCharset05" root="uint02" model="s3"
     description="Using Packed Decimal formatted hex with an invalid high 
nibble">
@@ -676,7 +677,7 @@
     </tdml:infoset>
 
   </tdml:parserTestCase>
- 
+
   <tdml:parserTestCase name="IBM4690Charset04" root="cal01" model="s4"
     description="Using IBM4690 packed decimal formatted hex for a calendar">
 
@@ -689,7 +690,7 @@
       </tdml:dfdlInfoset>
     </tdml:infoset>
 
-  </tdml:parserTestCase> 
+  </tdml:parserTestCase>
 
   <tdml:parserTestCase name="IBM4690Charset05" root="int02" model="s4"
     description="Using Packed IBM4690 Decimal formatted hex with an invalid 
sign nibble">
@@ -965,4 +966,88 @@
     </tdml:document>
   </tdml:unparserTestCase>
 
+  <tdml:defineSchema name="bcdBigIntToLongExprSch">
+    <xs:include 
schemaLocation="/org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>
+    <dfdl:format ref="ex:GeneralFormat" lengthKind="explicit" 
encoding="X-DFDL-HEX-MSBF" occursCountKind="implicit"
+    textNumberCheckPolicy="strict" textNumberPadCharacter="0" 
textNumberJustification="right"
+    lengthUnits="bytes" binaryNumberRep="bcd" 
binaryNumberCheckPolicy="strict"/>
+    <xs:element name="bcdBigIntToLong" dfdl:lengthKind="delimited">
+      <xs:complexType>
+        <xs:sequence>
+          <xs:element name="uint01" type="xs:unsignedInt" 
dfdl:representation="binary" dfdl:length="1" />
+          <xs:element name="string01" type="xs:string" 
dfdl:encoding="US-ASCII" dfdl:length="{ xs:int(fn:ceiling(../ex:uint01)) }" />
+        </xs:sequence>
+      </xs:complexType>
+    </xs:element>
+  </tdml:defineSchema>
+
+  <!-- Daffodil 2961 -->
+  <tdml:parserTestCase name="bcdBigIntToLongExpr" root="bcdBigIntToLong" 
model="bcdBigIntToLongExprSch"
+    description="Verify that unsigned packed values in an expression work 
correctly">
+
+    <tdml:document>
+      <tdml:documentPart type="byte">0568656C6C6F</tdml:documentPart>
+    </tdml:document>
+    <tdml:infoset>
+      <tdml:dfdlInfoset>
+        <bcdBigIntToLong>
+          <uint01>5</uint01>
+          <string01>hello</string01>
+        </bcdBigIntToLong>
+      </tdml:dfdlInfoset>
+    </tdml:infoset>
+  </tdml:parserTestCase>
+
+  <tdml:defineSchema name="packedDecimalRangeChecks">
+    <xs:include 
schemaLocation="/org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>
+    <dfdl:format ref="ex:GeneralFormat" lengthKind="explicit" 
encoding="X-DFDL-HEX-MSBF" occursCountKind="implicit"
+    textNumberCheckPolicy="strict" textNumberPadCharacter="0" 
textNumberJustification="right"
+    lengthUnits="bytes" binaryNumberRep="packed" binaryPackedSignCodes="C D F 
C" binaryNumberCheckPolicy="strict"/>
+
+    <xs:element name="uint01" type="xs:unsignedInt" 
dfdl:representation="binary" dfdl:length="2" />
+    <xs:element name="int01" type="xs:int" dfdl:representation="binary" 
dfdl:length="6" />
+
+  </tdml:defineSchema>
+
+  <tdml:parserTestCase name="packedNegativeUnsigned" root="uint01" 
model="packedDecimalRangeChecks"
+    description="Using BCD formatted hex to indicate an integer number">
+
+    <tdml:document>
+      <tdml:documentPart type="byte">123D</tdml:documentPart>
+    </tdml:document>
+
+    <tdml:errors>
+      <tdml:error>Parse Error</tdml:error>
+      <tdml:error>out of range for type</tdml:error>
+    </tdml:errors>
+    </tdml:parserTestCase>
+
+  <tdml:parserTestCase name="packedIntTooLarge" root="int01" 
model="packedDecimalRangeChecks"
+    description="Using BCD formatted hex to indicate INT_MAX + 1">
+
+    <tdml:document>
+      <tdml:documentPart type="byte">02147483648C</tdml:documentPart>
+    </tdml:document>
+
+    <tdml:errors>
+      <tdml:error>Parse Error</tdml:error>
+      <tdml:error>Error in packed data</tdml:error>
+      <tdml:error>out of range for type</tdml:error>
+    </tdml:errors>
+    </tdml:parserTestCase>
+
+  <tdml:parserTestCase name="packedIntMax" root="int01" 
model="packedDecimalRangeChecks"
+    description="Using BCD formatted hex to indicate INT_MAX">
+
+    <tdml:document>
+      <tdml:documentPart type="byte">02147483647C</tdml:documentPart>
+    </tdml:document>
+
+    <tdml:infoset>
+      <tdml:dfdlInfoset>
+        <int01>214783647</int01>
+      </tdml:dfdlInfoset>
+    </tdml:infoset>
+  </tdml:parserTestCase>
+
 </tdml:testSuite>
diff --git 
a/daffodil-test/src/test/scala/org/apache/daffodil/section13/packed/TestPacked.scala
 
b/daffodil-test/src/test/scala/org/apache/daffodil/section13/packed/TestPacked.scala
index 029ab04ea..e772a4979 100644
--- 
a/daffodil-test/src/test/scala/org/apache/daffodil/section13/packed/TestPacked.scala
+++ 
b/daffodil-test/src/test/scala/org/apache/daffodil/section13/packed/TestPacked.scala
@@ -75,6 +75,9 @@ class TestPacked {
   @Test def testBCDCharset12(): Unit = { runner.runOneTest("bcdCharset12") }
   @Test def testBCDCharset13(): Unit = { runner.runOneTest("bcdCharset13") }
 
+  @Test def testPackedNegativeUnsigned(): Unit = { 
runner.runOneTest("packedNegativeUnsigned") }
+  @Test def testPackedIntTooLarge(): Unit = { 
runner.runOneTest("packedIntTooLarge") }
+
   @Test def testIBM4690Charset01(): Unit = { 
runner.runOneTest("IBM4690Charset01") }
   @Test def testIBM4690Charset02(): Unit = { 
runner.runOneTest("IBM4690Charset02") }
   @Test def testIBM4690Charset03(): Unit = { 
runner.runOneTest("IBM4690Charset03") }
@@ -110,4 +113,7 @@ class TestPacked {
   @Test def testDelimitedIBM4690DecSeqUnparser(): Unit = {
     runner.runOneTest("DelimitedIBM4690DecSeqUnparser")
   }
+
+  // Daffodil-2961
+  @Test def testBCDBigIntToLongExpr(): Unit = { 
runner.runOneTest("bcdBigIntToLongExpr") }
 }

Reply via email to