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..09e4282043 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 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,10 @@ 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 match { + case n: PrimType.PrimNumeric => n.isSigned + case _ => false + } 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 9550e359c0..edcf343e9b 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 @@ -775,32 +775,36 @@ trait ElementBase result.isDefined && repElement.isSimpleType && representation == Representation.Binary ) { val nBits = result.get - if (isSignedIntegerType && nBits < 2) { - val outOfRangeStr = - "Minimum length for a signed binary integer is 2 bits, number of bits %d out of range. " + - "An unsigned integer with length 1 bit could be used instead." - if (tunable.allowSignedIntegerLength1Bit) { - SDW( - WarnID.SignedBinaryIntegerLength1Bit, - outOfRangeStr, - nBits - ) - } else { - SDE( - outOfRangeStr, - nBits - ) - } - } - schemaDefinitionWhen( - isUnsignedIntegerType && nBits < 1, - "Minimum length for an unsigned binary integer is 1 bit, number of bits %d out of range.", - nBits - ) primType match { case primNumeric: NodeInfo.PrimType.PrimNumeric => - if (primNumeric.width.isDefined) { - val width = primNumeric.width.get + if (primNumeric.minWidth.isDefined) { + val isSigned = primNumeric.isSigned + val signedStr = if (isSigned) "signed" else "unsigned" + val minWidth = primNumeric.minWidth.get + if(nBits < minWidth) { + val outOfRangeFmtStr = + "Minimum length for a %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) { + 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 402b16bee8..0473671ccc 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 @@ -782,7 +782,7 @@ trait ElementBaseGrammarMixin ) { ConvertZonedCombinator( this, - new IBM4690PackedIntegerKnownLength(this, false, binaryNumberKnownLengthInBits), + new IBM4690PackedIntegerKnownLength(this, binaryNumberKnownLengthInBits), textConverter ) } @@ -792,7 +792,7 @@ trait ElementBaseGrammarMixin ) { ConvertZonedCombinator( this, - new IBM4690PackedIntegerRuntimeLength(this, false), + new IBM4690PackedIntegerRuntimeLength(this), textConverter ) } @@ -802,7 +802,7 @@ trait ElementBaseGrammarMixin ) { ConvertZonedCombinator( this, - new IBM4690PackedIntegerDelimitedEndOfData(this, false), + new IBM4690PackedIntegerDelimitedEndOfData(this), textConverter ) } @@ -812,7 +812,7 @@ trait ElementBaseGrammarMixin ) { ConvertZonedCombinator( this, - new IBM4690PackedIntegerPrefixedLength(this, false), + new IBM4690PackedIntegerPrefixedLength(this), textConverter ) } @@ -823,7 +823,6 @@ trait ElementBaseGrammarMixin this, new PackedIntegerKnownLength( this, - false, packedSignCodes, binaryNumberKnownLengthInBits ), @@ -834,7 +833,7 @@ trait ElementBaseGrammarMixin prod("packedRuntimeLengthCalendar", binaryCalendarRep == BinaryCalendarRep.Packed) { ConvertZonedCombinator( this, - new PackedIntegerRuntimeLength(this, false, packedSignCodes), + new PackedIntegerRuntimeLength(this, packedSignCodes), textConverter ) } @@ -842,7 +841,7 @@ trait ElementBaseGrammarMixin prod("packedDelimitedLengthCalendar", binaryCalendarRep == BinaryCalendarRep.Packed) { ConvertZonedCombinator( this, - new PackedIntegerDelimitedEndOfData(this, false, packedSignCodes), + new PackedIntegerDelimitedEndOfData(this, packedSignCodes), textConverter ) } @@ -850,7 +849,7 @@ trait ElementBaseGrammarMixin prod("packedPrefixedLengthCalendar", binaryCalendarRep == BinaryCalendarRep.Packed) { ConvertZonedCombinator( this, - new PackedIntegerPrefixedLength(this, false, packedSignCodes), + new PackedIntegerPrefixedLength(this, packedSignCodes), textConverter ) } @@ -893,7 +892,7 @@ trait ElementBaseGrammarMixin private lazy val packedSignCodes = PackedSignCodes(binaryPackedSignCodes, binaryNumberCheckPolicy) - private def binaryIntegerValue(isSigned: Boolean) = { + private def binaryIntegerValue = { // // Is it a single byte or smaller // @@ -906,10 +905,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 (_, _, _) @@ -919,26 +918,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 => @@ -954,19 +952,6 @@ trait ElementBaseGrammarMixin } } - lazy val isSignedIntegerType: Boolean = primType match { - case PrimType.Byte | PrimType.Short | PrimType.Int | PrimType.Long | PrimType.Integer => - true - case _ => false - } - - lazy val isUnsignedIntegerType: Boolean = primType match { - case PrimType.UnsignedByte | PrimType.UnsignedShort | PrimType.UnsignedInt | - PrimType.UnsignedLong | PrimType.NonNegativeInteger => - true - case _ => false - } - private lazy val binaryValue: Gram = { Assert.invariant(primType != PrimType.String) @@ -983,12 +968,8 @@ trait ElementBaseGrammarMixin // This is in the spirit of that section. val res: Gram = primType match { - case _ if isSignedIntegerType => { - binaryIntegerValue(true) - } - - case _ if isUnsignedIntegerType => { - 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..0ef11c7ad1 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,36 +40,34 @@ 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) +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) +class BinaryIntegerPrefixedLength(val e: ElementBase) extends Terminal(e, true) { private lazy val erd = e.elementRuntimeData @@ -81,7 +79,6 @@ class BinaryIntegerPrefixedLength(val e: ElementBase, signed: Boolean) erd, e.prefixedLengthBody.parser, plerd, - signed, e.lengthUnits, pladj ) @@ -101,7 +98,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..f7b3c294ad 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,10 @@ 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) +class IBM4690PackedIntegerRuntimeLength(val e: ElementBase) extends Terminal(e, true) { override lazy val parser = new IBM4690PackedIntegerRuntimeLengthParser( e.elementRuntimeData, - signed, e.lengthEv, e.lengthUnits ) @@ -49,23 +48,22 @@ 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) +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..f45a9bb776 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,7 +287,7 @@ case class BCDDecimalDelimitedEndOfData(e: ElementBase) extends BCDDecimalDelimi val isDelimRequired: Boolean = false } -abstract class IBM4690PackedIntegerDelimited(e: ElementBase, signed: Boolean) +abstract class IBM4690PackedIntegerDelimited(e: ElementBase) extends StringDelimited(e) { override lazy val parser: DaffodilParser = new IBM4690PackedIntegerDelimitedParser( @@ -304,8 +302,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-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 59e5e03089..df266ca614 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 @@ -58,57 +58,8 @@ abstract class BinaryNumberBaseUnparser(override val context: ElementRuntimeData val nBits = getBitLength(state) val value = getNumberToPut(state) val dos = state.dataOutputStream - this match { - case unparser: BinaryIntegerBaseUnparser => { - val primNumeric = context.optPrimType.get.asInstanceOf[NodeInfo.PrimType.PrimNumeric] - // minimum length for a signed binary integer is 2 bits, for unsigned it is 1 bit - if (unparser.signed && nBits < 2) { - val outOfRangeStr = - "Minimum length for a signed binary integer is 2 bits, number of bits %d out of range. " + - "An unsigned integer with length 1 bit could be used instead." - if (state.tunable.allowSignedIntegerLength1Bit) { - state.SDW( - WarnID.SignedBinaryIntegerLength1Bit, - outOfRangeStr, - nBits - ) - } else { - UE( - state, - outOfRangeStr, - nBits - ) - return - } - } else if (!unparser.signed && nBits < 1) { - UE( - state, - "Minimum length for an unsigned binary integer is 1 bit, number of bits %d out of range.", - nBits - ) - return - } - if (primNumeric.width.isDefined) { - val width = primNumeric.width.get - if (nBits > width) { - UE( - state, - "Number of bits %d out of range, must be between 1 and %d bits.", - nBits, - width - ) - return - } - } - } - case _ => // do nothing - } - 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) @@ -125,17 +76,61 @@ abstract class BinaryNumberBaseUnparser(override val context: ElementRuntimeData } -abstract class BinaryIntegerBaseUnparser(e: ElementRuntimeData, val signed: Boolean) +abstract class BinaryIntegerBaseUnparser(e: ElementRuntimeData) extends BinaryNumberBaseUnparser(e) { + private val primNumeric = e.optPrimType.get.asInstanceOf[NodeInfo.PrimType.PrimNumeric] + override def putNumber( dos: DataOutputStream, value: JNumber, nBits: Int, finfo: FormatInfo ): Boolean = { + val state = finfo.asInstanceOf[UState] + if (primNumeric.minWidth.isDefined) { + val isSigned = primNumeric.isSigned + val signedStr = if (isSigned) "signed" else "unsigned" + val minWidth = primNumeric.minWidth.get + if(nBits < minWidth) { + val outOfRangeFmtStr = + "Minimum length for a %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 && state.tunable.allowSignedIntegerLength1Bit) { + state.SDW( + WarnID.SignedBinaryIntegerLength1Bit, + outOfRangeFmtStr, + signedStr, + minWidth, + nBits + ) + return false + } else { + UE( + state, + outOfRangeFmtStr, + signedStr, + minWidth, + nBits + ) + return false + } + } + } + if (primNumeric.maxWidth.isDefined) { + val width = primNumeric.maxWidth.get + if (nBits > width) { + UE( + state, + "Number of bits %d out of range, must be between 1 and %d bits.", + nBits, + width + ) + return false + } + } 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) } @@ -144,9 +139,8 @@ abstract class BinaryIntegerBaseUnparser(e: ElementRuntimeData, val signed: Bool class BinaryIntegerKnownLengthUnparser( e: ElementRuntimeData, - signed: Boolean, override val lengthInBits: Int -) extends BinaryIntegerBaseUnparser(e, signed) +) extends BinaryIntegerBaseUnparser(e) with HasKnownLengthInBits { override lazy val runtimeDependencies = Vector() @@ -155,10 +149,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) @@ -169,12 +162,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() @@ -187,7 +181,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 } } @@ -210,7 +204,11 @@ class BinaryFloatUnparser(e: ElementRuntimeData) extends BinaryNumberBaseUnparse nBits: Int, finfo: FormatInfo ): Boolean = { - dos.putBinaryFloat(asFloat(value), finfo) + if (nBits > 0) { + dos.putBinaryFloat(asFloat(value), finfo) + } else { + true + } } } @@ -227,7 +225,11 @@ class BinaryDoubleUnparser(e: ElementRuntimeData) extends BinaryNumberBaseUnpars nBits: Int, finfo: FormatInfo ): Boolean = { - dos.putBinaryDouble(asDouble(value), finfo) + if (nBits > 0) { + dos.putBinaryDouble(asDouble(value), finfo) + } else { + true + } } } @@ -315,6 +317,10 @@ abstract class BinaryDecimalUnparserBase( nBits: Int, finfo: FormatInfo ): Boolean = { - dos.putBigInt(asBigInt(value), nBits, signed == YesNo.Yes, finfo) + if (nBits > 0) { + dos.putBigInt(asBigInt(value), nBits, signed == YesNo.Yes, finfo) + } else { + true + } } } 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..782e2ad796 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 + val 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(2) + 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(1) + 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..dd9adf1960 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 @@ -70,11 +71,16 @@ abstract class PackedBinaryDecimalBaseParser( abstract class PackedBinaryIntegerBaseParser( override val context: ElementRuntimeData, - signed: Boolean = false ) extends PrimParser with PackedBinaryConversion { override lazy val runtimeDependencies = Vector() + val signed = { + context.optPrimType.get match { + case n: NodeInfo.PrimType.PrimNumeric => n.isSigned + case _ => false + } + } protected def getBitLength(s: ParseOrUnparseState): Int def parse(start: PState): Unit = { 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 f90cd271e0..a971017677 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 @@ -125,27 +125,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) @@ -157,7 +154,6 @@ class BinaryIntegerPrefixedLengthParser( abstract class BinaryIntegerBaseParser( override val context: ElementRuntimeData, - signed: Boolean ) extends PrimParser { override lazy val runtimeDependencies = Vector() @@ -167,35 +163,36 @@ abstract class BinaryIntegerBaseParser( def parse(start: PState): Unit = { val nBits = getBitLength(start) - // minimum length for a signed binary integer is 2 bits, for unsigned it is 1 bit - if (signed && nBits < 2) { - val outOfRangeStr = - "Minimum length for a signed binary integer is 2 bits, number of bits %d out of range. " + - "An unsigned integer with length 1 bit could be used instead." - if (start.tunable.allowSignedIntegerLength1Bit) { - start.SDW( - WarnID.SignedBinaryIntegerLength1Bit, - outOfRangeStr, - nBits - ) - } else { - PE( - start, - outOfRangeStr, - nBits - ) - return + if (primNumeric.minWidth.isDefined) { + val isSigned = primNumeric.isSigned + val signedStr = if (isSigned) "signed" else "unsigned" + val minWidth = primNumeric.minWidth.get + if(nBits < minWidth) { + val outOfRangeFmtStr = + "Minimum length for a %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 && start.tunable.allowSignedIntegerLength1Bit) { + start.SDW( + WarnID.SignedBinaryIntegerLength1Bit, + outOfRangeFmtStr, + signedStr, + minWidth, + nBits + ) + } else { + PE( + start, + outOfRangeFmtStr, + signedStr, + minWidth, + nBits + ) + return + } } - } else if (!signed && nBits < 1) { - PE( - start, - "Minimum length for an unsigned binary integer is 1 bit, number of bits %d out of range.", - nBits - ) - return } - if (primNumeric.width.isDefined) { - val width = primNumeric.width.get + if (primNumeric.maxWidth.isDefined) { + val width = primNumeric.maxWidth.get if (nBits > width) PE( start, @@ -211,7 +208,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 { diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/section12/lengthKind/ExplicitTests.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/section12/lengthKind/ExplicitTests.tdml index a975264a71..49b7f418de 100644 --- a/daffodil-test/src/test/resources/org/apache/daffodil/section12/lengthKind/ExplicitTests.tdml +++ b/daffodil-test/src/test/resources/org/apache/daffodil/section12/lengthKind/ExplicitTests.tdml @@ -1459,7 +1459,7 @@ Schema Definition Error unsigned binary integer - 1 bit + 1 bit(s) 0 out of range @@ -1475,7 +1475,7 @@ Schema Definition Error signed binary integer - 2 bits + 2 bit(s) 1 out of range @@ -1490,7 +1490,7 @@ Schema Definition Error unsigned binary integer - 1 bit + 1 bit(s) 0 out of range @@ -1506,7 +1506,7 @@ Schema Definition Error signed binary integer - 2 bits + 2 bit(s) 1 out of range @@ -1525,7 +1525,7 @@ Unparse Error signed binary integer - 2 bits + 2 bit(s) 1 out of range @@ -1543,7 +1543,7 @@ Unparse Error unsigned binary integer - 1 bit + 1 bit(s) 0 out of range