diff --git a/daffodil-codegen-c/src/main/scala/org/apache/daffodil/codegen/c/DaffodilCCodeGenerator.scala b/daffodil-codegen-c/src/main/scala/org/apache/daffodil/codegen/c/DaffodilCCodeGenerator.scala
index 959d97e337..92348ee819 100644
--- a/daffodil-codegen-c/src/main/scala/org/apache/daffodil/codegen/c/DaffodilCCodeGenerator.scala
+++ b/daffodil-codegen-c/src/main/scala/org/apache/daffodil/codegen/c/DaffodilCCodeGenerator.scala
@@ -278,7 +278,7 @@ object DaffodilCCodeGenerator
case g: BinaryDouble => binaryFloatGenerateCode(g.e, lengthInBits = 64, cgState)
case g: BinaryFloat => binaryFloatGenerateCode(g.e, lengthInBits = 32, cgState)
case g: BinaryIntegerKnownLength =>
- binaryIntegerKnownLengthGenerateCode(g.e, g.lengthInBits, g.signed, cgState)
+ binaryIntegerKnownLengthGenerateCode(g.e, g.lengthInBits, cgState)
case g: CaptureContentLengthEnd => noop(g)
case g: CaptureContentLengthStart => noop(g)
case g: CaptureValueLengthEnd => noop(g)
diff --git a/daffodil-codegen-c/src/main/scala/org/apache/daffodil/codegen/c/generators/BinaryIntegerKnownLengthCodeGenerator.scala b/daffodil-codegen-c/src/main/scala/org/apache/daffodil/codegen/c/generators/BinaryIntegerKnownLengthCodeGenerator.scala
index 4a835c9ac4..1d2476cb3d 100644
--- a/daffodil-codegen-c/src/main/scala/org/apache/daffodil/codegen/c/generators/BinaryIntegerKnownLengthCodeGenerator.scala
+++ b/daffodil-codegen-c/src/main/scala/org/apache/daffodil/codegen/c/generators/BinaryIntegerKnownLengthCodeGenerator.scala
@@ -18,6 +18,7 @@
package org.apache.daffodil.codegen.c.generators
import org.apache.daffodil.core.dsom.ElementBase
+import org.apache.daffodil.runtime1.dpath.NodeInfo.PrimType.PrimNumeric
trait BinaryIntegerKnownLengthCodeGenerator extends BinaryValueCodeGenerator {
@@ -25,7 +26,6 @@ trait BinaryIntegerKnownLengthCodeGenerator extends BinaryValueCodeGenerator {
def binaryIntegerKnownLengthGenerateCode(
e: ElementBase,
lengthInBits: Long,
- signed: Boolean,
cgState: CodeGeneratorState
): Unit = {
val cLengthInBits = lengthInBits match {
@@ -35,6 +35,7 @@ trait BinaryIntegerKnownLengthCodeGenerator extends BinaryValueCodeGenerator {
case n if n <= 64 => 64
case _ => e.SDE("Binary integer lengths longer than 64 bits are not supported.")
}
+ val signed = e.primType.asInstanceOf[PrimNumeric].isSigned
val primType = if (signed) s"int$cLengthInBits" else s"uint$cLengthInBits"
val addField = valueAddField(e, lengthInBits, primType, _, cgState)
val validateFixed = valueValidateFixed(e, _, cgState)
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 3992415bcd..825f69da83 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
@@ -774,11 +774,37 @@ trait ElementBase
if (
result.isDefined && repElement.isSimpleType && representation == Representation.Binary
) {
+ val nBits = result.get
primType match {
case primNumeric: NodeInfo.PrimType.PrimNumeric =>
- if (primNumeric.width.isDefined) {
- val nBits = result.get
- val width = primNumeric.width.get
+ if (primNumeric.minWidth.isDefined) {
+ val minWidth = primNumeric.minWidth.get
+ if (nBits < minWidth) {
+ val isSigned = primNumeric.isSigned
+ val signedStr = if (isSigned) "a signed" else "an unsigned"
+ val outOfRangeFmtStr =
+ "Minimum length for %s binary integer is %d bit(s), number of bits %d out of range. " +
+ "An unsigned integer with length 1 bit could be used instead."
+ if (isSigned && tunable.allowSignedIntegerLength1Bit && nBits == 1) {
+ SDW(
+ WarnID.SignedBinaryIntegerLength1Bit,
+ outOfRangeFmtStr,
+ signedStr,
+ minWidth,
+ nBits
+ )
+ } else {
+ SDE(
+ outOfRangeFmtStr,
+ signedStr,
+ minWidth,
+ nBits
+ )
+ }
+ }
+ }
+ if (primNumeric.maxWidth.isDefined) {
+ val width = primNumeric.maxWidth.get
if (nBits > width) {
SDE(
"Number of bits %d out of range for binary %s, must be between 1 and %d bits.",
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/ElementBaseGrammarMixin.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/ElementBaseGrammarMixin.scala
index f9982d71a4..12b53c352a 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/ElementBaseGrammarMixin.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/ElementBaseGrammarMixin.scala
@@ -786,7 +786,7 @@ trait ElementBaseGrammarMixin
) {
ConvertZonedCombinator(
this,
- new IBM4690PackedIntegerKnownLength(this, false, binaryNumberKnownLengthInBits),
+ new IBM4690PackedIntegerKnownLength(this, binaryNumberKnownLengthInBits),
textConverter
)
}
@@ -796,7 +796,7 @@ trait ElementBaseGrammarMixin
) {
ConvertZonedCombinator(
this,
- new IBM4690PackedIntegerRuntimeLength(this, false),
+ new IBM4690PackedIntegerRuntimeLength(this),
textConverter
)
}
@@ -806,7 +806,7 @@ trait ElementBaseGrammarMixin
) {
ConvertZonedCombinator(
this,
- new IBM4690PackedIntegerDelimitedEndOfData(this, false),
+ new IBM4690PackedIntegerDelimitedEndOfData(this),
textConverter
)
}
@@ -816,7 +816,7 @@ trait ElementBaseGrammarMixin
) {
ConvertZonedCombinator(
this,
- new IBM4690PackedIntegerPrefixedLength(this, false),
+ new IBM4690PackedIntegerPrefixedLength(this),
textConverter
)
}
@@ -827,7 +827,6 @@ trait ElementBaseGrammarMixin
this,
new PackedIntegerKnownLength(
this,
- false,
packedSignCodes,
binaryNumberKnownLengthInBits
),
@@ -838,7 +837,7 @@ trait ElementBaseGrammarMixin
prod("packedRuntimeLengthCalendar", binaryCalendarRep == BinaryCalendarRep.Packed) {
ConvertZonedCombinator(
this,
- new PackedIntegerRuntimeLength(this, false, packedSignCodes),
+ new PackedIntegerRuntimeLength(this, packedSignCodes),
textConverter
)
}
@@ -846,7 +845,7 @@ trait ElementBaseGrammarMixin
prod("packedDelimitedLengthCalendar", binaryCalendarRep == BinaryCalendarRep.Packed) {
ConvertZonedCombinator(
this,
- new PackedIntegerDelimitedEndOfData(this, false, packedSignCodes),
+ new PackedIntegerDelimitedEndOfData(this, packedSignCodes),
textConverter
)
}
@@ -854,7 +853,7 @@ trait ElementBaseGrammarMixin
prod("packedPrefixedLengthCalendar", binaryCalendarRep == BinaryCalendarRep.Packed) {
ConvertZonedCombinator(
this,
- new PackedIntegerPrefixedLength(this, false, packedSignCodes),
+ new PackedIntegerPrefixedLength(this, packedSignCodes),
textConverter
)
}
@@ -897,7 +896,7 @@ trait ElementBaseGrammarMixin
private lazy val packedSignCodes =
PackedSignCodes(binaryPackedSignCodes, binaryNumberCheckPolicy)
- private def binaryIntegerValue(isSigned: Boolean) = {
+ private lazy val binaryIntegerValue = {
//
// Is it a single byte or smaller
//
@@ -910,10 +909,10 @@ trait ElementBaseGrammarMixin
}
(binaryNumberRep, lengthKind, binaryNumberKnownLengthInBits) match {
case (BinaryNumberRep.Binary, LengthKind.Prefixed, _) =>
- new BinaryIntegerPrefixedLength(this, isSigned)
- case (BinaryNumberRep.Binary, _, -1) => new BinaryIntegerRuntimeLength(this, isSigned)
+ new BinaryIntegerPrefixedLength(this)
+ case (BinaryNumberRep.Binary, _, -1) => new BinaryIntegerRuntimeLength(this)
case (BinaryNumberRep.Binary, _, _) =>
- new BinaryIntegerKnownLength(this, isSigned, binaryNumberKnownLengthInBits)
+ new BinaryIntegerKnownLength(this, binaryNumberKnownLengthInBits)
case (_, LengthKind.Implicit, _) =>
SDE("lengthKind='implicit' is not allowed with packed binary formats")
case (_, _, _)
@@ -923,26 +922,25 @@ trait ElementBaseGrammarMixin
binaryNumberKnownLengthInBits
)
case (BinaryNumberRep.Packed, LengthKind.Delimited, -1) =>
- new PackedIntegerDelimitedEndOfData(this, isSigned, packedSignCodes)
+ new PackedIntegerDelimitedEndOfData(this, packedSignCodes)
case (BinaryNumberRep.Packed, LengthKind.Prefixed, -1) =>
- new PackedIntegerPrefixedLength(this, isSigned, packedSignCodes)
+ new PackedIntegerPrefixedLength(this, packedSignCodes)
case (BinaryNumberRep.Packed, _, -1) =>
- new PackedIntegerRuntimeLength(this, isSigned, packedSignCodes)
+ new PackedIntegerRuntimeLength(this, packedSignCodes)
case (BinaryNumberRep.Packed, _, _) =>
new PackedIntegerKnownLength(
this,
- isSigned,
packedSignCodes,
binaryNumberKnownLengthInBits
)
case (BinaryNumberRep.Ibm4690Packed, LengthKind.Delimited, -1) =>
- new IBM4690PackedIntegerDelimitedEndOfData(this, isSigned)
+ new IBM4690PackedIntegerDelimitedEndOfData(this)
case (BinaryNumberRep.Ibm4690Packed, LengthKind.Prefixed, -1) =>
- new IBM4690PackedIntegerPrefixedLength(this, isSigned)
+ new IBM4690PackedIntegerPrefixedLength(this)
case (BinaryNumberRep.Ibm4690Packed, _, -1) =>
- new IBM4690PackedIntegerRuntimeLength(this, isSigned)
+ new IBM4690PackedIntegerRuntimeLength(this)
case (BinaryNumberRep.Ibm4690Packed, _, _) =>
- new IBM4690PackedIntegerKnownLength(this, isSigned, binaryNumberKnownLengthInBits)
+ new IBM4690PackedIntegerKnownLength(this, binaryNumberKnownLengthInBits)
case (BinaryNumberRep.Bcd, _, _) =>
primType match {
case PrimType.Long | PrimType.Int | PrimType.Short | PrimType.Byte =>
@@ -974,13 +972,8 @@ trait ElementBaseGrammarMixin
// This is in the spirit of that section.
val res: Gram = primType match {
- case PrimType.Byte | PrimType.Short | PrimType.Int | PrimType.Long | PrimType.Integer => {
- binaryIntegerValue(true)
- }
-
- case PrimType.UnsignedByte | PrimType.UnsignedShort | PrimType.UnsignedInt |
- PrimType.UnsignedLong | PrimType.NonNegativeInteger => {
- binaryIntegerValue(false)
+ case n: PrimType.PrimNumeric if n.isInteger => {
+ binaryIntegerValue
}
case PrimType.Double | PrimType.Float => {
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesBinaryNumber.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesBinaryNumber.scala
index 2fbcad59e4..8c2b4b5940 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesBinaryNumber.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesBinaryNumber.scala
@@ -40,37 +40,33 @@ import org.apache.daffodil.unparsers.runtime1.BinaryIntegerKnownLengthUnparser
import org.apache.daffodil.unparsers.runtime1.BinaryIntegerPrefixedLengthUnparser
import org.apache.daffodil.unparsers.runtime1.BinaryIntegerRuntimeLengthUnparser
-class BinaryIntegerRuntimeLength(val e: ElementBase, signed: Boolean)
- extends Terminal(e, true) {
+class BinaryIntegerRuntimeLength(val e: ElementBase) extends Terminal(e, true) {
override lazy val parser = new BinaryIntegerRuntimeLengthParser(
e.elementRuntimeData,
- signed,
e.lengthEv,
e.lengthUnits
)
override lazy val unparser: Unparser = new BinaryIntegerRuntimeLengthUnparser(
e.elementRuntimeData,
- signed,
e.lengthEv,
e.lengthUnits
)
}
-class BinaryIntegerKnownLength(val e: ElementBase, val signed: Boolean, val lengthInBits: Long)
+class BinaryIntegerKnownLength(val e: ElementBase, val lengthInBits: Long)
extends Terminal(e, true) {
override lazy val parser = {
- new BinaryIntegerKnownLengthParser(e.elementRuntimeData, signed, lengthInBits.toInt)
+ new BinaryIntegerKnownLengthParser(e.elementRuntimeData, lengthInBits.toInt)
}
override lazy val unparser: Unparser =
- new BinaryIntegerKnownLengthUnparser(e.elementRuntimeData, signed, lengthInBits.toInt)
+ new BinaryIntegerKnownLengthUnparser(e.elementRuntimeData, lengthInBits.toInt)
}
-class BinaryIntegerPrefixedLength(val e: ElementBase, signed: Boolean)
- extends Terminal(e, true) {
+class BinaryIntegerPrefixedLength(val e: ElementBase) extends Terminal(e, true) {
private lazy val erd = e.elementRuntimeData
private lazy val plerd = e.prefixedLengthElementDecl.elementRuntimeData
@@ -81,7 +77,6 @@ class BinaryIntegerPrefixedLength(val e: ElementBase, signed: Boolean)
erd,
e.prefixedLengthBody.parser,
plerd,
- signed,
e.lengthUnits,
pladj
)
@@ -101,7 +96,6 @@ class BinaryIntegerPrefixedLength(val e: ElementBase, signed: Boolean)
e.prefixedLengthBody.unparser,
plerd,
maybeNBits,
- signed,
e.lengthUnits,
pladj
)
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 152af02cba..a5380474f5 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
@@ -33,11 +33,9 @@ import org.apache.daffodil.unparsers.runtime1.IBM4690PackedIntegerKnownLengthUnp
import org.apache.daffodil.unparsers.runtime1.IBM4690PackedIntegerPrefixedLengthUnparser
import org.apache.daffodil.unparsers.runtime1.IBM4690PackedIntegerRuntimeLengthUnparser
-class IBM4690PackedIntegerRuntimeLength(val e: ElementBase, signed: Boolean)
- extends Terminal(e, true) {
+class IBM4690PackedIntegerRuntimeLength(val e: ElementBase) extends Terminal(e, true) {
override lazy val parser = new IBM4690PackedIntegerRuntimeLengthParser(
e.elementRuntimeData,
- signed,
e.lengthEv,
e.lengthUnits
)
@@ -49,23 +47,21 @@ class IBM4690PackedIntegerRuntimeLength(val e: ElementBase, signed: Boolean)
)
}
-class IBM4690PackedIntegerKnownLength(val e: ElementBase, signed: Boolean, lengthInBits: Long)
+class IBM4690PackedIntegerKnownLength(val e: ElementBase, lengthInBits: Long)
extends Terminal(e, true) {
override lazy val parser =
- new IBM4690PackedIntegerKnownLengthParser(e.elementRuntimeData, signed, lengthInBits.toInt)
+ new IBM4690PackedIntegerKnownLengthParser(e.elementRuntimeData, lengthInBits.toInt)
override lazy val unparser: Unparser =
new IBM4690PackedIntegerKnownLengthUnparser(e.elementRuntimeData, lengthInBits.toInt)
}
-class IBM4690PackedIntegerPrefixedLength(val e: ElementBase, signed: Boolean)
- extends Terminal(e, true) {
+class IBM4690PackedIntegerPrefixedLength(val e: ElementBase) extends Terminal(e, true) {
override lazy val parser = new IBM4690PackedIntegerPrefixedLengthParser(
e.elementRuntimeData,
e.prefixedLengthBody.parser,
e.prefixedLengthElementDecl.elementRuntimeData,
- signed,
e.lengthUnits,
e.prefixedLengthAdjustmentInUnits
)
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 9459267ce0..21baad5654 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
@@ -205,7 +205,6 @@ case class HexBinaryLengthPrefixed(e: ElementBase) extends Terminal(e, true) {
abstract class PackedIntegerDelimited(
e: ElementBase,
- signed: Boolean,
packedSignCodes: PackedSignCodes
) extends StringDelimited(e) {
@@ -223,9 +222,8 @@ abstract class PackedIntegerDelimited(
case class PackedIntegerDelimitedEndOfData(
e: ElementBase,
- signed: Boolean,
packedSignCodes: PackedSignCodes
-) extends PackedIntegerDelimited(e, signed, packedSignCodes) {
+) extends PackedIntegerDelimited(e, packedSignCodes) {
val isDelimRequired: Boolean = false
}
@@ -289,8 +287,7 @@ case class BCDDecimalDelimitedEndOfData(e: ElementBase) extends BCDDecimalDelimi
val isDelimRequired: Boolean = false
}
-abstract class IBM4690PackedIntegerDelimited(e: ElementBase, signed: Boolean)
- extends StringDelimited(e) {
+abstract class IBM4690PackedIntegerDelimited(e: ElementBase) extends StringDelimited(e) {
override lazy val parser: DaffodilParser = new IBM4690PackedIntegerDelimitedParser(
e.elementRuntimeData,
@@ -304,8 +301,8 @@ abstract class IBM4690PackedIntegerDelimited(e: ElementBase, signed: Boolean)
)
}
-case class IBM4690PackedIntegerDelimitedEndOfData(e: ElementBase, signed: Boolean)
- extends IBM4690PackedIntegerDelimited(e, signed) {
+case class IBM4690PackedIntegerDelimitedEndOfData(e: ElementBase)
+ extends IBM4690PackedIntegerDelimited(e) {
val isDelimRequired: Boolean = false
}
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 fef8199c69..c0f7a73ecd 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
@@ -36,12 +36,10 @@ import org.apache.daffodil.unparsers.runtime1.PackedIntegerRuntimeLengthUnparser
class PackedIntegerRuntimeLength(
val e: ElementBase,
- signed: Boolean,
packedSignCodes: PackedSignCodes
) extends Terminal(e, true) {
override lazy val parser = new PackedIntegerRuntimeLengthParser(
e.elementRuntimeData,
- signed,
packedSignCodes,
e.lengthEv,
e.lengthUnits
@@ -57,14 +55,12 @@ class PackedIntegerRuntimeLength(
class PackedIntegerKnownLength(
val e: ElementBase,
- signed: Boolean,
packedSignCodes: PackedSignCodes,
lengthInBits: Long
) extends Terminal(e, true) {
override lazy val parser = new PackedIntegerKnownLengthParser(
e.elementRuntimeData,
- signed,
packedSignCodes,
lengthInBits.toInt
)
@@ -78,7 +74,6 @@ class PackedIntegerKnownLength(
class PackedIntegerPrefixedLength(
val e: ElementBase,
- signed: Boolean,
packedSignCodes: PackedSignCodes
) extends Terminal(e, true) {
@@ -86,7 +81,6 @@ class PackedIntegerPrefixedLength(
e.elementRuntimeData,
e.prefixedLengthBody.parser,
e.prefixedLengthElementDecl.elementRuntimeData,
- signed,
packedSignCodes,
e.lengthUnits,
e.prefixedLengthAdjustmentInUnits
diff --git a/daffodil-propgen/src/main/resources/org/apache/daffodil/xsd/dafext.xsd b/daffodil-propgen/src/main/resources/org/apache/daffodil/xsd/dafext.xsd
index d0e2f4a087..69ea3fdbb5 100644
--- a/daffodil-propgen/src/main/resources/org/apache/daffodil/xsd/dafext.xsd
+++ b/daffodil-propgen/src/main/resources/org/apache/daffodil/xsd/dafext.xsd
@@ -137,6 +137,14 @@
+
+
+
+ When processing signed binary integers, which should have a length of at least 2 bits, issue
+ a warning if the length is less than 2 bits by default, otherwise (if false) issue a SDE or Processing Error.
+
+
+
@@ -734,6 +742,7 @@
+
diff --git a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/BinaryNumberUnparsers.scala b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/BinaryNumberUnparsers.scala
index 2c5745fba0..b4f99d9ab2 100644
--- a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/BinaryNumberUnparsers.scala
+++ b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/BinaryNumberUnparsers.scala
@@ -24,13 +24,16 @@ import org.apache.daffodil.io.FormatInfo
import org.apache.daffodil.lib.exceptions.Assert
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.schema.annotation.props.gen.YesNo.Yes
import org.apache.daffodil.lib.util.Maybe._
import org.apache.daffodil.lib.util.MaybeInt
import org.apache.daffodil.lib.util.Numbers._
+import org.apache.daffodil.runtime1.dpath.NodeInfo
import org.apache.daffodil.runtime1.processors.ElementRuntimeData
import org.apache.daffodil.runtime1.processors.Evaluatable
import org.apache.daffodil.runtime1.processors.ParseOrUnparseState
import org.apache.daffodil.runtime1.processors.Processor
+import org.apache.daffodil.runtime1.processors.parsers.BinaryNumberCheckWidth
import org.apache.daffodil.runtime1.processors.parsers.HasKnownLengthInBits
import org.apache.daffodil.runtime1.processors.parsers.HasRuntimeExplicitLength
import org.apache.daffodil.runtime1.processors.unparsers._
@@ -56,12 +59,7 @@ abstract class BinaryNumberBaseUnparser(override val context: ElementRuntimeData
val nBits = getBitLength(state)
val value = getNumberToPut(state)
val dos = state.dataOutputStream
- val res =
- if (nBits > 0) {
- putNumber(dos, value, nBits, state)
- } else {
- true
- }
+ val res = putNumber(dos, value, nBits, state)
if (!res) {
Assert.invariant(dos.maybeRelBitLimit0b.isDefined)
@@ -78,8 +76,11 @@ abstract class BinaryNumberBaseUnparser(override val context: ElementRuntimeData
}
-abstract class BinaryIntegerBaseUnparser(e: ElementRuntimeData, signed: Boolean)
- extends BinaryNumberBaseUnparser(e) {
+abstract class BinaryIntegerBaseUnparser(e: ElementRuntimeData)
+ extends BinaryNumberBaseUnparser(e)
+ with BinaryNumberCheckWidth {
+
+ private val primNumeric = e.optPrimType.get.asInstanceOf[NodeInfo.PrimType.PrimNumeric]
override def putNumber(
dos: DataOutputStream,
@@ -87,8 +88,18 @@ abstract class BinaryIntegerBaseUnparser(e: ElementRuntimeData, signed: Boolean)
nBits: Int,
finfo: FormatInfo
): Boolean = {
+ val state = finfo.asInstanceOf[UState]
+ if (primNumeric.minWidth.isDefined) {
+ val minWidth = primNumeric.minWidth.get
+ val isSigned = primNumeric.isSigned
+ checkMinWidth(state, isSigned, nBits, minWidth)
+ }
+ if (primNumeric.maxWidth.isDefined) {
+ val maxWidth = primNumeric.maxWidth.get
+ checkMaxWidth(state, nBits, maxWidth)
+ }
if (nBits > 64) {
- dos.putBigInt(asBigInt(value), nBits, signed, finfo)
+ dos.putBigInt(asBigInt(value), nBits, primNumeric.isSigned, finfo)
} else {
dos.putLong(asLong(value), nBits, finfo)
}
@@ -97,9 +108,8 @@ abstract class BinaryIntegerBaseUnparser(e: ElementRuntimeData, signed: Boolean)
class BinaryIntegerKnownLengthUnparser(
e: ElementRuntimeData,
- signed: Boolean,
override val lengthInBits: Int
-) extends BinaryIntegerBaseUnparser(e, signed)
+) extends BinaryIntegerBaseUnparser(e)
with HasKnownLengthInBits {
override lazy val runtimeDependencies = Vector()
@@ -108,10 +118,9 @@ class BinaryIntegerKnownLengthUnparser(
class BinaryIntegerRuntimeLengthUnparser(
val e: ElementRuntimeData,
- signed: Boolean,
val lengthEv: Evaluatable[JLong],
val lengthUnits: LengthUnits
-) extends BinaryIntegerBaseUnparser(e, signed)
+) extends BinaryIntegerBaseUnparser(e)
with HasRuntimeExplicitLength {
override val runtimeDependencies = Vector(lengthEv)
@@ -122,12 +131,13 @@ class BinaryIntegerPrefixedLengthUnparser(
override val prefixedLengthUnparser: Unparser,
override val prefixedLengthERD: ElementRuntimeData,
maybeNBits: MaybeInt,
- signed: Boolean,
override val lengthUnits: LengthUnits,
override val prefixedLengthAdjustmentInUnits: Long
-) extends BinaryIntegerBaseUnparser(e: ElementRuntimeData, signed: Boolean)
+) extends BinaryIntegerBaseUnparser(e: ElementRuntimeData)
with KnownPrefixedLengthUnparserMixin {
+ private val primNumeric = e.optPrimType.get.asInstanceOf[NodeInfo.PrimType.PrimNumeric]
+
override def childProcessors: Vector[Processor] = Vector(prefixedLengthUnparser)
override lazy val runtimeDependencies = Vector()
@@ -140,7 +150,7 @@ class BinaryIntegerPrefixedLengthUnparser(
// bytes needed to represent the number
val value = getNumberToPut(s.asInstanceOf[UState])
val len = Math.max(asBigInt(value).bitLength, 1)
- val signedLen = if (signed) len + 1 else len
+ val signedLen = if (primNumeric.isSigned) len + 1 else len
(signedLen + 7) & ~0x7 // round up to nearest multilpe of 8
}
}
@@ -241,7 +251,8 @@ abstract class BinaryDecimalUnparserBase(
e: ElementRuntimeData,
signed: YesNo,
binaryDecimalVirtualPoint: Int
-) extends BinaryNumberBaseUnparser(e) {
+) extends BinaryNumberBaseUnparser(e)
+ with BinaryNumberCheckWidth {
override def getNumberToPut(state: UState): JNumber = {
val node = state.currentInfosetNode.asSimple
@@ -268,6 +279,10 @@ abstract class BinaryDecimalUnparserBase(
nBits: Int,
finfo: FormatInfo
): Boolean = {
- dos.putBigInt(asBigInt(value), nBits, signed == YesNo.Yes, finfo)
+ val state = finfo.asInstanceOf[UState]
+ 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)
}
}
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dpath/DFDLXFunctions.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dpath/DFDLXFunctions.scala
index 5cec60fff4..106d4740e2 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dpath/DFDLXFunctions.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dpath/DFDLXFunctions.scala
@@ -54,7 +54,7 @@ case class DFDLXLeftShift(recipes: List[CompiledDPath], argType: NodeInfo.Kind)
val shiftLong = arg2.getLong
val shift = shiftLong.toInt
- val width = argType.asInstanceOf[PrimNumeric].width.get
+ val width = argType.asInstanceOf[PrimNumeric].maxWidth.get
Assert.invariant(shift >= 0)
if (shift >= width)
dstate.SDE(
@@ -101,7 +101,7 @@ case class DFDLXRightShift(recipes: List[CompiledDPath], argType: NodeInfo.Kind)
): DataValuePrimitive = {
val shiftLong = arg2.getLong
val shift = shiftLong.toInt
- val width = argType.asInstanceOf[PrimNumeric].width.get
+ val width = argType.asInstanceOf[PrimNumeric].maxWidth.get
Assert.invariant(shift >= 0)
if (shift >= width)
dstate.SDE(
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dpath/NodeInfo.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dpath/NodeInfo.scala
index cb94dec31f..5ce59bf1ac 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dpath/NodeInfo.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dpath/NodeInfo.scala
@@ -534,7 +534,9 @@ object NodeInfo extends Enum {
}
trait PrimNumeric { self: Numeric.Kind =>
- def width: MaybeInt
+ def isSigned: Boolean
+ def minWidth: MaybeInt
+ def maxWidth: MaybeInt
def isValid(n: Number): Boolean
protected def fromNumberNoCheck(n: Number): DataValueNumber
def fromNumber(n: Number): DataValueNumber = {
@@ -648,7 +650,9 @@ object NodeInfo extends Enum {
// toString would have a precision different than Float.MaxValue.toString
override val minStr = "-" + JFloat.MAX_VALUE.toString
override val maxStr = JFloat.MAX_VALUE.toString
- override val width: MaybeInt = MaybeInt(32)
+ override val isSigned: Boolean = true
+ override val minWidth: MaybeInt = MaybeInt(32)
+ override val maxWidth: MaybeInt = MaybeInt(32)
}
protected sealed trait DoubleKind extends SignedNumeric.Kind
@@ -667,7 +671,9 @@ object NodeInfo extends Enum {
override val max = JDouble.MAX_VALUE
override val minStr = "-" + JDouble.MAX_VALUE.toString
override val maxStr = JDouble.MAX_VALUE.toString
- override val width: MaybeInt = MaybeInt(64)
+ override val isSigned: Boolean = true
+ override val minWidth: MaybeInt = MaybeInt(64)
+ override val maxWidth: MaybeInt = MaybeInt(64)
}
protected sealed trait DecimalKind extends SignedNumeric.Kind
@@ -686,8 +692,9 @@ object NodeInfo extends Enum {
case _ => true
}
}
-
- override val width: MaybeInt = MaybeInt.Nope
+ override val isSigned: Boolean = true
+ override val minWidth: MaybeInt = MaybeInt.Nope
+ override val maxWidth: MaybeInt = MaybeInt.Nope
override def isInteger = false
}
@@ -708,8 +715,9 @@ object NodeInfo extends Enum {
case _ => true
}
}
-
- override val width: MaybeInt = MaybeInt.Nope
+ override val isSigned: Boolean = true
+ override val minWidth: MaybeInt = MaybeInt(2)
+ override val maxWidth: MaybeInt = MaybeInt.Nope
override def isInteger = true
}
@@ -725,7 +733,9 @@ object NodeInfo extends Enum {
protected override def fromNumberNoCheck(n: Number): DataValueLong = n.longValue
override val min = JLong.MIN_VALUE
override val max = JLong.MAX_VALUE
- override val width: MaybeInt = MaybeInt(64)
+ override val isSigned: Boolean = true
+ override val minWidth: MaybeInt = MaybeInt(2)
+ override val maxWidth: MaybeInt = MaybeInt(64)
}
protected sealed trait IntKind extends Long.Kind
@@ -739,7 +749,9 @@ object NodeInfo extends Enum {
protected override def fromNumberNoCheck(n: Number): DataValueInt = n.intValue
override val min = JInt.MIN_VALUE.toLong
override val max = JInt.MAX_VALUE.toLong
- override val width: MaybeInt = MaybeInt(32)
+ override val isSigned: Boolean = true
+ override val minWidth: MaybeInt = MaybeInt(2)
+ override val maxWidth: MaybeInt = MaybeInt(32)
}
protected sealed trait ShortKind extends Int.Kind
@@ -753,7 +765,9 @@ object NodeInfo extends Enum {
protected override def fromNumberNoCheck(n: Number): DataValueShort = n.shortValue
override val min = JShort.MIN_VALUE.toLong
override val max = JShort.MAX_VALUE.toLong
- override val width: MaybeInt = MaybeInt(16)
+ override val isSigned: Boolean = true
+ override val minWidth: MaybeInt = MaybeInt(2)
+ override val maxWidth: MaybeInt = MaybeInt(16)
}
protected sealed trait ByteKind extends Short.Kind
@@ -767,7 +781,9 @@ object NodeInfo extends Enum {
protected override def fromNumberNoCheck(n: Number): DataValueByte = n.byteValue
override val min = JByte.MIN_VALUE.toLong
override val max = JByte.MAX_VALUE.toLong
- override val width: MaybeInt = MaybeInt(8)
+ override val isSigned: Boolean = true
+ override val minWidth: MaybeInt = MaybeInt(2)
+ override val maxWidth: MaybeInt = MaybeInt(8)
}
protected sealed trait NonNegativeIntegerKind extends Integer.Kind
@@ -786,8 +802,9 @@ object NodeInfo extends Enum {
case f: JFloat if f.isInfinite || f.isNaN => false
case _ => n.longValue >= 0
}
-
- override val width: MaybeInt = MaybeInt.Nope
+ override val isSigned: Boolean = false
+ override val minWidth: MaybeInt = MaybeInt(1)
+ override val maxWidth: MaybeInt = MaybeInt.Nope
override def isInteger = true
}
@@ -814,7 +831,9 @@ object NodeInfo extends Enum {
}
val max = new JBigInt(1, scala.Array.fill(8)(0xff.toByte))
val maxBD = new JBigDecimal(max)
- override val width: MaybeInt = MaybeInt(64)
+ override val isSigned: Boolean = false
+ override val minWidth: MaybeInt = MaybeInt(1)
+ override val maxWidth: MaybeInt = MaybeInt(64)
override def isInteger = true
}
@@ -834,7 +853,9 @@ object NodeInfo extends Enum {
protected override def fromNumberNoCheck(n: Number): DataValueLong = n.longValue
override val min = 0L
override val max = 0xffffffffL
- override val width: MaybeInt = MaybeInt(32)
+ override val isSigned: Boolean = false
+ override val minWidth: MaybeInt = MaybeInt(1)
+ override val maxWidth: MaybeInt = MaybeInt(32)
}
protected sealed trait UnsignedShortKind extends UnsignedInt.Kind
@@ -848,7 +869,9 @@ object NodeInfo extends Enum {
protected override def fromNumberNoCheck(n: Number): DataValueInt = n.intValue
override val min = 0L
override val max = 0xffffL
- override val width: MaybeInt = MaybeInt(16)
+ override val isSigned: Boolean = false
+ override val minWidth: MaybeInt = MaybeInt(1)
+ override val maxWidth: MaybeInt = MaybeInt(16)
}
protected sealed trait UnsignedByteKind extends UnsignedShort.Kind
@@ -862,7 +885,9 @@ object NodeInfo extends Enum {
protected override def fromNumberNoCheck(n: Number): DataValueShort = n.shortValue
override val min = 0L
override val max = 0xffL
- override val width: MaybeInt = MaybeInt(8)
+ override val isSigned: Boolean = false
+ override val minWidth: MaybeInt = MaybeInt(1)
+ override val maxWidth: MaybeInt = MaybeInt(8)
}
protected sealed trait StringKind extends AnyAtomic.Kind
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 36067c404f..dc2799262f 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
@@ -81,10 +81,9 @@ class IBM4690PackedDecimalPrefixedLengthParser(
class IBM4690PackedIntegerRuntimeLengthParser(
val e: ElementRuntimeData,
- signed: Boolean,
val lengthEv: Evaluatable[JLong],
val lengthUnits: LengthUnits
-) extends PackedBinaryIntegerBaseParser(e, signed)
+) extends PackedBinaryIntegerBaseParser(e)
with HasRuntimeExplicitLength {
override def toBigInteger(num: Array[Byte]): JBigInteger =
@@ -96,9 +95,8 @@ class IBM4690PackedIntegerRuntimeLengthParser(
class IBM4690PackedIntegerKnownLengthParser(
e: ElementRuntimeData,
- signed: Boolean,
val lengthInBits: Int
-) extends PackedBinaryIntegerBaseParser(e, signed)
+) extends PackedBinaryIntegerBaseParser(e)
with HasKnownLengthInBits {
override def toBigInteger(num: Array[Byte]): JBigInteger =
@@ -112,10 +110,9 @@ class IBM4690PackedIntegerPrefixedLengthParser(
e: ElementRuntimeData,
override val prefixedLengthParser: Parser,
override val prefixedLengthERD: ElementRuntimeData,
- signed: Boolean,
override val lengthUnits: LengthUnits,
override val prefixedLengthAdjustmentInUnits: Long
-) extends PackedBinaryIntegerBaseParser(e, signed)
+) extends PackedBinaryIntegerBaseParser(e)
with PrefixedLengthParserMixin {
override def toBigInteger(num: Array[Byte]): JBigInteger =
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 5030e0a687..e992768059 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,6 +26,7 @@ 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.processors.ElementRuntimeData
import org.apache.daffodil.runtime1.processors.FieldDFAParseEv
import org.apache.daffodil.runtime1.processors.ParseOrUnparseState
@@ -51,7 +52,14 @@ abstract class PackedBinaryDecimalBaseParser(
def parse(start: PState): Unit = {
val nBits = getBitLength(start)
- if (nBits == 0) return // zero length is used for outputValueCalc often.
+ if (nBits == 0) {
+ PE(
+ start,
+ "Number of bits %d out of range for a packed decimal.",
+ nBits
+ )
+ return
+ }
val dis = start.dataInputStream
if (!dis.isDefinedForLength(nBits)) {
@@ -69,17 +77,30 @@ abstract class PackedBinaryDecimalBaseParser(
}
abstract class PackedBinaryIntegerBaseParser(
- override val context: ElementRuntimeData,
- signed: Boolean = false
+ override val context: ElementRuntimeData
) extends PrimParser
with PackedBinaryConversion {
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 = {
val nBits = getBitLength(start)
- if (nBits == 0) return // zero length is used for outputValueCalc often.
+ if (nBits == 0) {
+ PE(
+ start,
+ "Number of bits %d out of range for a packed integer.",
+ nBits
+ )
+ return
+ }
val dis = start.dataInputStream
if (!dis.isDefinedForLength(nBits)) {
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 248322f3e1..6f130de9f6 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
@@ -84,11 +84,10 @@ class PackedDecimalPrefixedLengthParser(
class PackedIntegerRuntimeLengthParser(
val e: ElementRuntimeData,
- signed: Boolean,
packedSignCodes: PackedSignCodes,
val lengthEv: Evaluatable[JLong],
val lengthUnits: LengthUnits
-) extends PackedBinaryIntegerBaseParser(e, signed)
+) extends PackedBinaryIntegerBaseParser(e)
with HasRuntimeExplicitLength {
override def toBigInteger(num: Array[Byte]): JBigInteger =
@@ -100,10 +99,9 @@ class PackedIntegerRuntimeLengthParser(
class PackedIntegerKnownLengthParser(
e: ElementRuntimeData,
- signed: Boolean,
packedSignCodes: PackedSignCodes,
val lengthInBits: Int
-) extends PackedBinaryIntegerBaseParser(e, signed)
+) extends PackedBinaryIntegerBaseParser(e)
with HasKnownLengthInBits {
override def toBigInteger(num: Array[Byte]): JBigInteger =
@@ -117,11 +115,10 @@ class PackedIntegerPrefixedLengthParser(
e: ElementRuntimeData,
override val prefixedLengthParser: Parser,
override val prefixedLengthERD: ElementRuntimeData,
- signed: Boolean,
packedSignCodes: PackedSignCodes,
override val lengthUnits: LengthUnits,
override val prefixedLengthAdjustmentInUnits: Long
-) extends PackedBinaryIntegerBaseParser(e, signed)
+) extends PackedBinaryIntegerBaseParser(e)
with PrefixedLengthParserMixin {
override def toBigInteger(num: Array[Byte]): JBigInteger =
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/BinaryNumberParsers.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/BinaryNumberParsers.scala
index a373be2fbc..fac7a9078f 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/BinaryNumberParsers.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/BinaryNumberParsers.scala
@@ -22,12 +22,14 @@ import java.math.{ BigDecimal => JBigDecimal, BigInteger => JBigInt }
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.schema.annotation.props.gen.YesNo.Yes
import org.apache.daffodil.runtime1.dpath.InvalidPrimitiveDataException
import org.apache.daffodil.runtime1.dpath.NodeInfo
import org.apache.daffodil.runtime1.processors.ElementRuntimeData
import org.apache.daffodil.runtime1.processors.Evaluatable
import org.apache.daffodil.runtime1.processors.ParseOrUnparseState
import org.apache.daffodil.runtime1.processors.Processor
+import org.apache.daffodil.runtime1.processors.unparsers.UState
class BinaryFloatParser(override val context: ElementRuntimeData) extends PrimParser {
override lazy val runtimeDependencies = Vector()
@@ -100,13 +102,18 @@ abstract class BinaryDecimalParserBase(
override val context: ElementRuntimeData,
signed: YesNo,
binaryDecimalVirtualPoint: Int
-) extends PrimParser {
+) extends PrimParser
+ with BinaryNumberCheckWidth {
override lazy val runtimeDependencies = Vector()
protected def getBitLength(s: ParseOrUnparseState): Int
def parse(start: PState): Unit = {
val nBits = getBitLength(start)
+ val isSigned = signed == Yes
+ val minWidth = if (isSigned) 2 else 1
+ val res = checkMinWidth(start, isSigned, nBits, minWidth)
+ if (!res) return
val dis = start.dataInputStream
if (!dis.isDefinedForLength(nBits)) {
PENotEnoughBits(start, nBits, dis)
@@ -124,27 +131,24 @@ abstract class BinaryDecimalParserBase(
class BinaryIntegerRuntimeLengthParser(
val e: ElementRuntimeData,
- signed: Boolean,
val lengthEv: Evaluatable[JLong],
val lengthUnits: LengthUnits
-) extends BinaryIntegerBaseParser(e, signed)
+) extends BinaryIntegerBaseParser(e)
with HasRuntimeExplicitLength {}
class BinaryIntegerKnownLengthParser(
e: ElementRuntimeData,
- signed: Boolean,
val lengthInBits: Int
-) extends BinaryIntegerBaseParser(e, signed)
+) extends BinaryIntegerBaseParser(e)
with HasKnownLengthInBits {}
class BinaryIntegerPrefixedLengthParser(
e: ElementRuntimeData,
override val prefixedLengthParser: Parser,
override val prefixedLengthERD: ElementRuntimeData,
- signed: Boolean,
override val lengthUnits: LengthUnits,
override val prefixedLengthAdjustmentInUnits: Long
-) extends BinaryIntegerBaseParser(e, signed)
+) extends BinaryIntegerBaseParser(e)
with PrefixedLengthParserMixin {
override def childProcessors: Vector[Processor] = Vector(prefixedLengthParser)
@@ -155,9 +159,9 @@ class BinaryIntegerPrefixedLengthParser(
}
abstract class BinaryIntegerBaseParser(
- override val context: ElementRuntimeData,
- signed: Boolean
-) extends PrimParser {
+ override val context: ElementRuntimeData
+) extends PrimParser
+ with BinaryNumberCheckWidth {
override lazy val runtimeDependencies = Vector()
protected def getBitLength(s: ParseOrUnparseState): Int
@@ -166,16 +170,16 @@ abstract class BinaryIntegerBaseParser(
def parse(start: PState): Unit = {
val nBits = getBitLength(start)
- if (nBits == 0) return // zero length is used for outputValueCalc often.
- if (primNumeric.width.isDefined) {
- val width = primNumeric.width.get
- if (nBits > width)
- PE(
- start,
- "Number of bits %d out of range, must be between 1 and %d bits.",
- nBits,
- width
- )
+ if (primNumeric.minWidth.isDefined) {
+ val minWidth = primNumeric.minWidth.get
+ val isSigned: Boolean = primNumeric.isSigned
+ val res = checkMinWidth(start, isSigned, nBits, minWidth)
+ if (!res) return
+ }
+ if (primNumeric.maxWidth.isDefined) {
+ val maxWidth = primNumeric.maxWidth.get
+ val res = checkMaxWidth(start, nBits, maxWidth)
+ if (!res) return
}
val dis = start.dataInputStream
if (!dis.isDefinedForLength(nBits)) {
@@ -184,7 +188,7 @@ abstract class BinaryIntegerBaseParser(
}
val num: JNumber =
- if (signed) {
+ if (primNumeric.isSigned) {
if (nBits > 64) { dis.getSignedBigInt(nBits, start) }
else { dis.getSignedLong(nBits, start) }
} else {
@@ -205,3 +209,46 @@ abstract class BinaryIntegerBaseParser(
start.simpleElement.overwriteDataValue(res)
}
}
+
+trait BinaryNumberCheckWidth {
+ def checkMinWidth(
+ state: ParseOrUnparseState,
+ isSigned: Boolean,
+ nBits: Int,
+ minWidth: Int
+ ): Boolean = {
+ if (
+ nBits < minWidth && !(isSigned && state.tunable.allowSignedIntegerLength1Bit && nBits == 1)
+ ) {
+ val signedStr = if (isSigned) "a signed" else "an unsigned"
+ val outOfRangeStr =
+ s"Minimum length for $signedStr binary number is $minWidth bit(s), number of bits $nBits out of range. " +
+ "An unsigned number with length 1 bit could be used instead."
+ val procErr = state.toProcessingError(outOfRangeStr)
+ state match {
+ case s: PState =>
+ s.setFailed(procErr)
+ return false
+ case s: UState =>
+ s.toss(procErr)
+ }
+ }
+ true
+ }
+
+ def checkMaxWidth(state: ParseOrUnparseState, nBits: Int, maxWidth: Int): Boolean = {
+ if (nBits > maxWidth) {
+ val procErr = state.toProcessingError(
+ s"Number of bits $nBits out of range, must be between 1 and $maxWidth bits."
+ )
+ state match {
+ case s: PState =>
+ s.setFailed(procErr)
+ return false
+ case s: UState =>
+ s.toss(procErr)
+ }
+ }
+ true
+ }
+}
diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/extensions/enum/enums.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/extensions/enum/enums.tdml
index 7923ae7c44..4205964498 100644
--- a/daffodil-test/src/test/resources/org/apache/daffodil/extensions/enum/enums.tdml
+++ b/daffodil-test/src/test/resources/org/apache/daffodil/extensions/enum/enums.tdml
@@ -134,7 +134,7 @@
-
+
diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/section02/validation_errors/Validation.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/section02/validation_errors/Validation.tdml
index 88bb887021..1467b4e701 100644
--- a/daffodil-test/src/test/resources/org/apache/daffodil/section02/validation_errors/Validation.tdml
+++ b/daffodil-test/src/test/resources/org/apache/daffodil/section02/validation_errors/Validation.tdml
@@ -2521,7 +2521,7 @@
-
+
@@ -2537,7 +2537,10 @@
- a
+
+ 1
+ a
+
Runtime Schema Definition Error
dfdl:bitOrder
diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/section11/content_framing_properties/ContentFramingProps.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/section11/content_framing_properties/ContentFramingProps.tdml
index 20f7cb22ec..fe747f4a97 100644
--- a/daffodil-test/src/test/resources/org/apache/daffodil/section11/content_framing_properties/ContentFramingProps.tdml
+++ b/daffodil-test/src/test/resources/org/apache/daffodil/section11/content_framing_properties/ContentFramingProps.tdml
@@ -1319,7 +1319,7 @@
-
+
+
+
+
+ 64
+ 32
+
+
+
+
+ 64 out of range
+ between 1 and 32
+
+
+
@@ -1490,7 +1506,7 @@
-
+
@@ -1521,4 +1537,635 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+
+
+
+ ff
+
+
+
+ Schema Definition Error
+ unsigned binary integer
+ 1 bit(s)
+ 0 out of range
+
+
+
+
+
+
+ ff
+
+
+
+ Schema Definition Error
+ signed binary integer
+ 2 bit(s)
+ 1 out of range
+
+
+
+
+
+
+ 0
+
+
+
+ Schema Definition Error
+ unsigned binary integer
+ 1 bit(s)
+ 0 out of range
+
+
+
+
+
+
+ 0
+
+
+
+ Schema Definition Error
+ signed binary integer
+ 2 bit(s)
+ 1 out of range
+
+
+
+
+
+
+
+
+ -1
+
+
+
+
+ Unparse Error
+ signed binary number
+ 2 bit(s)
+ 1 out of range
+
+
+
+
+
+
+
+ 0
+ 65535
+
+
+
+
+ Unparse Error
+ unsigned binary number
+ 1 bit(s)
+ 0 out of range
+
+
+
+
+
+
+ 1
+ -1
+
+
+
+
+ 0180
+
+
+
+
+
+ 01
+ 1
+
+
+
+
+ 1
+ 1
+
+
+
+
+
+
+
+ 1
+
+
+
+ 1
+
+
+
+ Schema Definition Warning
+ signed binary integer
+ 2 bit(s)
+ 1 out of range
+
+
+
+
+
+ 00123C
+
+
+ Parse Error
+ 0 out of range
+
+
+
+
+
+ 001088
+
+
+ Parse Error
+ 0 out of range
+
+
+
+
+
+ 00123C
+
+
+ Parse Error
+ 0 out of range
+
+
+
+
+
+ 001088
+
+
+ Parse Error
+ 0 out of range
+
+
+
+
+
+
+ 1
+
+
+
+
+ 1
+
+
+
+
+
+
+
+ 11
+
+
+
+
+ -1
+
+
+
+
+
+
+
+ 11
+
+
+
+
+ -1
+
+
+
+
+
+
+
+ 1
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ 2
+ -1
+
+
+
+
+ 02
+ 11
+
+
+
+
+
+ 02123C
+
+
+
+
+ 2
+ 123
+
+
+
+
+
+
+
+ 021088
+
+
+
+
+ 2
+ 1088
+
+
+
+
+
+
+
+ 02
+ 11
+
+
+
+
+ 2
+ -1
+
+
+
+
+
+
+
+
+
+ 1
+ 1
+
+
+
+
+ 01
+ 1
+
+
+
+
+
+
+ 4668
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ff
+
+
+
+ Parse Error
+ unsigned binary number
+ 1 bit(s)
+ 0 out of range
+
+
+
+
+
+
+ ff
+
+
+
+ Parse Error
+ signed binary number
+ 2 bit(s)
+ 1 out of range
+
+
+
+
+
+
+ 1
+
+
+
+ Unparse Error
+ unsigned binary number
+ 1 bit(s)
+ 0 out of range
+
+
+
+
+
+
+ 1
+
+
+
+ Unparse Error
+ signed binary number
+ 2 bit(s)
+ 1 out of range
+
+
+
+
+
+ 1
+
+
+
+ 1
+
+
+
+
+
+
+
+ 1
+
+
+
+ 1
+
+
+
+
+
+ 00
+ 1
+
+
+ Parse Error
+ signed binary number
+ 2 bit(s)
+ 0 out of range
+
+
+
+
+
+
+
+ 0
+ 1
+
+
+
+
+ Unparse Error
+ signed binary number
+ 2 bit(s)
+ 0 out of range
+
+
+
+
+
+ 00
+ 1
+
+
+ Parse Error
+ signed binary number
+ 1 bit(s)
+ 0 out of range
+
+
+
+
+
+
+
+ 0
+ 1
+
+
+
+
+ Unparse Error
+ signed binary number
+ 1 bit(s)
+ 0 out of range
+
+
diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/section12/length_properties/LengthProperties.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/section12/length_properties/LengthProperties.tdml
index 866691abc0..52c8ed0f08 100644
--- a/daffodil-test/src/test/resources/org/apache/daffodil/section12/length_properties/LengthProperties.tdml
+++ b/daffodil-test/src/test/resources/org/apache/daffodil/section12/length_properties/LengthProperties.tdml
@@ -913,7 +913,7 @@
-
+
@@ -922,15 +922,15 @@
-
+
-
-
+
+
-
+
@@ -1118,7 +1118,7 @@
-
+
@@ -1190,7 +1190,7 @@
-
+
@@ -1245,10 +1245,10 @@
root="s4" model="bitSchema" description="Section 12 Length Properties - DFDL-12-161R">
00101010
- 1
+ 01
00000000 00000000 00000000 00000001
- 0
- 1
+ 00
+ 01
diff --git a/daffodil-test/src/test/scala/org/apache/daffodil/section12/lengthKind/TestLengthKindExplicit.scala b/daffodil-test/src/test/scala/org/apache/daffodil/section12/lengthKind/TestLengthKindExplicit.scala
index f8a62cb6de..c787fc2267 100644
--- a/daffodil-test/src/test/scala/org/apache/daffodil/section12/lengthKind/TestLengthKindExplicit.scala
+++ b/daffodil-test/src/test/scala/org/apache/daffodil/section12/lengthKind/TestLengthKindExplicit.scala
@@ -164,6 +164,9 @@ class TestLengthKindExplicit {
@Test def test_invalidIntBitLengthExpr(): Unit = {
runner.runOneTest("invalidIntBitLengthExpr")
}
+ @Test def test_unparseInvalidIntBitLengthExpr(): Unit = {
+ runner.runOneTest("unparseInvalidIntBitLengthExpr")
+ }
@Test def test_invalidShortBitLengthExpr(): Unit = {
runner.runOneTest("invalidShortBitLengthExpr")
@@ -180,4 +183,105 @@ class TestLengthKindExplicit {
@Test def test_insufficientBitsByte(): Unit = {
runner.runOneTest("insufficientBitsByte")
}
+
+ // DFDL-2297
+ @Test def test_outOfRangeLengthBinaryInteger1(): Unit = {
+ runner.runOneTest("outOfRangeLengthBinaryInteger1")
+ }
+ @Test def test_outOfRangeLengthBinaryInteger2(): Unit = {
+ runner.runOneTest("outOfRangeLengthBinaryInteger2")
+ }
+ @Test def test_outOfRangeLengthBinaryInteger3(): Unit = {
+ runner.runOneTest("outOfRangeLengthBinaryInteger3")
+ }
+ @Test def test_outOfRangeLengthBinaryInteger4(): Unit = {
+ runner.runOneTest("outOfRangeLengthBinaryInteger4")
+ }
+ @Test def test_outOfRangeLengthBinaryInteger5(): Unit = {
+ runner.runOneTest("outOfRangeLengthBinaryInteger5")
+ }
+ @Test def test_outOfRangeLengthBinaryInteger6(): Unit = {
+ runner.runOneTest("outOfRangeLengthBinaryInteger6")
+ }
+ @Test def test_outOfRangeLengthBinaryInteger7(): Unit = {
+ runner.runOneTest("outOfRangeLengthBinaryInteger7")
+ }
+ @Test def test_outOfRangeLengthBinaryInteger8(): Unit = {
+ runner.runOneTest("outOfRangeLengthBinaryInteger8")
+ }
+ @Test def test_outOfRangeLengthBinaryInteger9(): Unit = {
+ runner.runOneTest("outOfRangeLengthBinaryInteger9")
+ }
+ @Test def test_outOfRangeLengthBinaryInteger10(): Unit = {
+ runner.runOneTest("outOfRangeLengthBinaryInteger10")
+ }
+ @Test def test_outOfRangeLengthBinaryInteger11(): Unit = {
+ runner.runOneTest("outOfRangeLengthBinaryInteger11")
+ }
+ @Test def test_outOfRangeLengthBinaryInteger12(): Unit = {
+ runner.runOneTest("outOfRangeLengthBinaryInteger12")
+ }
+ @Test def test_outOfRangeLengthBinaryInteger13(): Unit = {
+ runner.runOneTest("outOfRangeLengthBinaryInteger13")
+ }
+ @Test def test_inRangeLengthBinaryInteger1(): Unit = {
+ runner.runOneTest("inRangeLengthBinaryInteger1")
+ }
+ @Test def test_inRangeLengthBinaryInteger2(): Unit = {
+ runner.runOneTest("inRangeLengthBinaryInteger2")
+ }
+ @Test def test_inRangeLengthBinaryInteger3(): Unit = {
+ runner.runOneTest("inRangeLengthBinaryInteger3")
+ }
+ @Test def test_inRangeLengthBinaryInteger4(): Unit = {
+ runner.runOneTest("inRangeLengthBinaryInteger4")
+ }
+ @Test def test_inRangeLengthBinaryInteger5(): Unit = {
+ runner.runOneTest("inRangeLengthBinaryInteger5")
+ }
+ @Test def test_inRangeLengthBinaryInteger6(): Unit = {
+ runner.runOneTest("inRangeLengthBinaryInteger6")
+ }
+ @Test def test_inRangeLengthBinaryInteger7(): Unit = {
+ runner.runOneTest("inRangeLengthBinaryInteger7")
+ }
+ @Test def test_inRangeLengthBinaryInteger8(): Unit = {
+ runner.runOneTest("inRangeLengthBinaryInteger8")
+ }
+ @Test def test_inRangeLengthBinaryInteger9(): Unit = {
+ runner.runOneTest("inRangeLengthBinaryInteger9")
+ }
+ @Test def test_inRangeLengthBinaryInteger10(): Unit = {
+ runner.runOneTest("inRangeLengthBinaryInteger10")
+ }
+ @Test def test_outOfRangeLengthBinaryDecimal1(): Unit = {
+ runner.runOneTest("outOfRangeLengthBinaryDecimal1")
+ }
+ @Test def test_outOfRangeLengthBinaryDecimal2(): Unit = {
+ runner.runOneTest("outOfRangeLengthBinaryDecimal2")
+ }
+ @Test def test_outOfRangeLengthBinaryDecimal3(): Unit = {
+ runner.runOneTest("outOfRangeLengthBinaryDecimal3")
+ }
+ @Test def test_outOfRangeLengthBinaryDecimal4(): Unit = {
+ runner.runOneTest("outOfRangeLengthBinaryDecimal4")
+ }
+ @Test def test_outOfRangeLengthBinaryDecimal5(): Unit = {
+ runner.runOneTest("outOfRangeLengthBinaryDecimal5")
+ }
+ @Test def test_outOfRangeLengthBinaryDecimal6(): Unit = {
+ runner.runOneTest("outOfRangeLengthBinaryDecimal6")
+ }
+ @Test def test_outOfRangeLengthBinaryDecimal7(): Unit = {
+ runner.runOneTest("outOfRangeLengthBinaryDecimal7")
+ }
+ @Test def test_outOfRangeLengthBinaryDecimal8(): Unit = {
+ runner.runOneTest("outOfRangeLengthBinaryDecimal8")
+ }
+ @Test def test_outOfRangeLengthBinaryDecimal9(): Unit = {
+ runner.runOneTest("outOfRangeLengthBinaryDecimal9")
+ }
+ @Test def test_outOfRangeLengthBinaryDecimal10(): Unit = {
+ runner.runOneTest("outOfRangeLengthBinaryDecimal10")
+ }
}