You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@daffodil.apache.org by mb...@apache.org on 2022/02/15 18:49:36 UTC

[daffodil] branch main updated: dfdl:contentLength and valueLength for prefixed

This is an automated email from the ASF dual-hosted git repository.

mbeckerle 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 575a4c6  dfdl:contentLength and valueLength for prefixed
575a4c6 is described below

commit 575a4c6ff9fcadb8eff733ba693b831de4156201
Author: Michael Beckerle <mb...@apache.org>
AuthorDate: Mon Feb 14 13:38:00 2022 -0500

    dfdl:contentLength and valueLength for prefixed
    
    For lengthKind prefixed and complex types,
    captures the content and value lengths.
    For simple types captures the content length.
    
    valueLength for simpleTypes unchanged.
    
    Added test cases for complex types and
    contentLength for simple types.
    
    Test added showing prefixed + valueLength for
    simple values with trimming of pad-char does
    NOT work (DAFFODIL-2658)
    
    Tests added to improve coverage of prefixed
    length corner cases around lengthUnits
    'characters' and utf-8/variable-width encodings.
    
    Rename maybeComputedLength to reflect "InBits" units.
    
    DAFFODIL-2656, DAFFODIL-2657, DAFFODIL-2658
---
 .../daffodil/grammar/ElementBaseGrammarMixin.scala |   4 +-
 .../grammar/primitives/SpecifiedLength.scala       |  27 +-
 .../processors/unparsers/SpecifiedLength2.scala    |   2 +-
 .../unparsers/SpecifiedLengthUnparsers.scala       |  22 +-
 .../org/apache/daffodil/infoset/InfosetImpl.scala  |  14 +-
 .../processors/parsers/BinaryNumberTraits.scala    |  28 +-
 .../section12/lengthKind/PrefixedTests.tdml        | 385 +++++++++++++++++++++
 .../lengthKind/TestLengthKindPrefixed.scala        |  17 +
 8 files changed, 472 insertions(+), 27 deletions(-)

diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/grammar/ElementBaseGrammarMixin.scala b/daffodil-core/src/main/scala/org/apache/daffodil/grammar/ElementBaseGrammarMixin.scala
index a9b3a3b..4e6e9f7 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/grammar/ElementBaseGrammarMixin.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/grammar/ElementBaseGrammarMixin.scala
@@ -198,7 +198,7 @@ trait ElementBaseGrammarMixin
         case LengthKind.Explicit => pl.lengthEv.optConstant.get // already in lengthUnits when explicit
         case LengthKind.Implicit =>
           Assert.invariant(impliedRepresentation == Representation.Binary)
-          val len = pl.lengthEv.optConstant.get // always in bits when implicit
+          val len = pl.implicitBinaryLengthInBits
           pl.lengthUnits match {
             case LengthUnits.Bits => len
             case LengthUnits.Bytes => len / 8
@@ -1071,7 +1071,7 @@ trait ElementBaseGrammarMixin
         Assert.invariant(lengthUnits eq LengthUnits.Characters)
         new SpecifiedLengthExplicitCharacters(this, body)
       }
-      case LengthKind.Prefixed if bitsMultiplier != 0 =>
+      case LengthKind.Prefixed if (bitsMultiplier != 0) =>
         new SpecifiedLengthPrefixed(this, body, bitsMultiplier)
       case LengthKind.Prefixed => {
         Assert.invariant(!knownEncodingIsFixedWidth)
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/SpecifiedLength.scala b/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/SpecifiedLength.scala
index c603c4f..8aec092 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/SpecifiedLength.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/SpecifiedLength.scala
@@ -29,6 +29,7 @@ import org.apache.daffodil.processors.parsers.SpecifiedLengthExplicitParser
 import org.apache.daffodil.processors.parsers.SpecifiedLengthImplicitParser
 import org.apache.daffodil.dpath.NodeInfo.PrimType
 import org.apache.daffodil.processors.parsers.Parser
+import org.apache.daffodil.schema.annotation.props.gen.LengthUnits
 
 abstract class SpecifiedLengthCombinatorBase(val e: ElementBase, eGramArg: => Gram)
   extends Terminal(e, true) {
@@ -163,13 +164,20 @@ class SpecifiedLengthPrefixed(e: ElementBase, eGram: => Gram, bitsMultiplier: In
     e.lengthUnits,
     pladj)
 
-  lazy val unparser: Unparser = new SpecifiedLengthPrefixedUnparser(
-    eUnparser,
-    erd,
-    e.prefixedLengthBody.unparser,
-    plerd,
-    e.lengthUnits,
-    pladj)
+  lazy val unparser: Unparser = {
+    if (e.lengthUnits == LengthUnits.Characters &&
+        e.isComplexType &&
+        !e.encodingInfo.knownEncodingIsFixedWidth)
+      e.subsetError(
+        "Unparsing with dfdl:lengthUnits 'characters' for complex types requires a fixed-width known (constant) encoding.")
+    new SpecifiedLengthPrefixedUnparser(
+      eUnparser,
+      erd,
+      e.prefixedLengthBody.unparser,
+      plerd,
+      e.lengthUnits,
+      pladj)
+  }
 }
 
 class SpecifiedLengthExplicitCharacters(e: ElementBase, eGram: => Gram)
@@ -208,5 +216,8 @@ class SpecifiedLengthPrefixedCharacters(e: ElementBase, eGram: => Gram)
     e.prefixedLengthElementDecl.elementRuntimeData,
     e.prefixedLengthAdjustmentInUnits)
 
-  lazy val unparser: Unparser = Assert.nyi("unparsing with dfdl:lengthKind=\"prefixed\" and dfdl:lengthUnits=\"characters\"")
+  lazy val unparser: Unparser =
+    e.subsetError(
+      """Unparsing with dfdl:lengthKind='prefixed' and dfdl:lengthUnits='characters' and
+        |a non-constant or variable-width encoding is not supported.""".stripMargin)
 }
diff --git a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/SpecifiedLength2.scala b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/SpecifiedLength2.scala
index b871b10..69f92a7 100644
--- a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/SpecifiedLength2.scala
+++ b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/SpecifiedLength2.scala
@@ -827,6 +827,6 @@ class PrefixLengthSuspendableOperation(
 
   override def continuation(state: UState): Unit = {
     val len = elem.valueLength.maybeLengthInBits.isDefined
-    assignPrefixLength(elem, plElem)
+    assignPrefixLength(state, elem, plElem)
   }
 }
diff --git a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/SpecifiedLengthUnparsers.scala b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/SpecifiedLengthUnparsers.scala
index d20085a..7599bbb 100644
--- a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/SpecifiedLengthUnparsers.scala
+++ b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/SpecifiedLengthUnparsers.scala
@@ -36,6 +36,7 @@ import org.apache.daffodil.schema.annotation.props.gen.Representation
 import org.apache.daffodil.util.Maybe
 import org.apache.daffodil.util.Maybe._
 import org.apache.daffodil.util.MaybeJULong
+import passera.unsigned.ULong
 
 /**
  * Restricts the bits available for unparsing to just those within
@@ -361,11 +362,26 @@ trait CalculatedPrefixedLengthUnparserMixin {
    * @param plElem The element to store the length
    * @param lengthUnits The length units (bytes or bits)
    */
-  def assignPrefixLength(elem: DIElement, plElem: DISimple): Unit = {
+  def assignPrefixLength(state: UState, elem: DIElement, plElem: DISimple): Unit = {
     val lenInUnits = lengthUnits match {
       case LengthUnits.Bits => elem.valueLength.lengthInBits
       case LengthUnits.Bytes => elem.valueLength.lengthInBytes
-      case LengthUnits.Characters => ???
+      case LengthUnits.Characters => {
+        val maybeFixedWidth = elem.erd.encInfo.getEncoderInfo(state).coder.bitsCharset.maybeFixedWidth
+        val lengthInChars =
+          if (maybeFixedWidth.isDefined) {
+            val fixedWidth = maybeFixedWidth.get
+            Assert.invariant((elem.valueLength.lengthInBits % fixedWidth) == 0) // divisible
+            elem.valueLength.lengthInBits / fixedWidth
+          } else {
+            // This is checked for statically, so should not get here.
+            // $COVERAGE-OFF$
+            Assert.invariantFailed(
+              "Not supported: prefixed length with variable-width or non-constant encoding.")
+            // $COVERAGE-ON$
+          }
+        ULong(lengthInChars)
+      }
     }
     val adjustedLenInUnits = lenInUnits + prefixedLengthAdjustmentInUnits
     plElem.setDataValue(java.lang.Integer.valueOf(adjustedLenInUnits.toInt))
@@ -414,7 +430,7 @@ class SpecifiedLengthPrefixedUnparser(
       // then just set it as the value of the detached element created above so
       // that when the prefixedLengthUnparser suspension resumes it can unparse
       // the value
-      assignPrefixLength(elem, plElem)
+      assignPrefixLength(state, elem, plElem)
     } else {
       // The length was not able to be calculated, likely because there was a
       // suspension when unparsing the eUnparser. So let's create a new
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/infoset/InfosetImpl.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/infoset/InfosetImpl.scala
index e7f0470..e35ddff 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/infoset/InfosetImpl.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/infoset/InfosetImpl.scala
@@ -383,14 +383,14 @@ sealed abstract class LengthState(ie: DIElement) {
   var maybeStartPos0bInBits: MaybeULong = MaybeULong.Nope
   var maybeEndDataOutputStream: Maybe[DataOutputStream] = Nope
   var maybeEndPos0bInBits: MaybeULong = MaybeULong.Nope
-  var maybeComputedLength: MaybeULong = MaybeULong.Nope
+  var maybeComputedLengthInBits: MaybeULong = MaybeULong.Nope
 
   def copyFrom(other: LengthState): Unit = {
     this.maybeStartDataOutputStream = other.maybeStartDataOutputStream
     this.maybeStartPos0bInBits = other.maybeStartPos0bInBits
     this.maybeEndDataOutputStream = other.maybeEndDataOutputStream
     this.maybeEndPos0bInBits = other.maybeEndPos0bInBits
-    this.maybeComputedLength = other.maybeComputedLength
+    this.maybeComputedLengthInBits = other.maybeComputedLengthInBits
   }
 
   def clear(): Unit = {
@@ -398,7 +398,7 @@ sealed abstract class LengthState(ie: DIElement) {
     maybeStartPos0bInBits = MaybeULong.Nope
     maybeEndDataOutputStream = Nope
     maybeEndPos0bInBits = MaybeULong.Nope
-    maybeComputedLength = MaybeULong.Nope
+    maybeComputedLengthInBits = MaybeULong.Nope
   }
 
   protected def throwUnknown: Nothing
@@ -488,10 +488,10 @@ sealed abstract class LengthState(ie: DIElement) {
   def maybeLengthInBits(): MaybeULong = {
     recheckStreams()
     val computed: MaybeULong = {
-      if (maybeComputedLength.isDefined) {
-        val len = maybeComputedLength.get
+      if (maybeComputedLengthInBits.isDefined) {
+        val len = maybeComputedLengthInBits.get
         Logger.log.debug(s"${flavor}gth of ${ie.name} is ${len}, (was already computed)")
-        return maybeComputedLength
+        return maybeComputedLengthInBits
       } else if (isStartUndef || isEndUndef) {
         Logger.log.debug(s"${flavor}gth of ${ie.name} cannot be computed yet. ${toString}")
         MaybeULong.Nope
@@ -545,7 +545,7 @@ sealed abstract class LengthState(ie: DIElement) {
         MaybeULong.Nope
       }
     }
-    maybeComputedLength = computed
+    maybeComputedLengthInBits = computed
     computed
   }
 
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/BinaryNumberTraits.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/BinaryNumberTraits.scala
index 83c99e3..cd8a424 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/BinaryNumberTraits.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/BinaryNumberTraits.scala
@@ -17,9 +17,9 @@
 
 package org.apache.daffodil.processors.parsers
 
-import java.lang.{ Long => JLong }
-
+import java.lang.{Long => JLong}
 import org.apache.daffodil.exceptions.Assert
+import org.apache.daffodil.infoset.DIComplex
 import org.apache.daffodil.infoset.DISimple
 import org.apache.daffodil.infoset.Infoset
 import org.apache.daffodil.processors.ElementRuntimeData
@@ -27,6 +27,7 @@ import org.apache.daffodil.processors.Evaluatable
 import org.apache.daffodil.processors.ParseOrUnparseState
 import org.apache.daffodil.processors.Success
 import org.apache.daffodil.schema.annotation.props.gen.LengthUnits
+import org.apache.daffodil.util.MaybeULong
 import org.apache.daffodil.util.Numbers
 
 trait HasKnownLengthInBits {
@@ -108,15 +109,30 @@ trait PrefixedLengthParserMixin {
    */
   def getPrefixedLengthInBits(state: PState): Long = {
     val lenInUnits = getPrefixedLengthInUnits(state)
-    lengthUnits match {
+    val lenInBits = lengthUnits match {
       case LengthUnits.Bits => lenInUnits
       case LengthUnits.Bytes => lenInUnits * 8
       case LengthUnits.Characters => {
         val mfw = state.encoder.bitsCharset.maybeFixedWidth
-        if (mfw.isDefined) mfw.get
-        else
-          Assert.invariantFailed("Prefixed length for text data in non-fixed width encoding.")
+        Assert.invariant(mfw.isDefined, "Prefixed length for text data in non-fixed width encoding.")
+        lenInUnits * mfw.get
+      }
+    }
+    // Now we save the contentLength that we obtained from the prefix
+    // so that the dfdl:contentLength function can be called on the prefixed length element
+    // at parse time.
+    val mLenInBits = MaybeULong(lenInBits)
+    state.infoset match {
+      case ci: DIComplex => {
+        ci.contentLength.maybeComputedLengthInBits = mLenInBits
+        ci.valueLength.maybeComputedLengthInBits = mLenInBits
+      }
+      case si: DISimple => {
+        si.contentLength.maybeComputedLengthInBits = mLenInBits
+        // Note value length for simple types is handled elsewhere as we don't
+        // have any information about padding/trimming here.
       }
     }
+    lenInBits
   }
 }
diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/section12/lengthKind/PrefixedTests.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/section12/lengthKind/PrefixedTests.tdml
index 182cad8..c94dcce 100644
--- a/daffodil-test/src/test/resources/org/apache/daffodil/section12/lengthKind/PrefixedTests.tdml
+++ b/daffodil-test/src/test/resources/org/apache/daffodil/section12/lengthKind/PrefixedTests.tdml
@@ -2168,4 +2168,389 @@
     </tdml:errors>
   </tdml:parserTestCase>
 
+  <tdml:defineSchema name="lengthKindPrefixed-2"
+                     useDefaultNamespace="false"
+                     elementFormDefault="unqualified">
+
+  <xs:include schemaLocation="org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd" />
+
+  <dfdl:format ref="ex:GeneralFormat"
+               representation="binary"
+               lengthKind="implicit"
+               prefixIncludesPrefixLength="yes" />
+
+    <xs:simpleType name="prefixType1" dfdl:lengthKind="implicit">
+      <xs:restriction base="xs:unsignedInt"/>
+    </xs:simpleType>
+
+  <xs:element name="root1" dfdl:lengthKind="prefixed"
+    dfdl:prefixLengthType="ex:prefixType1">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="f" type="xs:string" dfdl:lengthKind="delimited"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+
+    <xs:simpleType name="prefixType2" dfdl:lengthKind="explicit" dfdl:length="4">
+      <xs:restriction base="xs:unsignedInt"/>
+    </xs:simpleType>
+
+    <xs:element name="root2" dfdl:lengthKind="prefixed"
+                dfdl:prefixLengthType="ex:prefixType2">
+      <xs:complexType>
+        <xs:sequence>
+          <xs:element name="e" dfdl:inputValueCalc='{ dfdl:contentLength(.., "bytes") }'>
+            <xs:annotation>
+              <xs:appinfo source="http://www.ogf.org/dfdl/">
+                <dfdl:assert>{ dfdl:checkConstraints(.) }</dfdl:assert>
+              </xs:appinfo>
+            </xs:annotation>
+            <xs:simpleType>
+              <xs:restriction base="xs:int">
+                <xs:minInclusive value="1"/>
+                <xs:maxInclusive value="6"/>
+              </xs:restriction>
+            </xs:simpleType>
+          </xs:element>
+          <xs:element name="f" type="xs:string" dfdl:lengthKind="delimited"/>
+        </xs:sequence>
+      </xs:complexType>
+    </xs:element>
+
+    <xs:element name="root3" dfdl:lengthKind="prefixed"
+                dfdl:prefixLengthType="ex:prefixType2">
+      <xs:complexType>
+        <xs:sequence>
+          <xs:element name="e" dfdl:inputValueCalc='{ dfdl:valueLength(.., "bytes") }'>
+            <xs:annotation>
+              <xs:appinfo source="http://www.ogf.org/dfdl/">
+                <dfdl:assert>{ dfdl:checkConstraints(.) }</dfdl:assert>
+              </xs:appinfo>
+            </xs:annotation>
+            <xs:simpleType>
+              <xs:restriction base="xs:int">
+                <xs:minInclusive value="1"/>
+                <xs:maxInclusive value="6"/>
+              </xs:restriction>
+            </xs:simpleType>
+          </xs:element>
+          <xs:element name="f" type="xs:string" dfdl:lengthKind="delimited"/>
+        </xs:sequence>
+      </xs:complexType>
+    </xs:element>
+
+    <xs:simpleType name="prefixType3" dfdl:lengthKind="explicit" dfdl:length="32"
+      dfdl:lengthUnits="bits">
+      <xs:restriction base="xs:unsignedInt"/>
+    </xs:simpleType>
+
+    <xs:element name="root4" dfdl:lengthKind="prefixed"
+                dfdl:prefixLengthType="ex:prefixType3"
+                dfdl:lengthUnits="bits">
+      <xs:complexType>
+        <xs:sequence>
+          <xs:element name="e" dfdl:inputValueCalc='{ dfdl:contentLength(.., "bits") }'>
+            <xs:annotation>
+              <xs:appinfo source="http://www.ogf.org/dfdl/">
+                <dfdl:assert>{ dfdl:checkConstraints(.) }</dfdl:assert>
+              </xs:appinfo>
+            </xs:annotation>
+            <xs:simpleType>
+              <xs:restriction base="xs:int">
+                <xs:minInclusive value="8"/>
+                <xs:maxInclusive value="48"/>
+              </xs:restriction>
+            </xs:simpleType>
+          </xs:element>
+          <xs:element name="f" type="xs:string" dfdl:lengthKind="delimited"/>
+        </xs:sequence>
+      </xs:complexType>
+    </xs:element>
+
+    <xs:element name="root5" dfdl:lengthKind="prefixed"
+                dfdl:prefixLengthType="ex:prefixType3"
+                dfdl:lengthUnits="bits">
+      <xs:complexType>
+        <xs:sequence>
+          <xs:element name="e" dfdl:inputValueCalc='{ dfdl:valueLength(.., "bits") }'>
+            <xs:annotation>
+              <xs:appinfo source="http://www.ogf.org/dfdl/">
+                <dfdl:assert>{ dfdl:checkConstraints(.) }</dfdl:assert>
+              </xs:appinfo>
+            </xs:annotation>
+            <xs:simpleType>
+              <xs:restriction base="xs:int">
+                <xs:minInclusive value="8"/>
+                <xs:maxInclusive value="48"/>
+              </xs:restriction>
+            </xs:simpleType>
+          </xs:element>
+          <xs:element name="f" type="xs:string" dfdl:lengthKind="delimited"/>
+        </xs:sequence>
+      </xs:complexType>
+    </xs:element>
+
+    <xs:element name="root6">
+      <xs:complexType>
+        <xs:sequence>
+          <xs:element name="s" type="xs:string" dfdl:lengthKind="prefixed"
+                      dfdl:prefixLengthType="ex:prefixType2"/>
+          <xs:element name="e" type="xs:int" dfdl:inputValueCalc='{ dfdl:contentLength(../s, "bytes") }'>
+          </xs:element>
+        </xs:sequence>
+      </xs:complexType>
+    </xs:element>
+
+    <xs:element name="root7">
+      <xs:complexType>
+        <xs:sequence>
+          <xs:element name="s" type="xs:string" dfdl:lengthKind="prefixed"
+                      dfdl:prefixLengthType="ex:prefixType2"
+                      dfdl:textTrimKind="padChar"
+                      dfdl:textPadKind="none"
+                      dfdl:textStringPadCharacter="%SP;"
+                      dfdl:textStringJustification="center"/>
+          <xs:element name="e" type="xs:int" dfdl:inputValueCalc='{ dfdl:valueLength(../s, "bytes") }'>
+          </xs:element>
+        </xs:sequence>
+      </xs:complexType>
+    </xs:element>
+
+  </tdml:defineSchema>
+
+  <tdml:parserTestCase name="pl_implicit_1"
+                       model="lengthKindPrefixed-2">
+    <tdml:document>
+      <tdml:documentPart type="byte">00 00 00 07</tdml:documentPart>
+      <tdml:documentPart type="text">ABC</tdml:documentPart>
+    </tdml:document>
+    <tdml:infoset>
+      <tdml:dfdlInfoset>
+        <ex:root1>
+          <f>ABC</f>
+        </ex:root1>
+      </tdml:dfdlInfoset>
+    </tdml:infoset>
+  </tdml:parserTestCase>
+
+  <tdml:parserTestCase name="pl_complexContentLengthBytes_1"
+                       model="lengthKindPrefixed-2">
+    <tdml:document>
+      <tdml:documentPart type="byte">00 00 00 07</tdml:documentPart>
+      <tdml:documentPart type="text">ABC</tdml:documentPart>
+    </tdml:document>
+    <tdml:infoset>
+      <tdml:dfdlInfoset>
+        <ex:root2>
+          <e>3</e>
+          <f>ABC</f>
+        </ex:root2>
+      </tdml:dfdlInfoset>
+    </tdml:infoset>
+  </tdml:parserTestCase>
+
+  <tdml:parserTestCase name="pl_complexValueLengthBytes_1"
+                       model="lengthKindPrefixed-2">
+    <tdml:document>
+      <tdml:documentPart type="byte">00 00 00 07</tdml:documentPart>
+      <tdml:documentPart type="text">ABC</tdml:documentPart>
+    </tdml:document>
+    <tdml:infoset>
+      <tdml:dfdlInfoset>
+        <ex:root3>
+          <e>3</e>
+          <f>ABC</f>
+        </ex:root3>
+      </tdml:dfdlInfoset>
+    </tdml:infoset>
+  </tdml:parserTestCase>
+
+  <tdml:parserTestCase name="pl_complexContentLengthBits_1"
+                       model="lengthKindPrefixed-2">
+    <tdml:document>
+      <tdml:documentPart type="byte">00 00 00 38</tdml:documentPart>
+      <tdml:documentPart type="text">ABC</tdml:documentPart>
+    </tdml:document>
+    <tdml:infoset>
+      <tdml:dfdlInfoset>
+        <ex:root4>
+          <e>24</e>
+          <f>ABC</f>
+        </ex:root4>
+      </tdml:dfdlInfoset>
+    </tdml:infoset>
+  </tdml:parserTestCase>
+
+  <tdml:parserTestCase name="pl_complexValueLengthBits_1"
+                       model="lengthKindPrefixed-2">
+    <tdml:document>
+      <tdml:documentPart type="byte">00 00 00 38</tdml:documentPart>
+      <tdml:documentPart type="text">ABC</tdml:documentPart>
+    </tdml:document>
+    <tdml:infoset>
+      <tdml:dfdlInfoset>
+        <ex:root5>
+          <e>24</e>
+          <f>ABC</f>
+        </ex:root5>
+      </tdml:dfdlInfoset>
+    </tdml:infoset>
+  </tdml:parserTestCase>
+
+  <tdml:parserTestCase name="pl_simpleContentLengthBytes_1"
+                       model="lengthKindPrefixed-2">
+    <tdml:document>
+      <tdml:documentPart type="byte">00 00 00 07</tdml:documentPart>
+      <tdml:documentPart type="text">ABC</tdml:documentPart>
+    </tdml:document>
+    <tdml:infoset>
+      <tdml:dfdlInfoset>
+        <ex:root6>
+          <s>ABC</s>
+          <e>3</e>
+        </ex:root6>
+      </tdml:dfdlInfoset>
+    </tdml:infoset>
+  </tdml:parserTestCase>
+
+  <tdml:parserTestCase name="pl_simpleValueLengthBytes_1"
+                       model="lengthKindPrefixed-2">
+    <tdml:document>
+      <tdml:documentPart type="byte">00 00 00 0B</tdml:documentPart>
+      <tdml:documentPart type="text">  ABC  </tdml:documentPart>
+    </tdml:document>
+    <tdml:infoset>
+      <tdml:dfdlInfoset>
+        <ex:root7>
+          <s>ABC</s>
+          <e>3</e>
+        </ex:root7>
+      </tdml:dfdlInfoset>
+    </tdml:infoset>
+  </tdml:parserTestCase>
+
+  <tdml:defineSchema name="lengthKindPrefixed-3"
+                     useDefaultNamespace="false"
+                     elementFormDefault="unqualified">
+
+    <xs:include schemaLocation="org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd" />
+
+    <dfdl:format ref="ex:GeneralFormat"
+                 representation="binary"
+                 lengthKind="implicit"
+                 prefixIncludesPrefixLength="no"/>
+
+    <xs:simpleType name="prefixType"
+                   dfdl:lengthUnits="bytes"
+                   dfdl:lengthKind="explicit"
+                   dfdl:length="4">
+      <xs:restriction base="xs:unsignedInt"/>
+    </xs:simpleType>
+
+    <xs:element name="root8">
+      <xs:complexType>
+        <xs:sequence>
+          <xs:element name="s" type="xs:string"
+                      dfdl:lengthKind="prefixed"
+                      dfdl:prefixLengthType="ex:prefixType"
+                      dfdl:lengthUnits="characters"
+                      dfdl:encoding="utf-16be"/>
+          <xs:element name="e" type="xs:int" dfdl:inputValueCalc='{ dfdl:contentLength(../s, "bytes") }'>
+          </xs:element>
+        </xs:sequence>
+      </xs:complexType>
+    </xs:element>
+
+    <xs:element name="root9" dfdl:lengthKind="prefixed"
+                dfdl:prefixLengthType="ex:prefixType"
+                dfdl:lengthUnits="characters"
+                dfdl:encoding="utf-16be">
+      <xs:complexType>
+        <xs:sequence>
+          <xs:element name="s" type="xs:string"
+                      dfdl:lengthKind="delimited"
+                      dfdl:lengthUnits="characters"
+                      dfdl:encoding="utf-16be"/>
+          <xs:element name="e" type="xs:int" dfdl:inputValueCalc='{ dfdl:contentLength(.., "bytes") }'>
+          </xs:element>
+        </xs:sequence>
+      </xs:complexType>
+    </xs:element>
+
+    <xs:element name="root10" dfdl:lengthKind="prefixed"
+                dfdl:prefixLengthType="ex:prefixType"
+                dfdl:lengthUnits="characters"
+                dfdl:encoding="utf-8">
+      <xs:complexType>
+        <xs:sequence>
+          <xs:element name="s" type="xs:string"
+                      dfdl:lengthKind="delimited"
+                      dfdl:lengthUnits="characters"
+                      dfdl:encoding="utf-8"/>
+          <xs:element name="e" type="xs:int" dfdl:inputValueCalc='{ dfdl:contentLength(.., "bytes") }'>
+          </xs:element>
+        </xs:sequence>
+      </xs:complexType>
+    </xs:element>
+
+  </tdml:defineSchema>
+
+  <tdml:parserTestCase name="pl_simpleContentLengthCharacters_1"
+                       model="lengthKindPrefixed-3">
+    <tdml:document>
+      <tdml:documentPart type="byte">00 00 00 03</tdml:documentPart>
+      <tdml:documentPart type="text" encoding="utf-16be">ABC</tdml:documentPart>
+    </tdml:document>
+    <tdml:infoset>
+      <tdml:dfdlInfoset>
+        <ex:root8>
+          <s>ABC</s>
+          <e>6</e>
+        </ex:root8>
+      </tdml:dfdlInfoset>
+    </tdml:infoset>
+  </tdml:parserTestCase>
+
+  <tdml:parserTestCase name="pl_complexContentLengthCharacters_1"
+                       model="lengthKindPrefixed-3">
+    <tdml:document>
+      <tdml:documentPart type="byte">00 00 00 03</tdml:documentPart>
+      <tdml:documentPart type="text" encoding="utf-16be">ABC</tdml:documentPart>
+    </tdml:document>
+    <tdml:infoset>
+      <tdml:dfdlInfoset>
+        <ex:root9>
+          <s>ABC</s>
+          <e>6</e>
+        </ex:root9>
+      </tdml:dfdlInfoset>
+    </tdml:infoset>
+  </tdml:parserTestCase>
+
+  <tdml:parserTestCase name="pl_complexContentLengthCharacters_utf8_1"
+                       model="lengthKindPrefixed-3"
+                       root="root10">
+    <tdml:document>
+      <tdml:documentPart type="byte">00 00 00 03</tdml:documentPart>
+      <tdml:documentPart type="text" encoding="utf-8">ABC</tdml:documentPart>
+    </tdml:document>
+    <!--
+    <tdml:infoset>
+      <tdml:dfdlInfoset>
+        <ex:root10>
+          <s>ABC</s>
+          <e>3</e>
+        </ex:root10>
+      </tdml:dfdlInfoset>
+    </tdml:infoset> -->
+    <tdml:errors>
+      <tdml:error>Schema Definition Error</tdml:error>
+      <tdml:error>Unparsing</tdml:error>
+      <tdml:error>dfdl:lengthKind='prefixed'</tdml:error>
+      <tdml:error>dfdl:lengthUnits='characters'</tdml:error>
+      <tdml:error>variable-width encoding</tdml:error>
+    </tdml:errors>
+  </tdml:parserTestCase>
+
 </tdml:testSuite>
diff --git a/daffodil-test/src/test/scala/org/apache/daffodil/section12/lengthKind/TestLengthKindPrefixed.scala b/daffodil-test/src/test/scala/org/apache/daffodil/section12/lengthKind/TestLengthKindPrefixed.scala
index ee28937..27fd2f8 100644
--- a/daffodil-test/src/test/scala/org/apache/daffodil/section12/lengthKind/TestLengthKindPrefixed.scala
+++ b/daffodil-test/src/test/scala/org/apache/daffodil/section12/lengthKind/TestLengthKindPrefixed.scala
@@ -150,4 +150,21 @@ class TestLengthKindPrefixed {
   @Test def test_pl_lengthunits_err() = { runner.runOneTest("pl_lengthunits_err") }
   @Test def test_pl_nest_err() = { runner.runOneTest("pl_nest_err") }
   @Test def test_pl_decimal_err() = { runner.runOneTest("pl_decimal_err") }
+
+  // DAFFODIL-2657
+  @Test def test_pl_implicit_1() = { runner.runOneTest("pl_implicit_1")}
+
+  // DAFFODIL-2656
+  @Test def test_pl_complexContentLengthBytes_1() = { runner.runOneTest("pl_complexContentLengthBytes_1")}
+  @Test def test_pl_complexValueLengthBytes_1() = { runner.runOneTest("pl_complexValueLengthBytes_1")}
+  @Test def test_pl_complexContentLengthBits_1() = { runner.runOneTest("pl_complexContentLengthBits_1")}
+  @Test def test_pl_complexValueLengthBits_1() = { runner.runOneTest("pl_complexValueLengthBits_1")}
+  @Test def test_pl_simpleContentLengthBytes_1() = { runner.runOneTest("pl_simpleContentLengthBytes_1")}
+
+  // DAFFODIL-2658
+  // @Test def test_pl_simpleValueLengthBytes_1() = { runner.runOneTest("pl_simpleValueLengthBytes_1")}
+
+  @Test def test_pl_simpleContentLengthCharacters_1() = { runner.runOneTest("pl_simpleContentLengthCharacters_1")}
+  @Test def test_pl_complexContentLengthCharacters_1() = { runner.runOneTest("pl_complexContentLengthCharacters_1")}
+  @Test def test_pl_complexContentLengthCharacters_utf8_1() = { runner.runOneTest("pl_complexContentLengthCharacters_utf8_1")}
 }