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

olabusayo 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 4e6383ebc Add support for `dfdl:decimalSigned` property  to 
parsers/unparsers
4e6383ebc is described below

commit 4e6383ebcf0605c8ffe1e496c09c1f69e9a1d493
Author: olabusayoT <[email protected]>
AuthorDate: Mon Sep 29 15:35:20 2025 -0400

    Add support for `dfdl:decimalSigned` property  to parsers/unparsers
    
    - Integrate `decimalSigned` checks across packed and IBM4690 decimal 
formats.
    - Update parser and unparser implementations to respect `decimalSigned` 
semantics (e.g., disallow negative values when `decimalSigned="no"`).
    - Update tests for `dfdl:decimalSigned`, removing `@Ignore` annotations for 
validation.
    - Adjust TDML error output expectations to include `decimalSigned` error 
messages.
    - Update `dfdl:decimalSigned` handling for delimited packed formats and add 
tests for such
    
    Deprecation/Compatibility
    We added checks for when dfdl:decimalSigned=no or dfdl:decimalSigned is not 
applicabl (as in the case of BCD numbers, which are always positive), but an 
attempt is made to parse to/unparse a negative number
    
    DAFFODIL-2957, DAFFODIL-2963
---
 .../core/grammar/primitives/PrimitivesBCD.scala    | 10 ++-
 .../primitives/PrimitivesIBM4690Packed.scala       | 18 ++++--
 .../grammar/primitives/PrimitivesLengthKind.scala  | 23 +++++--
 .../core/grammar/primitives/PrimitivesPacked.scala | 18 ++++--
 .../daffodil/runtime1/processors/BCDParsers.scala  |  6 +-
 .../processors/IBM4690PackedDecimalParsers.scala   | 16 +++--
 .../runtime1/processors/PackedBinaryTraits.scala   | 26 +++++++-
 .../runtime1/processors/PackedDecimalParsers.scala | 16 +++--
 .../processors/parsers/DelimitedParsers.scala      | 19 ++++--
 .../daffodil/unparsers/runtime1/BCDUnparsers.scala |  2 +-
 .../unparsers/runtime1/BinaryNumberUnparsers.scala | 11 +++-
 .../runtime1/IBM4690PackedDecimalUnparsers.scala   | 26 +++++---
 .../runtime1/PackedBinaryUnparserTraits.scala      | 21 +++++-
 .../runtime1/PackedDecimalUnparsers.scala          | 46 ++++++++++---
 .../section13/decimal/TestDecimalSigned.tdml       | 75 ++++++++++++++++++----
 .../section13/decimal/TestDecimalSigned.scala      | 17 +++--
 16 files changed, 262 insertions(+), 88 deletions(-)

diff --git 
a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesBCD.scala
 
b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesBCD.scala
index 154e22137..e9e0996b0 100644
--- 
a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesBCD.scala
+++ 
b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesBCD.scala
@@ -93,8 +93,14 @@ class BCDDecimalKnownLength(val e: ElementBase, 
lengthInBits: Long) extends Term
 class BCDDecimalPrefixedLength(val e: ElementBase) extends Terminal(e, true) {
 
   override lazy val parser =
-    new BCDDecimalBitLimitLengthParser(e.elementRuntimeData, 
e.binaryDecimalVirtualPoint)
+    new BCDDecimalBitLimitLengthParser(
+      e.elementRuntimeData,
+      e.binaryDecimalVirtualPoint
+    )
 
   override lazy val unparser: Unparser =
-    new BCDDecimalMinimumLengthUnparser(e.elementRuntimeData, 
e.binaryDecimalVirtualPoint)
+    new BCDDecimalMinimumLengthUnparser(
+      e.elementRuntimeData,
+      e.binaryDecimalVirtualPoint
+    )
 }
diff --git 
a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesIBM4690Packed.scala
 
b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesIBM4690Packed.scala
index 1316426de..91d0d25ef 100644
--- 
a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesIBM4690Packed.scala
+++ 
b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesIBM4690Packed.scala
@@ -71,14 +71,16 @@ class IBM4690PackedDecimalRuntimeLength(val e: ElementBase) 
extends Terminal(e,
     e.elementRuntimeData,
     e.binaryDecimalVirtualPoint,
     e.lengthEv,
-    e.lengthUnits
+    e.lengthUnits,
+    e.decimalSigned
   )
 
   override lazy val unparser: Unparser = new 
IBM4690PackedDecimalRuntimeLengthUnparser(
     e.elementRuntimeData,
     e.binaryDecimalVirtualPoint,
     e.lengthEv,
-    e.lengthUnits
+    e.lengthUnits,
+    e.decimalSigned
   )
 
 }
@@ -88,24 +90,28 @@ class IBM4690PackedDecimalKnownLength(val e: ElementBase, 
lengthInBits: Long)
   override lazy val parser = new IBM4690PackedDecimalKnownLengthParser(
     e.elementRuntimeData,
     e.binaryDecimalVirtualPoint,
-    lengthInBits.toInt
+    lengthInBits.toInt,
+    e.decimalSigned
   )
 
   override lazy val unparser: Unparser = new 
IBM4690PackedDecimalKnownLengthUnparser(
     e.elementRuntimeData,
     e.binaryDecimalVirtualPoint,
-    lengthInBits.toInt
+    lengthInBits.toInt,
+    e.decimalSigned
   )
 }
 
 class IBM4690PackedDecimalPrefixedLength(val e: ElementBase) extends 
Terminal(e, true) {
   override lazy val parser = new IBM4690PackedDecimalBitLimitLengthParser(
     e.elementRuntimeData,
-    e.binaryDecimalVirtualPoint
+    e.binaryDecimalVirtualPoint,
+    e.decimalSigned
   )
 
   override lazy val unparser: Unparser = new 
IBM4690PackedDecimalMinimumLengthUnparser(
     e.elementRuntimeData,
-    e.binaryDecimalVirtualPoint
+    e.binaryDecimalVirtualPoint,
+    e.decimalSigned
   )
 }
diff --git 
a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesLengthKind.scala
 
b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesLengthKind.scala
index d17322383..e069353bd 100644
--- 
a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesLengthKind.scala
+++ 
b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesLengthKind.scala
@@ -224,13 +224,15 @@ abstract class PackedDecimalDelimited(e: ElementBase, 
packedSignCodes: PackedSig
     fieldDFAParseEv,
     isDelimRequired,
     e.binaryDecimalVirtualPoint,
-    packedSignCodes
+    packedSignCodes,
+    e.decimalSigned
   )
 
   override lazy val unparser: DaffodilUnparser = new 
PackedDecimalDelimitedUnparser(
     e.elementRuntimeData,
     e.binaryDecimalVirtualPoint,
-    packedSignCodes
+    packedSignCodes,
+    e.decimalSigned
   )
 }
 
@@ -264,11 +266,15 @@ abstract class BCDDecimalDelimited(e: ElementBase) 
extends StringDelimited(e) {
     textDelimitedParser,
     fieldDFAParseEv,
     isDelimRequired,
-    e.binaryDecimalVirtualPoint
+    e.binaryDecimalVirtualPoint,
+    e.decimalSigned
   )
 
   override lazy val unparser: DaffodilUnparser =
-    new BCDDecimalDelimitedUnparser(e.elementRuntimeData, 
e.binaryDecimalVirtualPoint)
+    new BCDDecimalDelimitedUnparser(
+      e.elementRuntimeData,
+      e.binaryDecimalVirtualPoint
+    )
 }
 
 case class BCDDecimalDelimitedEndOfData(e: ElementBase) extends 
BCDDecimalDelimited(e) {
@@ -301,11 +307,16 @@ abstract class IBM4690PackedDecimalDelimited(e: 
ElementBase) extends StringDelim
     textDelimitedParser,
     fieldDFAParseEv,
     isDelimRequired,
-    e.binaryDecimalVirtualPoint
+    e.binaryDecimalVirtualPoint,
+    e.decimalSigned
   )
 
   override lazy val unparser: DaffodilUnparser =
-    new IBM4690PackedDecimalDelimitedUnparser(e.elementRuntimeData, 
e.binaryDecimalVirtualPoint)
+    new IBM4690PackedDecimalDelimitedUnparser(
+      e.elementRuntimeData,
+      e.binaryDecimalVirtualPoint,
+      e.decimalSigned
+    )
 }
 
 case class IBM4690PackedDecimalDelimitedEndOfData(e: ElementBase)
diff --git 
a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesPacked.scala
 
b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesPacked.scala
index 109abfef9..f5c81be1f 100644
--- 
a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesPacked.scala
+++ 
b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesPacked.scala
@@ -91,7 +91,8 @@ class PackedDecimalRuntimeLength(val e: ElementBase, 
packedSignCodes: PackedSign
     e.binaryDecimalVirtualPoint,
     packedSignCodes,
     e.lengthEv,
-    e.lengthUnits
+    e.lengthUnits,
+    e.decimalSigned
   )
 
   override lazy val unparser: Unparser = new 
PackedDecimalRuntimeLengthUnparser(
@@ -99,7 +100,8 @@ class PackedDecimalRuntimeLength(val e: ElementBase, 
packedSignCodes: PackedSign
     e.binaryDecimalVirtualPoint,
     packedSignCodes,
     e.lengthEv,
-    e.lengthUnits
+    e.lengthUnits,
+    e.decimalSigned
   )
 
 }
@@ -113,14 +115,16 @@ class PackedDecimalKnownLength(
     e.elementRuntimeData,
     e.binaryDecimalVirtualPoint,
     packedSignCodes,
-    lengthInBits.toInt
+    lengthInBits.toInt,
+    e.decimalSigned
   )
 
   override lazy val unparser: Unparser = new PackedDecimalKnownLengthUnparser(
     e.elementRuntimeData,
     e.binaryDecimalVirtualPoint,
     packedSignCodes,
-    lengthInBits.toInt
+    lengthInBits.toInt,
+    e.decimalSigned
   )
 }
 
@@ -130,12 +134,14 @@ class PackedDecimalPrefixedLength(val e: ElementBase, 
packedSignCodes: PackedSig
   override lazy val parser = new PackedDecimalBitLimitLengthParser(
     e.elementRuntimeData,
     e.binaryDecimalVirtualPoint,
-    packedSignCodes
+    packedSignCodes,
+    e.decimalSigned
   )
 
   override lazy val unparser: Unparser = new 
PackedDecimalMinimumLengthUnparser(
     e.elementRuntimeData,
     e.binaryDecimalVirtualPoint,
-    packedSignCodes
+    packedSignCodes,
+    e.decimalSigned
   )
 }
diff --git 
a/daffodil-core/src/main/scala/org/apache/daffodil/runtime1/processors/BCDParsers.scala
 
b/daffodil-core/src/main/scala/org/apache/daffodil/runtime1/processors/BCDParsers.scala
index e1aee9bc2..36fc5dded 100644
--- 
a/daffodil-core/src/main/scala/org/apache/daffodil/runtime1/processors/BCDParsers.scala
+++ 
b/daffodil-core/src/main/scala/org/apache/daffodil/runtime1/processors/BCDParsers.scala
@@ -29,7 +29,7 @@ class BCDDecimalKnownLengthParser(
   e: ElementRuntimeData,
   binaryDecimalVirtualPoint: Int,
   val lengthInBits: Int
-) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint)
+) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint, None)
   with HasKnownLengthInBits {
 
   override def toNumber(num: Array[Byte]): JBigDecimal =
@@ -42,7 +42,7 @@ class BCDDecimalRuntimeLengthParser(
   binaryDecimalVirtualPoint: Int,
   val lengthEv: Evaluatable[JLong],
   val lengthUnits: LengthUnits
-) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint)
+) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint, None)
   with HasRuntimeExplicitLength {
 
   override def toNumber(num: Array[Byte]): JBigDecimal =
@@ -53,7 +53,7 @@ class BCDDecimalRuntimeLengthParser(
 class BCDDecimalBitLimitLengthParser(
   e: ElementRuntimeData,
   binaryDecimalVirtualPoint: Int
-) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint)
+) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint, None)
   with BitLengthFromBitLimitMixin {
 
   override def toNumber(num: Array[Byte]): JBigDecimal =
diff --git 
a/daffodil-core/src/main/scala/org/apache/daffodil/runtime1/processors/IBM4690PackedDecimalParsers.scala
 
b/daffodil-core/src/main/scala/org/apache/daffodil/runtime1/processors/IBM4690PackedDecimalParsers.scala
index 85643178a..6ea612a57 100644
--- 
a/daffodil-core/src/main/scala/org/apache/daffodil/runtime1/processors/IBM4690PackedDecimalParsers.scala
+++ 
b/daffodil-core/src/main/scala/org/apache/daffodil/runtime1/processors/IBM4690PackedDecimalParsers.scala
@@ -21,6 +21,7 @@ import java.lang.Long as JLong
 import java.math.{ BigDecimal as JBigDecimal, BigInteger as JBigInteger }
 
 import org.apache.daffodil.lib.schema.annotation.props.gen.LengthUnits
+import org.apache.daffodil.lib.schema.annotation.props.gen.YesNo
 import org.apache.daffodil.lib.util.DecimalUtils
 import org.apache.daffodil.runtime1.processors.ElementRuntimeData
 import org.apache.daffodil.runtime1.processors.Evaluatable
@@ -28,8 +29,9 @@ import org.apache.daffodil.runtime1.processors.Evaluatable
 class IBM4690PackedDecimalKnownLengthParser(
   e: ElementRuntimeData,
   binaryDecimalVirtualPoint: Int,
-  val lengthInBits: Int
-) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint)
+  val lengthInBits: Int,
+  decimalSigned: YesNo
+) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint, 
Some(decimalSigned))
   with HasKnownLengthInBits {
 
   override def toNumber(num: Array[Byte]): JBigDecimal =
@@ -41,8 +43,9 @@ class IBM4690PackedDecimalRuntimeLengthParser(
   val e: ElementRuntimeData,
   binaryDecimalVirtualPoint: Int,
   val lengthEv: Evaluatable[JLong],
-  val lengthUnits: LengthUnits
-) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint)
+  val lengthUnits: LengthUnits,
+  decimalSigned: YesNo
+) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint, 
Some(decimalSigned))
   with HasRuntimeExplicitLength {
 
   override def toNumber(num: Array[Byte]): JBigDecimal =
@@ -52,8 +55,9 @@ class IBM4690PackedDecimalRuntimeLengthParser(
 
 class IBM4690PackedDecimalBitLimitLengthParser(
   e: ElementRuntimeData,
-  binaryDecimalVirtualPoint: Int
-) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint)
+  binaryDecimalVirtualPoint: Int,
+  decimalSigned: YesNo
+) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint, 
Some(decimalSigned))
   with BitLengthFromBitLimitMixin {
 
   override def toNumber(num: Array[Byte]): JBigDecimal =
diff --git 
a/daffodil-core/src/main/scala/org/apache/daffodil/runtime1/processors/PackedBinaryTraits.scala
 
b/daffodil-core/src/main/scala/org/apache/daffodil/runtime1/processors/PackedBinaryTraits.scala
index e26116015..cc05f382d 100644
--- 
a/daffodil-core/src/main/scala/org/apache/daffodil/runtime1/processors/PackedBinaryTraits.scala
+++ 
b/daffodil-core/src/main/scala/org/apache/daffodil/runtime1/processors/PackedBinaryTraits.scala
@@ -24,6 +24,7 @@ import java.nio.charset.StandardCharsets
 import org.apache.daffodil.io.processors.charset.StandardBitsCharsets
 import org.apache.daffodil.lib.equality.TypeEqual
 import org.apache.daffodil.lib.exceptions.Assert
+import org.apache.daffodil.lib.schema.annotation.props.gen.YesNo
 import org.apache.daffodil.lib.util.Maybe
 import org.apache.daffodil.lib.util.MaybeChar
 import org.apache.daffodil.runtime1.dpath.InvalidPrimitiveDataException
@@ -87,7 +88,8 @@ trait PackedBinaryLengthCheck {
 
 abstract class PackedBinaryDecimalBaseParser(
   override val context: ElementRuntimeData,
-  binaryDecimalVirtualPoint: Int
+  binaryDecimalVirtualPoint: Int,
+  optDecimalSigned: Option[YesNo]
 ) extends PrimParser
   with PackedBinaryConversion[JBigDecimal]
   with PackedBinaryLengthCheck {
@@ -111,6 +113,17 @@ abstract class PackedBinaryDecimalBaseParser(
 
     try {
       val dec = toPrimType(context, dis.getByteArray(nBits, start))
+      if (
+        dec.getBigDecimal
+          .signum() == -1 && optDecimalSigned.isDefined && 
optDecimalSigned.get == YesNo.No
+      ) {
+        PE(
+          start,
+          "Packed binary decimal value is negative (%s), but property 
dfdl:decimalSigned is no.",
+          dec.value.toString
+        )
+        return
+      }
       start.simpleElement.setDataValue(dec)
     } catch {
       case n: NumberFormatException => PE(start, "Error in packed data: \n%s", 
n.getMessage())
@@ -207,7 +220,8 @@ abstract class PackedBinaryDecimalDelimitedBaseParser(
   textParser: TextDelimitedParserBase,
   fieldDFAEv: FieldDFAParseEv,
   isDelimRequired: Boolean,
-  binaryDecimalVirtualPoint: Int
+  binaryDecimalVirtualPoint: Int,
+  decimalSigned: YesNo
 ) extends StringDelimitedParser(
     e,
     TextJustificationType.None,
@@ -248,6 +262,14 @@ abstract class PackedBinaryDecimalDelimitedBaseParser(
       } else {
         try {
           val num = toPrimType(e, fieldBytes)
+          if (num.getBigDecimal.signum() == -1 && decimalSigned == YesNo.No) {
+            PE(
+              state,
+              "Packed binary decimal value is negative (%s), but property 
dfdl:decimalSigned is no.",
+              num.value.toString
+            )
+            return
+          }
           state.simpleElement.setDataValue(num)
         } catch {
           case n: NumberFormatException =>
diff --git 
a/daffodil-core/src/main/scala/org/apache/daffodil/runtime1/processors/PackedDecimalParsers.scala
 
b/daffodil-core/src/main/scala/org/apache/daffodil/runtime1/processors/PackedDecimalParsers.scala
index 1525f95ec..46fc6c091 100644
--- 
a/daffodil-core/src/main/scala/org/apache/daffodil/runtime1/processors/PackedDecimalParsers.scala
+++ 
b/daffodil-core/src/main/scala/org/apache/daffodil/runtime1/processors/PackedDecimalParsers.scala
@@ -21,6 +21,7 @@ import java.lang.Long as JLong
 import java.math.{ BigDecimal as JBigDecimal, BigInteger as JBigInteger }
 
 import org.apache.daffodil.lib.schema.annotation.props.gen.LengthUnits
+import org.apache.daffodil.lib.schema.annotation.props.gen.YesNo
 import org.apache.daffodil.lib.util.{ DecimalUtils, PackedSignCodes }
 import org.apache.daffodil.runtime1.processors.ElementRuntimeData
 import org.apache.daffodil.runtime1.processors.Evaluatable
@@ -29,8 +30,9 @@ class PackedDecimalKnownLengthParser(
   e: ElementRuntimeData,
   binaryDecimalVirtualPoint: Int,
   packedSignCodes: PackedSignCodes,
-  val lengthInBits: Int
-) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint)
+  val lengthInBits: Int,
+  decimalSigned: YesNo
+) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint, 
Some(decimalSigned))
   with HasKnownLengthInBits {
 
   override def toNumber(num: Array[Byte]): JBigDecimal =
@@ -43,8 +45,9 @@ class PackedDecimalRuntimeLengthParser(
   binaryDecimalVirtualPoint: Int,
   packedSignCodes: PackedSignCodes,
   val lengthEv: Evaluatable[JLong],
-  val lengthUnits: LengthUnits
-) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint)
+  val lengthUnits: LengthUnits,
+  decimalSigned: YesNo
+) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint, 
Some(decimalSigned))
   with HasRuntimeExplicitLength {
 
   override def toNumber(num: Array[Byte]): JBigDecimal =
@@ -54,8 +57,9 @@ class PackedDecimalRuntimeLengthParser(
 class PackedDecimalBitLimitLengthParser(
   e: ElementRuntimeData,
   binaryDecimalVirtualPoint: Int,
-  packedSignCodes: PackedSignCodes
-) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint)
+  packedSignCodes: PackedSignCodes,
+  decimalSigned: YesNo
+) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint, 
Some(decimalSigned))
   with BitLengthFromBitLimitMixin {
 
   override def toNumber(num: Array[Byte]): JBigDecimal =
diff --git 
a/daffodil-core/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/DelimitedParsers.scala
 
b/daffodil-core/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/DelimitedParsers.scala
index 73ec3d8d8..6d3c739f4 100644
--- 
a/daffodil-core/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/DelimitedParsers.scala
+++ 
b/daffodil-core/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/DelimitedParsers.scala
@@ -19,6 +19,7 @@ package org.apache.daffodil.runtime1.processors.parsers
 
 import org.apache.daffodil.lib.equality.*
 import org.apache.daffodil.lib.exceptions.Assert
+import org.apache.daffodil.lib.schema.annotation.props.gen.YesNo
 import org.apache.daffodil.lib.util.Maybe
 import org.apache.daffodil.lib.util.PackedSignCodes
 import org.apache.daffodil.runtime1.processors.ElementRuntimeData
@@ -226,13 +227,15 @@ class PackedDecimalDelimitedParser(
   fieldDFAEv: FieldDFAParseEv,
   isDelimRequired: Boolean,
   binaryDecimalVirtualPoint: Int,
-  packedSignCodes: PackedSignCodes
+  packedSignCodes: PackedSignCodes,
+  decimalSigned: YesNo
 ) extends PackedBinaryDecimalDelimitedBaseParser(
     erd,
     textParser,
     fieldDFAEv,
     isDelimRequired,
-    binaryDecimalVirtualPoint
+    binaryDecimalVirtualPoint,
+    decimalSigned
   ) {
 
   override def toNumber(num: Array[Byte]): JBigDecimal =
@@ -256,13 +259,15 @@ class BCDDecimalDelimitedParser(
   textParser: TextDelimitedParserBase,
   fieldDFAEv: FieldDFAParseEv,
   isDelimRequired: Boolean,
-  binaryDecimalVirtualPoint: Int
+  binaryDecimalVirtualPoint: Int,
+  decimalSigned: YesNo
 ) extends PackedBinaryDecimalDelimitedBaseParser(
     erd,
     textParser,
     fieldDFAEv,
     isDelimRequired,
-    binaryDecimalVirtualPoint
+    binaryDecimalVirtualPoint,
+    decimalSigned
   ) {
 
   override def toNumber(num: Array[Byte]): JBigDecimal =
@@ -287,13 +292,15 @@ class IBM4690PackedDecimalDelimitedParser(
   textParser: TextDelimitedParserBase,
   fieldDFAEv: FieldDFAParseEv,
   isDelimRequired: Boolean,
-  binaryDecimalVirtualPoint: Int
+  binaryDecimalVirtualPoint: Int,
+  decimalSigned: YesNo
 ) extends PackedBinaryDecimalDelimitedBaseParser(
     erd,
     textParser,
     fieldDFAEv,
     isDelimRequired,
-    binaryDecimalVirtualPoint
+    binaryDecimalVirtualPoint,
+    decimalSigned
   ) {
 
   override def toNumber(num: Array[Byte]): JBigDecimal =
diff --git 
a/daffodil-core/src/main/scala/org/apache/daffodil/unparsers/runtime1/BCDUnparsers.scala
 
b/daffodil-core/src/main/scala/org/apache/daffodil/unparsers/runtime1/BCDUnparsers.scala
index 571ec4dc3..0c47178d0 100644
--- 
a/daffodil-core/src/main/scala/org/apache/daffodil/unparsers/runtime1/BCDUnparsers.scala
+++ 
b/daffodil-core/src/main/scala/org/apache/daffodil/unparsers/runtime1/BCDUnparsers.scala
@@ -70,7 +70,7 @@ final class BCDIntegerMinimumLengthUnparser(e: 
ElementRuntimeData)
 }
 
 abstract class BCDDecimalBaseUnparser(e: ElementRuntimeData, 
binaryDecimalVirtualPoint: Int)
-  extends PackedBinaryDecimalBaseUnparser(e, binaryDecimalVirtualPoint) {
+  extends PackedBinaryDecimalBaseUnparser(e, binaryDecimalVirtualPoint, None) {
 
   override def fromBigInteger(bigInt: JBigInteger, nBits: Int): Array[Byte] =
     DecimalUtils.bcdFromBigInteger(bigInt, nBits)
diff --git 
a/daffodil-core/src/main/scala/org/apache/daffodil/unparsers/runtime1/BinaryNumberUnparsers.scala
 
b/daffodil-core/src/main/scala/org/apache/daffodil/unparsers/runtime1/BinaryNumberUnparsers.scala
index e1ac99fdc..6b8a1708c 100644
--- 
a/daffodil-core/src/main/scala/org/apache/daffodil/unparsers/runtime1/BinaryNumberUnparsers.scala
+++ 
b/daffodil-core/src/main/scala/org/apache/daffodil/unparsers/runtime1/BinaryNumberUnparsers.scala
@@ -261,6 +261,15 @@ abstract class BinaryDecimalUnparserBase(
     val isSigned: Boolean = signed == Yes
     val minWidth: Int = if (isSigned) 2 else 1
     checkMinWidth(state, isSigned, nBits, minWidth)
-    dos.putBigInt(asBigInt(value), nBits, isSigned, finfo)
+    val bigInt = asBigInt(value)
+    if (!isSigned && bigInt.signum() == -1) {
+      UnparseError(
+        One(state.schemaFileLocation),
+        One(state.currentLocation),
+        "Binary decimal value is negative (%s), but property 
dfdl:decimalSigned is no",
+        bigInt.toString
+      )
+    }
+    dos.putBigInt(bigInt, nBits, isSigned, finfo)
   }
 }
diff --git 
a/daffodil-core/src/main/scala/org/apache/daffodil/unparsers/runtime1/IBM4690PackedDecimalUnparsers.scala
 
b/daffodil-core/src/main/scala/org/apache/daffodil/unparsers/runtime1/IBM4690PackedDecimalUnparsers.scala
index f0f4b8897..9f732208d 100644
--- 
a/daffodil-core/src/main/scala/org/apache/daffodil/unparsers/runtime1/IBM4690PackedDecimalUnparsers.scala
+++ 
b/daffodil-core/src/main/scala/org/apache/daffodil/unparsers/runtime1/IBM4690PackedDecimalUnparsers.scala
@@ -21,6 +21,7 @@ import java.lang.Long as JLong
 import java.math.BigInteger as JBigInteger
 
 import org.apache.daffodil.lib.schema.annotation.props.gen.LengthUnits
+import org.apache.daffodil.lib.schema.annotation.props.gen.YesNo
 import org.apache.daffodil.lib.util.DecimalUtils
 import org.apache.daffodil.runtime1.processors.ElementRuntimeData
 import org.apache.daffodil.runtime1.processors.Evaluatable
@@ -75,8 +76,9 @@ final class IBM4690PackedIntegerMinimumLengthUnparser(e: 
ElementRuntimeData)
 
 abstract class IBM4690PackedDecimalBaseUnparser(
   e: ElementRuntimeData,
-  binaryDecimalVirtualPoint: Int
-) extends PackedBinaryDecimalBaseUnparser(e, binaryDecimalVirtualPoint) {
+  binaryDecimalVirtualPoint: Int,
+  decimalSigned: YesNo
+) extends PackedBinaryDecimalBaseUnparser(e, binaryDecimalVirtualPoint, 
Some(decimalSigned)) {
 
   override def fromBigInteger(bigInt: JBigInteger, nBits: Int): Array[Byte] =
     DecimalUtils.ibm4690FromBigInteger(bigInt, nBits)
@@ -85,16 +87,18 @@ abstract class IBM4690PackedDecimalBaseUnparser(
 class IBM4690PackedDecimalKnownLengthUnparser(
   e: ElementRuntimeData,
   binaryDecimalVirtualPoint: Int,
-  override val lengthInBits: Int
-) extends IBM4690PackedDecimalBaseUnparser(e, binaryDecimalVirtualPoint)
+  override val lengthInBits: Int,
+  decimalSigned: YesNo
+) extends IBM4690PackedDecimalBaseUnparser(e, binaryDecimalVirtualPoint, 
decimalSigned)
   with HasKnownLengthInBits {}
 
 class IBM4690PackedDecimalRuntimeLengthUnparser(
   val e: ElementRuntimeData,
   binaryDecimalVirtualPoint: Int,
   val lengthEv: Evaluatable[JLong],
-  val lengthUnits: LengthUnits
-) extends IBM4690PackedDecimalBaseUnparser(e, binaryDecimalVirtualPoint)
+  val lengthUnits: LengthUnits,
+  decimalSigned: YesNo
+) extends IBM4690PackedDecimalBaseUnparser(e, binaryDecimalVirtualPoint, 
decimalSigned)
   with HasRuntimeExplicitLength {
 
   override def runtimeDependencies = Vector(lengthEv)
@@ -102,16 +106,18 @@ class IBM4690PackedDecimalRuntimeLengthUnparser(
 
 final class IBM4690PackedDecimalDelimitedUnparser(
   e: ElementRuntimeData,
-  binaryDecimalVirtualPoint: Int
-) extends IBM4690PackedDecimalBaseUnparser(e, binaryDecimalVirtualPoint) {
+  binaryDecimalVirtualPoint: Int,
+  decimalSigned: YesNo
+) extends IBM4690PackedDecimalBaseUnparser(e, binaryDecimalVirtualPoint, 
decimalSigned) {
 
   override def getBitLength(state: ParseOrUnparseState): Int = { 0 }
 }
 
 final class IBM4690PackedDecimalMinimumLengthUnparser(
   e: ElementRuntimeData,
-  binaryDecimalVirtualPoint: Int
-) extends IBM4690PackedDecimalBaseUnparser(e, binaryDecimalVirtualPoint) {
+  binaryDecimalVirtualPoint: Int,
+  decimalSigned: YesNo
+) extends IBM4690PackedDecimalBaseUnparser(e, binaryDecimalVirtualPoint, 
decimalSigned) {
 
   override def runtimeDependencies = Vector()
 
diff --git 
a/daffodil-core/src/main/scala/org/apache/daffodil/unparsers/runtime1/PackedBinaryUnparserTraits.scala
 
b/daffodil-core/src/main/scala/org/apache/daffodil/unparsers/runtime1/PackedBinaryUnparserTraits.scala
index c7b0463d3..7c53bc172 100644
--- 
a/daffodil-core/src/main/scala/org/apache/daffodil/unparsers/runtime1/PackedBinaryUnparserTraits.scala
+++ 
b/daffodil-core/src/main/scala/org/apache/daffodil/unparsers/runtime1/PackedBinaryUnparserTraits.scala
@@ -24,6 +24,7 @@ import java.math.BigInteger as JBigInteger
 import org.apache.daffodil.io.DataOutputStream
 import org.apache.daffodil.io.FormatInfo
 import org.apache.daffodil.lib.exceptions.Assert
+import org.apache.daffodil.lib.schema.annotation.props.gen.YesNo
 import org.apache.daffodil.lib.util.Maybe.*
 import org.apache.daffodil.runtime1.dpath.NodeInfo
 import 
org.apache.daffodil.runtime1.infoset.DataValue.DataValuePrimitiveNullable
@@ -87,7 +88,8 @@ abstract class PackedBinaryBaseUnparser(override val context: 
ElementRuntimeData
 
 abstract class PackedBinaryDecimalBaseUnparser(
   e: ElementRuntimeData,
-  binaryDecimalVirtualPoint: Int
+  binaryDecimalVirtualPoint: Int,
+  decimalSigned: Option[YesNo]
 ) extends PackedBinaryBaseUnparser(e) {
 
   override def getNumberToPut(ustate: UState): JNumber = {
@@ -100,6 +102,23 @@ abstract class PackedBinaryDecimalBaseUnparser(
         binaryDecimalVirtualPoint
       )
     }
+    if (bigDec.signum == -1 && decimalSigned.isEmpty) {
+      UnparseError(
+        One(e.schemaFileLocation),
+        Nope,
+        "Signed numbers with dfdl:binaryNumberRep 'bcd' are always only 
positive. %s cannot be negative, but value was %s",
+        context.dpathElementCompileInfo.namedQName.toPrettyString,
+        bigDec.toString
+      )
+    }
+    if (bigDec.signum() == -1 && decimalSigned.isDefined && decimalSigned.get 
== YesNo.No) {
+      UnparseError(
+        One(e.schemaFileLocation),
+        Nope,
+        "Packed binary decimal value is negative (%s), but property 
dfdl:decimalSigned is no",
+        bigDec.toString
+      )
+    }
     bigDec.unscaledValue
   }
 
diff --git 
a/daffodil-core/src/main/scala/org/apache/daffodil/unparsers/runtime1/PackedDecimalUnparsers.scala
 
b/daffodil-core/src/main/scala/org/apache/daffodil/unparsers/runtime1/PackedDecimalUnparsers.scala
index 137d8dff3..3feb90cb9 100644
--- 
a/daffodil-core/src/main/scala/org/apache/daffodil/unparsers/runtime1/PackedDecimalUnparsers.scala
+++ 
b/daffodil-core/src/main/scala/org/apache/daffodil/unparsers/runtime1/PackedDecimalUnparsers.scala
@@ -21,6 +21,7 @@ import java.lang.Long as JLong
 import java.math.BigInteger as JBigInteger
 
 import org.apache.daffodil.lib.schema.annotation.props.gen.LengthUnits
+import org.apache.daffodil.lib.schema.annotation.props.gen.YesNo
 import org.apache.daffodil.lib.util.DecimalUtils
 import org.apache.daffodil.lib.util.PackedSignCodes
 import org.apache.daffodil.runtime1.processors.ElementRuntimeData
@@ -83,8 +84,9 @@ final class PackedIntegerMinimumLengthUnparser(
 abstract class PackedDecimalBaseUnparser(
   e: ElementRuntimeData,
   binaryDecimalVirtualPoint: Int,
-  packedSignCodes: PackedSignCodes
-) extends PackedBinaryDecimalBaseUnparser(e, binaryDecimalVirtualPoint) {
+  packedSignCodes: PackedSignCodes,
+  decimalSigned: YesNo
+) extends PackedBinaryDecimalBaseUnparser(e, binaryDecimalVirtualPoint, 
Some(decimalSigned)) {
 
   override def fromBigInteger(bigInt: JBigInteger, nBits: Int): Array[Byte] =
     DecimalUtils.packedFromBigInteger(bigInt, nBits, packedSignCodes)
@@ -94,8 +96,14 @@ class PackedDecimalKnownLengthUnparser(
   e: ElementRuntimeData,
   binaryDecimalVirtualPoint: Int,
   packedSignCodes: PackedSignCodes,
-  override val lengthInBits: Int
-) extends PackedDecimalBaseUnparser(e, binaryDecimalVirtualPoint, 
packedSignCodes)
+  override val lengthInBits: Int,
+  decimalSigned: YesNo
+) extends PackedDecimalBaseUnparser(
+    e,
+    binaryDecimalVirtualPoint,
+    packedSignCodes,
+    decimalSigned
+  )
   with HasKnownLengthInBits {}
 
 class PackedDecimalRuntimeLengthUnparser(
@@ -103,8 +111,14 @@ class PackedDecimalRuntimeLengthUnparser(
   binaryDecimalVirtualPoint: Int,
   packedSignCodes: PackedSignCodes,
   val lengthEv: Evaluatable[JLong],
-  val lengthUnits: LengthUnits
-) extends PackedDecimalBaseUnparser(e, binaryDecimalVirtualPoint, 
packedSignCodes)
+  val lengthUnits: LengthUnits,
+  decimalSigned: YesNo
+) extends PackedDecimalBaseUnparser(
+    e,
+    binaryDecimalVirtualPoint,
+    packedSignCodes,
+    decimalSigned
+  )
   with HasRuntimeExplicitLength {
 
   override def runtimeDependencies = Vector(lengthEv)
@@ -113,8 +127,14 @@ class PackedDecimalRuntimeLengthUnparser(
 final class PackedDecimalDelimitedUnparser(
   e: ElementRuntimeData,
   binaryDecimalVirtualPoint: Int,
-  packedSignCodes: PackedSignCodes
-) extends PackedDecimalBaseUnparser(e, binaryDecimalVirtualPoint, 
packedSignCodes) {
+  packedSignCodes: PackedSignCodes,
+  decimalSigned: YesNo
+) extends PackedDecimalBaseUnparser(
+    e,
+    binaryDecimalVirtualPoint,
+    packedSignCodes,
+    decimalSigned
+  ) {
 
   override def getBitLength(state: ParseOrUnparseState): Int = { 0 }
 }
@@ -122,8 +142,14 @@ final class PackedDecimalDelimitedUnparser(
 final class PackedDecimalMinimumLengthUnparser(
   e: ElementRuntimeData,
   binaryDecimalVirtualPoint: Int,
-  packedSignCodes: PackedSignCodes
-) extends PackedDecimalBaseUnparser(e, binaryDecimalVirtualPoint, 
packedSignCodes) {
+  packedSignCodes: PackedSignCodes,
+  decimalSigned: YesNo
+) extends PackedDecimalBaseUnparser(
+    e,
+    binaryDecimalVirtualPoint,
+    packedSignCodes,
+    decimalSigned
+  ) {
 
   override def runtimeDependencies = Vector()
 
diff --git 
a/daffodil-test/src/test/resources/org/apache/daffodil/section13/decimal/TestDecimalSigned.tdml
 
b/daffodil-test/src/test/resources/org/apache/daffodil/section13/decimal/TestDecimalSigned.tdml
index 2c077e397..cdd3d1223 100644
--- 
a/daffodil-test/src/test/resources/org/apache/daffodil/section13/decimal/TestDecimalSigned.tdml
+++ 
b/daffodil-test/src/test/resources/org/apache/daffodil/section13/decimal/TestDecimalSigned.tdml
@@ -46,6 +46,9 @@
 
     <element name="r4" type="xs:decimal" dfdl:decimalSigned="no" 
dfdl:length="2" dfdl:binaryNumberRep="ibm4690Packed"/>
 
+    <element name="r5" type="xs:decimal" dfdl:decimalSigned="no" 
dfdl:lengthKind="delimited" dfdl:encoding="ISO-8859-1"
+      dfdl:binaryNumberRep="packed" />
+
 
   </tdml:defineSchema>
 
@@ -70,10 +73,13 @@
       </dfdlInfoset>
       <!-- representation of this as 2s complement would be 0xFF85 -->
     </infoset>
-     <errors>
-      <error>Unparse Error</error>
-      <error>unsigned</error>
-    </errors>
+      <errors>
+        <error>Unparse Error</error>
+        <error>Binary</error>
+        <error>negative</error>
+        <error>decimalSigned</error>
+        <error>no</error>
+      </errors>
   </unparserTestCase>
 
   <parserTestCase name="parseTestdecimalSigned_no_bcd" root="r2" model="s"
@@ -94,11 +100,12 @@
         <ex:r2>-1.23</ex:r2>
       </dfdlInfoset>
     </infoset>
-    <!-- This should unparse error. Instead it unparses as D123, where that D 
is a sign digit.
-    This is not allowed in BCD which is unsigned only -->
-    <document>
-      <documentPart type="byte">0123</documentPart><!-- unparses as packed -->
-    </document>
+    <errors>
+      <error>Signed</error>
+      <error>bcd</error>
+      <error>only positive</error>
+      <error>r2 cannot be negative</error>
+    </errors>
   </unparserTestCase>
 
   <parserTestCase name="parseTestDecimalSigned_no_packed" root="r3" model="s"
@@ -110,7 +117,10 @@
     </document>
     <errors>
       <error>Parse Error</error>
-      <error>unsigned</error>
+      <error>Packed binary</error>
+      <error>negative</error>
+      <error>decimalSigned</error>
+      <error>no</error>
     </errors>
   </parserTestCase>
 
@@ -123,7 +133,10 @@
     </infoset>
     <errors>
       <error>Unparse Error</error>
-      <error>unsigned</error>
+      <error>Packed binary</error>
+      <error>negative</error>
+      <error>decimalSigned</error>
+      <error>no</error>
     </errors>
   </unparserTestCase>
 
@@ -136,7 +149,10 @@
     </document>
     <errors>
       <error>Parse Error</error>
-      <error>unsigned</error>
+      <error>Packed binary</error>
+      <error>negative</error>
+      <error>decimalSigned</error>
+      <error>no</error>
     </errors>
   </parserTestCase>
 
@@ -149,9 +165,42 @@
     </infoset>
     <errors>
       <error>Unparse Error</error>
-      <error>unsigned</error>
+      <error>Packed binary</error>
+      <error>negative</error>
+      <error>decimalSigned</error>
+      <error>no</error>
     </errors>
   </unparserTestCase>
 
+    <parserTestCase name="parseTestDecimalSigned_no_packed_delimited" 
root="r5" model="s"
+      description="negative packed representation should fail to parse as 
decimal when decimalSigned='no'">
+    <document>
+      <documentPart type="byte">
+        123D
+      </documentPart>
+    </document>
+    <errors>
+      <error>Parse Error</error>
+      <error>Packed binary</error>
+      <error>negative</error>
+      <error>decimalSigned</error>
+      <error>no</error>
+    </errors>
+  </parserTestCase>
 
+    <unparserTestCase name="unparseTestDecimalSigned_no_packed_delimited" 
model="s"
+      description="negative values cannot unparse as decimal when 
decimalSigned is 'no'" >
+    <infoset>
+      <dfdlInfoset>
+        <ex:r5>-1.23</ex:r5>
+      </dfdlInfoset>
+    </infoset>
+    <errors>
+      <error>Unparse Error</error>
+      <error>Packed binary</error>
+      <error>negative</error>
+      <error>decimalSigned</error>
+      <error>no</error>
+    </errors>
+  </unparserTestCase>
 </testSuite>
diff --git 
a/daffodil-test/src/test/scala/org/apache/daffodil/section13/decimal/TestDecimalSigned.scala
 
b/daffodil-test/src/test/scala/org/apache/daffodil/section13/decimal/TestDecimalSigned.scala
index 69e6417c2..1f2169420 100644
--- 
a/daffodil-test/src/test/scala/org/apache/daffodil/section13/decimal/TestDecimalSigned.scala
+++ 
b/daffodil-test/src/test/scala/org/apache/daffodil/section13/decimal/TestDecimalSigned.scala
@@ -20,7 +20,6 @@ package org.apache.daffodil.section13.decimal
 import org.apache.daffodil.junit.tdml.TdmlSuite
 import org.apache.daffodil.junit.tdml.TdmlTests
 
-import org.junit.Ignore
 import org.junit.Test
 
 object TestDecimalSigned extends TdmlSuite {
@@ -32,13 +31,13 @@ class TestDecimalSigned extends TdmlTests {
 
   @Test def parseTestDecimalSigned_no_binary = test
   @Test def parseTestdecimalSigned_no_bcd = test
+  @Test def unparseTestDecimalSigned_no_binary = test
+  @Test def unparseTestdecimalSigned_no_bcd = test
+  @Test def parseTestDecimalSigned_no_packed = test
+  @Test def unparseTestDecimalSigned_no_packed = test
+  @Test def parseTestDecimalSigned_no_ibm4690Packed = test
+  @Test def unparseTestDecimalSigned_no_ibm4690Packed = test
 
-  // DAFFODIL-2957 - the tests below all failing
-  // Abort with usage error. Should be unparse error.
-  @Ignore @Test def unparseTestDecimalSigned_no_binary = test
-  @Ignore @Test def unparseTestdecimalSigned_no_bcd = test
-  @Ignore @Test def parseTestDecimalSigned_no_packed = test
-  @Ignore @Test def unparseTestDecimalSigned_no_packed = test
-  @Ignore @Test def parseTestDecimalSigned_no_ibm4690Packed = test
-  @Ignore @Test def unparseTestDecimalSigned_no_ibm4690Packed = test
+  @Test def parseTestDecimalSigned_no_packed_delimited = test
+  @Test def unparseTestDecimalSigned_no_packed_delimited = test
 }


Reply via email to