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
}