stevedlawrence commented on code in PR #988:
URL: https://github.com/apache/daffodil/pull/988#discussion_r1143268255


##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/Parser.scala:
##########
@@ -65,12 +66,51 @@ sealed trait Parser extends Processor {
     pstate.setFailed(new ParseError(One(sfl), One(dataLoc), s, args: _*))
   }
 
-  def PENotEnoughBits(pstate: PState, neededBits: Long, remainingBits: 
MaybeULong) = {
+  def PENotEnoughBits(
+    pstate: PState,
+    neededBits: Long,
+    startPos: Long,
+    source: InputSourceDataInputStream,
+  ): Unit = {
+    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 = {
+          if (startPos % 8 == 0)
+            source.knownBytesAvailable * 8
+          else {
+            source.knownBytesAvailable * 8 - (startPos % 8)
+          }
+        }
+        if (remainingLimitedBits.isEmpty || bitsAvailable < 
remainingLimitedBits.get)
+          MaybeULong(bitsAvailable)
+        else
+          remainingLimitedBits
+      } else remainingLimitedBits
+    }
+
     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,
+    neededBits: Long,
+    source: InputSourceDataInputStream,
+  ): Unit = {
+    PENotEnoughBits(pstate, neededBits, source.bitPos0b, source)
+  }
+
   def PENotEnoughBits(

Review Comment:
   I'd suggest the blobs should use this `PENotEnoughBits` (and modify it to 
have the remaining bits logic) and pass in a `DataLocation` saved from the 
beginning of the  blob parsing before it started reading chunks. And then the 
remaining bits logic could adjust bits based on the difference between 
`DataLocation.bitPos1b - 1` and `pstate.bitPos0b`.  We'll also want to modify 
this to call the `PE` function that accepts a `DataLocation` so the 
`ParseError` uses the saved `DataLocation` instead of the one from the 
`pstate`. This way the generated diagnostics has he correct bitPosition at the 
beginning of the blob.
   
   The above `PENotENoughBits` that everything else uses can then just call 
this one, passing in `pstate.currentLocation` as the `DataLocation`. In that 
case the difference between `DataLocation.bitPos1b - 1` and `pstate.bitPos0b` 
will be zero, so the adjusting logic just won't change anything.



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/Parser.scala:
##########
@@ -65,12 +66,51 @@ sealed trait Parser extends Processor {
     pstate.setFailed(new ParseError(One(sfl), One(dataLoc), s, args: _*))
   }
 
-  def PENotEnoughBits(pstate: PState, neededBits: Long, remainingBits: 
MaybeULong) = {
+  def PENotEnoughBits(
+    pstate: PState,
+    neededBits: Long,
+    startPos: Long,
+    source: InputSourceDataInputStream,
+  ): Unit = {
+    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 = {
+          if (startPos % 8 == 0)
+            source.knownBytesAvailable * 8
+          else {
+            source.knownBytesAvailable * 8 - (startPos % 8)
+          }
+        }

Review Comment:
   I personally find this hard to read. I think it would be more clear to split 
it up, something like:
   ```scala
   val fragmentBitsRead = startPos % 8
   val bitsAvailable = (source.knownBytesAvailable * 8) - fragmentBitsRead
   ```



##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/Parser.scala:
##########
@@ -65,12 +66,51 @@ sealed trait Parser extends Processor {
     pstate.setFailed(new ParseError(One(sfl), One(dataLoc), s, args: _*))
   }
 
-  def PENotEnoughBits(pstate: PState, neededBits: Long, remainingBits: 
MaybeULong) = {
+  def PENotEnoughBits(
+    pstate: PState,
+    neededBits: Long,
+    startPos: Long,
+    source: InputSourceDataInputStream,
+  ): Unit = {
+    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 = {
+          if (startPos % 8 == 0)
+            source.knownBytesAvailable * 8
+          else {
+            source.knownBytesAvailable * 8 - (startPos % 8)
+          }
+        }
+        if (remainingLimitedBits.isEmpty || bitsAvailable < 
remainingLimitedBits.get)
+          MaybeULong(bitsAvailable)
+        else
+          remainingLimitedBits
+      } else remainingLimitedBits
+    }
+
     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)

Review Comment:
   I think this still suffers from a previous comment. If data was chunked, 
this call to `PE` will use `DataLocation` from the `pstate`, which could be too 
far forward in the data (i.e.  where the last successful chunk finished, 
instead of where the blob started actually reading). And `reaminigStr` is going 
to only say the amount of bits remaining after the last successful chunk was 
read.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to