This is an automated email from the ASF dual-hosted git repository.
mmcgann pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/daffodil.git
The following commit(s) were added to refs/heads/main by this push:
new 6590127af Update parse error message
6590127af is described below
commit 6590127afe09aaa5a8bcffa4296fa6ec852d0ebe
Author: Mike McGann <[email protected]>
AuthorDate: Wed Mar 15 10:41:41 2023 -0400
Update parse error message
When there are not enough bits for parsing, an error message will be
displayed showing the number of bits available. Sometimes this value uses
the number of bits remaining in the limit and doesn't consider that this
could be greater than the number of bits actually available in the data
stream. This change selects the lesser of the two values when that
information is known.
The TDML runner has also been updated to only place a limit on the parser
when the length of the document under test doesn't end on a byte boundary.
DAFFODIL-2645
---
.../main/scala/org/apache/daffodil/cli/Main.scala | 4 +-
.../daffodil/io/DataInputStreamImplMixin.scala | 11 ----
.../daffodil/io/DataOutputStreamImplMixin.scala | 5 --
.../org/apache/daffodil/io/DataStreamCommon.scala | 8 ---
.../scala/org/apache/daffodil/io/InputSource.scala | 10 +--
.../daffodil/io/InputSourceDataInputStream.scala | 11 +++-
.../runtime1/processors/PackedBinaryTraits.scala | 4 +-
.../processors/parsers/BinaryBooleanParsers.scala | 2 +-
.../processors/parsers/BinaryNumberParsers.scala | 8 +--
.../processors/parsers/BlobLengthParsers.scala | 13 +---
.../parsers/HexBinaryLengthParsers.scala | 2 +-
.../processors/parsers/LayeredSequenceParser.scala | 2 -
.../runtime1/processors/parsers/Parser.scala | 73 ++++++++++++++++++----
.../processors/parsers/PrimitivesDateTime1.scala | 2 +-
.../parsers/SpecifiedLengthParsers.scala | 4 +-
.../processor/tdml/DaffodilTDMLDFDLProcessor.scala | 17 +++--
.../daffodil/section05/simple_types/Blobs.tdml | 34 +++++++++-
.../section12/lengthKind/ExplicitTests.tdml | 53 +++++++++++++++-
.../section05/simple_types/TestBlobs.scala | 4 ++
.../lengthKind/TestLengthKindExplicit.scala | 8 +++
20 files changed, 197 insertions(+), 78 deletions(-)
diff --git a/daffodil-cli/src/main/scala/org/apache/daffodil/cli/Main.scala
b/daffodil-cli/src/main/scala/org/apache/daffodil/cli/Main.scala
index ee5139f2b..26141b797 100644
--- a/daffodil-cli/src/main/scala/org/apache/daffodil/cli/Main.scala
+++ b/daffodil-cli/src/main/scala/org/apache/daffodil/cli/Main.scala
@@ -1138,7 +1138,7 @@ class Main(
if (loc.bitLimit0b.isDefined) {
(loc.bitLimit0b.get - loc.bitPos0b).toString
} else {
- "at least " + (inStream.inputSource.bytesAvailable *
8)
+ "at least " +
(inStream.inputSource.knownBytesAvailable * 8)
}
Logger.log.error(
s"Left over data after consuming 0 bits while
streaming. Stopped after consuming ${loc.bitPos0b} bit(s) with ${remainingBits}
bit(s) remaining.",
@@ -1176,7 +1176,7 @@ class Main(
dumpString
} else ""
val curBytePosition1b = inStream.inputSource.position + 1
- val bytesAvailable = inStream.inputSource.bytesAvailable
+ val bytesAvailable =
inStream.inputSource.knownBytesAvailable
val bytesLimit = math.min(8, bytesAvailable).toInt
val destArray = new Array[Byte](bytesLimit)
val destArrayFilled = inStream.inputSource.get(destArray,
0, bytesLimit)
diff --git
a/daffodil-io/src/main/scala/org/apache/daffodil/io/DataInputStreamImplMixin.scala
b/daffodil-io/src/main/scala/org/apache/daffodil/io/DataInputStreamImplMixin.scala
index c4dcd8254..045eef054 100644
---
a/daffodil-io/src/main/scala/org/apache/daffodil/io/DataInputStreamImplMixin.scala
+++
b/daffodil-io/src/main/scala/org/apache/daffodil/io/DataInputStreamImplMixin.scala
@@ -18,7 +18,6 @@
package org.apache.daffodil.io
import org.apache.daffodil.lib.exceptions.Assert
-import org.apache.daffodil.lib.util.MaybeULong
trait DataInputStreamImplMixin
extends DataInputStream
@@ -45,14 +44,4 @@ trait DataInputStreamImplMixin
skip(deltaBits, finfo)
}
- final override def remainingBits = {
- if (this.bitLimit0b.isEmpty) MaybeULong.Nope
- else {
- val lim = bitLimit0b.get
- Assert.invariant(lim >= 0)
- val nBits = lim - bitPos0b
- MaybeULong(nBits)
- }
- }
-
}
diff --git
a/daffodil-io/src/main/scala/org/apache/daffodil/io/DataOutputStreamImplMixin.scala
b/daffodil-io/src/main/scala/org/apache/daffodil/io/DataOutputStreamImplMixin.scala
index 6ead5579b..4aeb4a792 100644
---
a/daffodil-io/src/main/scala/org/apache/daffodil/io/DataOutputStreamImplMixin.scala
+++
b/daffodil-io/src/main/scala/org/apache/daffodil/io/DataOutputStreamImplMixin.scala
@@ -313,11 +313,6 @@ trait DataOutputStreamImplMixin
*/
var bitStartOffset0b: Int = 0
- final override def remainingBits: MaybeULong = {
- if (maybeRelBitLimit0b.isEmpty) MaybeULong.Nope
- else MaybeULong(maybeRelBitLimit0b.get - relBitPos0b.toLong)
- }
-
var debugOutputStream: Maybe[ByteArrayOutputStream] = Nope
/**
diff --git
a/daffodil-io/src/main/scala/org/apache/daffodil/io/DataStreamCommon.scala
b/daffodil-io/src/main/scala/org/apache/daffodil/io/DataStreamCommon.scala
index f4056f86c..474aa247c 100644
--- a/daffodil-io/src/main/scala/org/apache/daffodil/io/DataStreamCommon.scala
+++ b/daffodil-io/src/main/scala/org/apache/daffodil/io/DataStreamCommon.scala
@@ -19,8 +19,6 @@ package org.apache.daffodil.io
import java.nio.ByteBuffer
-import org.apache.daffodil.lib.util.MaybeULong
-
/**
* This is an interface trait, and it defines methods shared by
* both DataInputStream and DataOutputStream.
@@ -30,12 +28,6 @@ import org.apache.daffodil.lib.util.MaybeULong
*/
trait DataStreamCommon {
- /**
- * Returns number of bits remaining (if a limit is defined). Nope if not
defined.
- */
-
- def remainingBits: MaybeULong
-
/*
* Methods for moving through data.
*/
diff --git
a/daffodil-io/src/main/scala/org/apache/daffodil/io/InputSource.scala
b/daffodil-io/src/main/scala/org/apache/daffodil/io/InputSource.scala
index e3da0cb78..141049ecd 100644
--- a/daffodil-io/src/main/scala/org/apache/daffodil/io/InputSource.scala
+++ b/daffodil-io/src/main/scala/org/apache/daffodil/io/InputSource.scala
@@ -116,9 +116,9 @@ abstract class InputSource {
*
* This should not be used to determine the length of the data, as more bytes
* may become available in the future. This should really only be used for
- * debug purposes.
+ * debug or diagnostic purposes.
*/
- def bytesAvailable(): Long
+ def knownBytesAvailable(): Long
/**
* Return a single byte at the current byte position with a value in the
@@ -396,7 +396,7 @@ class BucketingInputSource(
* Calculate how many bytes are currently buffered starting from the current
* position
*/
- def bytesAvailable(): Long = {
+ def knownBytesAvailable(): Long = {
var available = 0L
val (curBucketIndex, curByteIndex) =
bytePositionToIndicies(curBytePosition0b)
@@ -528,7 +528,7 @@ class BucketingInputSource(
* buckets arraybuffer does not grow too big. This will move all existing
* buckets to the front of the buckets ArrayBuffer and update offsets
* accordingly. This way, there are not a bunch of null empty buckets at the
- * front of the buckets array taking up space.
+ * front of the buckets array taking up space.
*/
def compact(): Unit = {
releaseBuckets()
@@ -559,7 +559,7 @@ class ByteBufferInputSource(byteBuffer: ByteBuffer) extends
InputSource {
bb.remaining >= nBytes
}
- def bytesAvailable(): Long = {
+ def knownBytesAvailable(): Long = {
bb.remaining
}
diff --git
a/daffodil-io/src/main/scala/org/apache/daffodil/io/InputSourceDataInputStream.scala
b/daffodil-io/src/main/scala/org/apache/daffodil/io/InputSourceDataInputStream.scala
index 024e5cd5c..e745d348f 100644
---
a/daffodil-io/src/main/scala/org/apache/daffodil/io/InputSourceDataInputStream.scala
+++
b/daffodil-io/src/main/scala/org/apache/daffodil/io/InputSourceDataInputStream.scala
@@ -128,6 +128,15 @@ final class InputSourceDataInputStream private (val
inputSource: InputSource)
*/
def hasReachedEndOfData: Boolean = inputSource.hasReachedEndOfData
+ /**
+ * Return the number of currently available bytes.
+ *
+ * This should not be used to determine the length of the data, as more bytes
+ * may become available in the future. This should really only be used for
+ * debug or diagnostic purposes.
+ */
+ def knownBytesAvailable: Long = inputSource.knownBytesAvailable
+
def setBitPos0b(newBitPos0b: Long): Unit = {
// threadCheck()
Assert.invariant(newBitPos0b >= 0)
@@ -789,7 +798,7 @@ final class InputSourceDataInputStream private (val
inputSource: InputSource)
// need to call areBytesAvailable first to ensure at least length bytes are
// buffered if they exist
val available = inputSource.areBytesAvailable(nBytesRequested)
- val bytesToRead = if (available) nBytesRequested else
inputSource.bytesAvailable.toInt
+ val bytesToRead = if (available) nBytesRequested else
inputSource.knownBytesAvailable.toInt
val array = new Array[Byte](bytesToRead)
inputSource.get(array, 0, bytesToRead)
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 09e8a2c1e..608ec58e9 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
@@ -55,7 +55,7 @@ abstract class PackedBinaryDecimalBaseParser(
val dis = start.dataInputStream
if (!dis.isDefinedForLength(nBits)) {
- PENotEnoughBits(start, nBits, dis.remainingBits)
+ PENotEnoughBits(start, nBits, dis)
return
}
@@ -83,7 +83,7 @@ abstract class PackedBinaryIntegerBaseParser(
val dis = start.dataInputStream
if (!dis.isDefinedForLength(nBits)) {
- PENotEnoughBits(start, nBits, dis.remainingBits)
+ PENotEnoughBits(start, nBits, dis)
return
}
diff --git
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/BinaryBooleanParsers.scala
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/BinaryBooleanParsers.scala
index c69f45d21..c92f8d339 100644
---
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/BinaryBooleanParsers.scala
+++
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/BinaryBooleanParsers.scala
@@ -62,7 +62,7 @@ abstract class BinaryBooleanParserBase(
val dis = start.dataInputStream
if (!dis.isDefinedForLength(nBits)) {
- PENotEnoughBits(start, nBits, dis.remainingBits)
+ PENotEnoughBits(start, nBits, dis)
return
}
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 60da09183..c546cbe72 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
@@ -36,7 +36,7 @@ class BinaryFloatParser(override val context:
ElementRuntimeData) extends PrimPa
val dis = start.dataInputStream
if (!dis.isDefinedForLength(32)) {
- PENotEnoughBits(start, 32, dis.remainingBits)
+ PENotEnoughBits(start, 32, dis)
return
}
@@ -52,7 +52,7 @@ class BinaryDoubleParser(override val context:
ElementRuntimeData) extends PrimP
val dis = start.dataInputStream
if (!dis.isDefinedForLength(64)) {
- PENotEnoughBits(start, 64, dis.remainingBits)
+ PENotEnoughBits(start, 64, dis)
return
}
@@ -109,7 +109,7 @@ abstract class BinaryDecimalParserBase(
val nBits = getBitLength(start)
val dis = start.dataInputStream
if (!dis.isDefinedForLength(nBits)) {
- PENotEnoughBits(start, nBits, dis.remainingBits)
+ PENotEnoughBits(start, nBits, dis)
return
}
@@ -179,7 +179,7 @@ abstract class BinaryIntegerBaseParser(
}
val dis = start.dataInputStream
if (!dis.isDefinedForLength(nBits)) {
- PENotEnoughBits(start, nBits, dis.remainingBits)
+ PENotEnoughBits(start, nBits, dis)
return
}
diff --git
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/BlobLengthParsers.scala
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/BlobLengthParsers.scala
index 4fb5d367d..32c106606 100644
---
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/BlobLengthParsers.scala
+++
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/BlobLengthParsers.scala
@@ -20,7 +20,6 @@ package org.apache.daffodil.runtime1.processors.parsers
import java.nio.file.Files
import java.nio.file.StandardOpenOption
-import org.apache.daffodil.lib.util.MaybeULong
import org.apache.daffodil.runtime1.processors.ElementRuntimeData
import org.apache.daffodil.runtime1.processors.LengthInBitsEv
@@ -37,10 +36,11 @@ trait ByteChunkWriter { self: PrimParser =>
writeChunk: (Array[Byte], Int) => Unit,
): Unit = {
val dis = start.dataInputStream
+ val startLoc = start.currentLocation
+ val startSfl = start.schemaFileLocation
var remainingBitsToGet = nBits
val array = new Array[Byte](start.tunable.blobChunkSizeInBytes)
-
// Tunable restrictions ensure blobChunkSizeInBits still fits in an int.
// All the places where toInt is called below can be no larger than this
// value, and so have no issues with potential overflow.
@@ -54,14 +54,7 @@ trait ByteChunkWriter { self: PrimParser =>
writeChunk(array, bytesToPut.toInt)
remainingBitsToGet -= bitsToGet
} else {
- val remainingBits =
- if (dis.remainingBits.isDefined) {
- val totalBitsRead = nBits - remainingBitsToGet
- MaybeULong(dis.remainingBits.get + totalBitsRead)
- } else {
- MaybeULong.Nope
- }
- self.PENotEnoughBits(start, nBits, remainingBits)
+ PENotEnoughBits(start, startSfl, startLoc, nBits,
start.dataInputStream)
remainingBitsToGet = 0 // break out of the loop
}
}
diff --git
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/HexBinaryLengthParsers.scala
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/HexBinaryLengthParsers.scala
index ee6b5d61a..1e8ddf163 100644
---
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/HexBinaryLengthParsers.scala
+++
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/HexBinaryLengthParsers.scala
@@ -52,7 +52,7 @@ sealed abstract class HexBinaryLengthParser(override val
context: ElementRuntime
// create and fill the byte array
val dis = start.dataInputStream
if (!dis.isDefinedForLength(nBits)) {
- PENotEnoughBits(start, nBits, dis.remainingBits)
+ PENotEnoughBits(start, nBits, dis)
} else {
val array = start.dataInputStream.getByteArray(nBits.toInt, start)
currentElement.setDataValue(array)
diff --git
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/LayeredSequenceParser.scala
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/LayeredSequenceParser.scala
index 18f181f0d..25cc5c06b 100644
---
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/LayeredSequenceParser.scala
+++
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/LayeredSequenceParser.scala
@@ -17,7 +17,6 @@
package org.apache.daffodil.runtime1.processors.parsers
-import org.apache.daffodil.lib.util.MaybeULong
import org.apache.daffodil.runtime1.layers.LayerExecutionException
import org.apache.daffodil.runtime1.layers.LayerNotEnoughDataException
import org.apache.daffodil.runtime1.layers.LayerRuntimeInfo
@@ -62,7 +61,6 @@ class LayeredSequenceParser(
le.schemaFileLocation,
le.dataLocation,
le.nBytesRequired * 8,
- MaybeULong.Nope,
)
case e: Exception =>
throw LayerExecutionException(
diff --git
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/Parser.scala
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/Parser.scala
index d546b0869..d67548535 100644
---
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/Parser.scala
+++
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/Parser.scala
@@ -18,13 +18,13 @@
package org.apache.daffodil.runtime1.processors.parsers
import org.apache.daffodil.io.BacktrackingException
+import org.apache.daffodil.io.InputSourceDataInputStream
import org.apache.daffodil.lib.api.DataLocation
import org.apache.daffodil.lib.api.Diagnostic
import org.apache.daffodil.lib.exceptions.Assert
import org.apache.daffodil.lib.exceptions.SchemaFileLocation
import org.apache.daffodil.lib.util.Maybe.One
-import org.apache.daffodil.lib.util.MaybeULong
-import org.apache.daffodil.lib.util.Misc
+import org.apache.daffodil.lib.util.{ MaybeULong, Misc }
import org.apache.daffodil.runtime1.dsom.RuntimeSchemaDefinitionError
import org.apache.daffodil.runtime1.processors.CombinatorProcessor
import org.apache.daffodil.runtime1.processors.ElementRuntimeData
@@ -65,10 +65,49 @@ sealed trait Parser extends Processor {
pstate.setFailed(new ParseError(One(sfl), One(dataLoc), s, args: _*))
}
- def PENotEnoughBits(pstate: PState, neededBits: Long, remainingBits:
MaybeULong) = {
- val remainingStr =
- if (remainingBits.isDefined) s" but found only ${remainingBits.get}
available" else ""
- PE(pstate, "Insufficient bits in data. Needed %d bit(s)%s.", neededBits,
remainingStr)
+ def PENotEnoughBits(
+ pstate: PState,
+ sfl: SchemaFileLocation,
+ dataLoc: DataLocation,
+ neededBits: Long,
+ source: InputSourceDataInputStream,
+ ): Unit = {
+ val startPos = dataLoc.bitPos1b - 1
+ val remainingLimitedBits = {
+ if (source.bitLimit0b.isEmpty) MaybeULong.Nope
+ else {
+ val lim = source.bitLimit0b.get
+ Assert.invariant(lim >= 0)
+ val nBits = lim - startPos
+ MaybeULong(nBits)
+ }
+ }
+ val remainingBits = {
+ if (source.hasReachedEndOfData) {
+ val bitsAvailable = {
+ val fragmentBitsReadFromSourcePos = source.bitPos0b % 8
+ val bitsAvailableFromSourcePos =
+ source.knownBytesAvailable * 8 - fragmentBitsReadFromSourcePos
+ val bitsBetweenStartPosAndSourcePos = source.bitPos0b - startPos
+ val bitsAvailableFromStartPos =
+ bitsAvailableFromSourcePos + bitsBetweenStartPosAndSourcePos
+ bitsAvailableFromStartPos
+ }
+ if (remainingLimitedBits.isEmpty || bitsAvailable <
remainingLimitedBits.get)
+ bitsAvailable
+ else
+ remainingLimitedBits.get
+ } else remainingLimitedBits.get
+ }
+
+ PE(
+ pstate,
+ sfl,
+ dataLoc,
+ "Insufficient bits in data. Needed %d bit(s) but found only %d
available",
+ neededBits,
+ remainingBits,
+ )
}
def PENotEnoughBits(
@@ -76,17 +115,27 @@ sealed trait Parser extends Processor {
sfl: SchemaFileLocation,
dataLoc: DataLocation,
neededBits: Long,
- remainingBits: MaybeULong,
- ) = {
- val remainingStr =
- if (remainingBits.isDefined) s" but found only ${remainingBits.get}
available" else ""
+ ): Unit = {
PE(
pstate,
sfl,
dataLoc,
- "Insufficient bits in data. Needed %d bit(s)%s.",
+ "Insufficient bits in data. Needed %d bit(s)",
+ neededBits,
+ )
+ }
+
+ def PENotEnoughBits(
+ pstate: PState,
+ neededBits: Long,
+ source: InputSourceDataInputStream,
+ ): Unit = {
+ PENotEnoughBits(
+ pstate,
+ pstate.schemaFileLocation,
+ pstate.currentLocation,
neededBits,
- remainingStr,
+ source,
)
}
diff --git
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/PrimitivesDateTime1.scala
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/PrimitivesDateTime1.scala
index d075fe223..729fb42b3 100644
---
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/PrimitivesDateTime1.scala
+++
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/PrimitivesDateTime1.scala
@@ -203,7 +203,7 @@ case class ConvertBinaryCalendarSecMilliParser(
val dis = start.dataInputStream
if (!dis.isDefinedForLength(lengthInBits)) {
- PENotEnoughBits(start, lengthInBits, dis.remainingBits)
+ PENotEnoughBits(start, lengthInBits, dis)
return
}
diff --git
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/SpecifiedLengthParsers.scala
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/SpecifiedLengthParsers.scala
index 94f9145ee..07f6c1bde 100644
---
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/SpecifiedLengthParsers.scala
+++
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/SpecifiedLengthParsers.scala
@@ -67,7 +67,7 @@ sealed abstract class SpecifiedLengthParserBase(eParser:
Parser, erd: RuntimeDat
}
if (shouldCheckDefinedForLength && !dis.isDefinedForLength(nBits)) {
- PENotEnoughBits(pState, nBits, dis.remainingBits)
+ PENotEnoughBits(pState, nBits, dis)
return
}
@@ -96,7 +96,7 @@ sealed abstract class SpecifiedLengthParserBase(eParser:
Parser, erd: RuntimeDat
// skip left over bits
val skipSuccess = dis.skip(bitsToSkip, pState)
if (!skipSuccess) {
- PENotEnoughBits(pState, bitsToSkip, dis.remainingBits)
+ PENotEnoughBits(pState, bitsToSkip, dis)
}
}
}
diff --git
a/daffodil-tdml-processor/src/main/scala/org/apache/daffodil/processor/tdml/DaffodilTDMLDFDLProcessor.scala
b/daffodil-tdml-processor/src/main/scala/org/apache/daffodil/processor/tdml/DaffodilTDMLDFDLProcessor.scala
index 8290b9336..6bf60ebfc 100644
---
a/daffodil-tdml-processor/src/main/scala/org/apache/daffodil/processor/tdml/DaffodilTDMLDFDLProcessor.scala
+++
b/daffodil-tdml-processor/src/main/scala/org/apache/daffodil/processor/tdml/DaffodilTDMLDFDLProcessor.scala
@@ -269,13 +269,6 @@ class DaffodilTDMLDFDLProcessor private (private var dp:
DataProcessor)
saxInputStream: java.io.InputStream,
lengthLimitInBits: Long,
): TDMLParseResult = {
- //
- // TDML Tests MUST have a length limit. Otherwise they cannot determine if
- // there is left-over-data or not without doing more reading from the
input stream
- // so as to be sure to hit end-of-data.
- //
- Assert.usage(lengthLimitInBits >= 0)
-
val outputter = new TDMLInfosetOutputter()
outputter.setBlobAttributes(blobDir, blobPrefix, blobSuffix)
@@ -293,8 +286,14 @@ class DaffodilTDMLDFDLProcessor private (private var dp:
DataProcessor)
val dis = InputSourceDataInputStream(dpInputStream)
val sis = InputSourceDataInputStream(saxInputStream)
- dis.setBitLimit0b(MaybeULong(lengthLimitInBits))
- sis.setBitLimit0b(MaybeULong(lengthLimitInBits))
+ // The length limit here should be the length of the document
+ // under test. Only set a limit when the end of the document
+ // do not match a byte boundary.
+ if (lengthLimitInBits % 8 != 0) {
+ Assert.usage(lengthLimitInBits >= 0)
+ dis.setBitLimit0b(MaybeULong(lengthLimitInBits))
+ sis.setBitLimit0b(MaybeULong(lengthLimitInBits))
+ }
val actual = dp.parse(dis, outputter)
xri.parse(sis)
diff --git
a/daffodil-test/src/test/resources/org/apache/daffodil/section05/simple_types/Blobs.tdml
b/daffodil-test/src/test/resources/org/apache/daffodil/section05/simple_types/Blobs.tdml
index a71090adf..b5c982238 100644
---
a/daffodil-test/src/test/resources/org/apache/daffodil/section05/simple_types/Blobs.tdml
+++
b/daffodil-test/src/test/resources/org/apache/daffodil/section05/simple_types/Blobs.tdml
@@ -48,6 +48,16 @@
dfdl:lengthKind="explicit" dfdl:length="4"
dfdlx:objectKind="bytes" />
+ <xs:element name="blob_01_complex" dfdl:lengthKind="explicit"
dfdl:length="8">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="blob_01" type="xs:anyURI"
+ dfdl:lengthKind="explicit" dfdl:length="4"
+ dfdlx:objectKind="bytes" />
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
<xs:element name="blob_02" type="xs:anyURI"
dfdl:lengthKind="explicit" dfdl:length="30" dfdl:lengthUnits="bits"
dfdl:bitOrder="mostSignificantBitFirst"
@@ -145,7 +155,29 @@
</tdml:dfdlInfoset>
</tdml:infoset>
</tdml:parserTestCase>
-
+
+ <tdml:parserTestCase name="blob_01_insufficient" root="blob_01"
model="Blob.dfdl.xsd">
+ <tdml:document>
+ <tdml:documentPart type="byte"><![CDATA[a1b1c1]]></tdml:documentPart>
+ <tdml:documentPart type="bits">1</tdml:documentPart>
+ </tdml:document>
+ <tdml:errors>
+ <tdml:error>Needed 32 bit(s)</tdml:error>
+ <tdml:error>found only 25</tdml:error>
+ </tdml:errors>
+ </tdml:parserTestCase>
+
+ <tdml:parserTestCase name="blob_01_insufficient_complex"
root="blob_01_complex" model="Blob.dfdl.xsd">
+ <tdml:document>
+ <tdml:documentPart type="byte"><![CDATA[a1b1c1]]></tdml:documentPart>
+ <tdml:documentPart type="bits">1</tdml:documentPart>
+ </tdml:document>
+ <tdml:errors>
+ <tdml:error>Needed 64 bit(s)</tdml:error>
+ <tdml:error>found only 25</tdml:error>
+ </tdml:errors>
+ </tdml:parserTestCase>
+
<!-- 30 bits of blob data, MSBF -->
<tdml:parserTestCase name="blob_02" root="blob_02" model="Blob.dfdl.xsd">
<tdml:document>
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 b9facca16..613d559ee 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
@@ -605,7 +605,8 @@
<tdml:documentPart type="text"><![CDATA[000118Ridgewood Circle
Rochester NY123]]></tdml:documentPart>
</tdml:document>
<tdml:errors>
- <tdml:error>6467715464</tdml:error>
+ <tdml:error>Needed 16</tdml:error>
+ <tdml:error>found only 8</tdml:error>
<tdml:error>insufficient</tdml:error>
<tdml:error>parse error</tdml:error>
</tdml:errors>
@@ -1338,4 +1339,54 @@
</tdml:errors>
</tdml:parserTestCase>
+ <tdml:defineSchema name="insufficientBits">
+ <xs:include
schemaLocation="org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>
+ <dfdl:format ref="ex:GeneralFormat"
+ representation="binary"
+ alignment="1"
+ alignmentUnits="bits"
+ />
+
+ <xs:element name="complex" dfdl:lengthKind="explicit" dfdl:length="16">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="child" type="xs:int" dfdl:lengthKind="explicit"
dfdl:length="4" />
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="nineBits" dfdl:lengthKind="explicit" dfdl:length="2">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="bit" type="xs:int" dfdl:lengthKind="explicit"
dfdl:lengthUnits="bits" dfdl:length="1"/>
+ <xs:element name="byte" type="xs:int" dfdl:lengthKind="explicit"
dfdl:lengthUnits="bits" dfdl:length="8"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </tdml:defineSchema>
+
+ <tdml:parserTestCase name="insufficientBitsComplex" root="complex"
model="insufficientBits"
+ description="Tests that we get the correct error
message when there are not enough bits remaining in the stream">
+ <tdml:document>
+ <tdml:documentPart type="byte">
+ 12 34
+ </tdml:documentPart>
+ </tdml:document>
+ <tdml:errors>
+ <tdml:error>32 bit(s) but found only 16</tdml:error>
+ </tdml:errors>
+ </tdml:parserTestCase>
+
+ <tdml:parserTestCase name="insufficientBitsByte" root="nineBits"
model="insufficientBits"
+ description="Tests that we get the correct error
message when there are not enough bits remaining in the stream when unaligned">
+ <tdml:document>
+ <tdml:documentPart type="byte">
+ ff
+ </tdml:documentPart>
+ </tdml:document>
+ <tdml:errors>
+ <tdml:error>8 bit(s) but found only 7</tdml:error>
+ </tdml:errors>
+ </tdml:parserTestCase>
+
</tdml:testSuite>
diff --git
a/daffodil-test/src/test/scala/org/apache/daffodil/section05/simple_types/TestBlobs.scala
b/daffodil-test/src/test/scala/org/apache/daffodil/section05/simple_types/TestBlobs.scala
index 13b75726a..f450dd25f 100644
---
a/daffodil-test/src/test/scala/org/apache/daffodil/section05/simple_types/TestBlobs.scala
+++
b/daffodil-test/src/test/scala/org/apache/daffodil/section05/simple_types/TestBlobs.scala
@@ -37,6 +37,10 @@ class TestBlobs {
import TestBlobs._
@Test def test_blob_01(): Unit = { runner.runOneTest("blob_01") }
+ @Test def test_blob_01_insufficient(): Unit = {
runner.runOneTest("blob_01_insufficient") }
+ @Test def test_blob_01_insufficient_complex(): Unit = {
+ runner.runOneTest("blob_01_insufficient_complex")
+ }
@Test def test_blob_02(): Unit = { runner.runOneTest("blob_02") }
@Test def test_blob_03(): Unit = { runner.runOneTest("blob_03") }
@Test def test_blob_04(): Unit = { runner.runOneTest("blob_04") }
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 c5df7b6b3..e85cabf01 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
@@ -153,4 +153,12 @@ class TestLengthKindExplicit {
@Test def test_invalidByteBitLengthExpr(): Unit = {
runner.runOneTest("invalidByteBitLengthExpr")
}
+
+ @Test def test_insufficientBitsComplex(): Unit = {
+ runner.runOneTest("insufficientBitsComplex")
+ }
+
+ @Test def test_insufficientBitsByte(): Unit = {
+ runner.runOneTest("insufficientBitsByte")
+ }
}