diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/AlignedMixin.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/AlignedMixin.scala
index a6d52b8a5c..256afd445b 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/AlignedMixin.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/AlignedMixin.scala
@@ -134,11 +134,14 @@ trait AlignedMixin extends GrammarMixin { self: Term =>
LengthExact(trailingSkipInBits)
}
- // FIXME: DAFFODIL-2295
- // Does not take into account that in a sequence, what may be prior may be a separator.
- // The separator is text in some encoding, might not be the same as this term's encoding, and
- // the alignment will be left where that text leaves it.
- //
+ /**
+ * The priorAlignmentApprox doesn't need to take into account the separator
+ * alignment/length as that comes after the priorAlignmentApprox, but before
+ * the leadingSkip.
+ *
+ * TODO: DAFFODIL-3056 We need to consider the initiator MTA/length,
+ * as well as the prefix length
+ */
private lazy val priorAlignmentApprox: AlignmentMultipleOf =
LV(Symbol("priorAlignmentApprox")) {
if (this.isInstanceOf[Root] || this.isInstanceOf[QuasiElementDeclBase]) {
@@ -232,6 +235,31 @@ trait AlignedMixin extends GrammarMixin { self: Term =>
priorAlignmentApprox + leadingSkipApprox
}
+ private lazy val terminatorMTAApprox =
+ if (this.hasTerminator) {
+ AlignmentMultipleOf(this.knownEncodingAlignmentInBits)
+ } else {
+ AlignmentMultipleOf(0)
+ }
+
+ private lazy val terminatorLengthApprox = if (this.hasTerminator) {
+ getEncodingLengthApprox(this)
+ } else {
+ LengthMultipleOf(0)
+ }
+
+ private def getEncodingLengthApprox(t: Term) = {
+ if (t.isKnownEncoding) {
+ val dfdlCharset = t.charsetEv.optConstant.get
+ val fixedWidth =
+ if (dfdlCharset.maybeFixedWidth.isDefined) dfdlCharset.maybeFixedWidth.get else 8
+ LengthMultipleOf(fixedWidth)
+ } else {
+ // runtime encoding, which must be a byte-length encoding
+ LengthMultipleOf(8)
+ }
+ }
+
protected lazy val contentStartAlignment: AlignmentMultipleOf = {
if (priorAlignmentWithLeadingSkipApprox % alignmentApprox == 0) {
// alignment won't be needed, continue using prior alignment as start alignment
@@ -242,15 +270,22 @@ trait AlignedMixin extends GrammarMixin { self: Term =>
}
}
+ /**
+ * Accounts for the terminator MTA/Length and trailing skip
+ */
protected lazy val endingAlignmentApprox: AlignmentMultipleOf = {
this match {
case eb: ElementBase => {
- if (eb.isComplexType && eb.lengthKind == LengthKind.Implicit) {
- eb.complexType.group.endingAlignmentApprox + trailingSkipApprox
+ val res = if (eb.isComplexType && eb.lengthKind == LengthKind.Implicit) {
+ eb.complexType.group.endingAlignmentApprox
} else {
// simple type or complex type with specified length
- contentStartAlignment + (elementSpecifiedLengthApprox + trailingSkipApprox)
+ contentStartAlignment + elementSpecifiedLengthApprox
}
+ val cea = res * terminatorMTAApprox
+ + terminatorLengthApprox
+ + trailingSkipApprox
+ cea
}
case mg: ModelGroup => {
//
@@ -261,31 +296,36 @@ trait AlignedMixin extends GrammarMixin { self: Term =>
val (lastChildren, couldBeLast) = mg.potentialLastChildren
val lastApproxesConsideringChildren: Seq[AlignmentMultipleOf] = lastChildren.map { lc =>
//
- // for each possible last child, add its ending alignment
- // to our trailing skip to get where it would leave off were
- // it the actual last child.
- //
+ // for each possible last child, gather its endingAlignmentApprox
val lceaa = lc.endingAlignmentApprox
- val res = lceaa + trailingSkipApprox
- res
+ lceaa
}
val optApproxIfNoChildren =
//
// gather possibilities for this item itself
//
- if (couldBeLast)
+ if (couldBeLast) {
//
// if this model group could be last, then consider
// if none of its content was present.
- // We'd just have the contentStart, nothing, and the trailing Skip.
+ // We'd just have the contentStart
//
- Some(contentStartAlignment + trailingSkipApprox)
- else
+ val res = Some(contentStartAlignment)
+ res
+ } else
// can't be last, no possibilities to gather.
None
val lastApproxes = lastApproxesConsideringChildren ++ optApproxIfNoChildren
- Assert.invariant(lastApproxes.nonEmpty)
- val res = lastApproxes.reduce { _ * _ }
+ // take all the gathered possibilities and add the ending alignment
+ // to terminator MTA/length and our trailing skip to get where it would leave off were
+ // each the actual last child.
+ val lastApproxesFinal = lastApproxes.map {
+ _ * terminatorMTAApprox
+ + terminatorLengthApprox
+ + trailingSkipApprox
+ }
+ Assert.invariant(lastApproxesFinal.nonEmpty)
+ val res = lastApproxesFinal.reduce { _ * _ }
res
}
}
@@ -329,15 +369,7 @@ trait AlignedMixin extends GrammarMixin { self: Term =>
}
private lazy val encodingLengthApprox: LengthApprox = {
- if (isKnownEncoding) {
- val dfdlCharset = charsetEv.optConstant.get
- val fixedWidth =
- if (dfdlCharset.maybeFixedWidth.isDefined) dfdlCharset.maybeFixedWidth.get else 8
- LengthMultipleOf(fixedWidth)
- } else {
- // runtime encoding, which must be a byte-length encoding
- LengthMultipleOf(8)
- }
+ getEncodingLengthApprox(this)
}
protected lazy val isKnownToBeByteAlignedAndByteLength: Boolean = {
diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/section12/aligned_data/Aligned_Data.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/section12/aligned_data/Aligned_Data.tdml
index 119c799854..c25818a934 100644
--- a/daffodil-test/src/test/resources/org/apache/daffodil/section12/aligned_data/Aligned_Data.tdml
+++ b/daffodil-test/src/test/resources/org/apache/daffodil/section12/aligned_data/Aligned_Data.tdml
@@ -602,6 +602,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ aaTBbb
+
+
+
+
+
+ aa
+ bb
+
+
+
+
+
+
+
+ aabbT2ee
+
+
+
+
+
+ aa
+ bb
+
+ ee
+
+
+
+
+
diff --git a/daffodil-test/src/test/scala/org/apache/daffodil/section12/aligned_data/TestAlignedData.scala b/daffodil-test/src/test/scala/org/apache/daffodil/section12/aligned_data/TestAlignedData.scala
index 23967c96a8..860415d7b1 100644
--- a/daffodil-test/src/test/scala/org/apache/daffodil/section12/aligned_data/TestAlignedData.scala
+++ b/daffodil-test/src/test/scala/org/apache/daffodil/section12/aligned_data/TestAlignedData.scala
@@ -186,6 +186,10 @@ class TestAlignedData extends TdmlTests {
@Test def alignmentFillByteDefined = test
@Test def separatorMTA_01 = test
+
+ // DAFFODIL-3057
+ @Test def test_term_alignment_1 = test
+ @Test def test_term_alignment_2 = test
}
class TestBinaryInput extends TdmlTests {