Skip to content

Commit 7154301

Browse files
committed
Ensure that contents and valid apply to individual elements
Resolves kaitai-io/kaitai_struct#1117 This is how the `contents` key worked until KS 0.8, but then in KS 0.9, `contents` started to be converted to the newly introduced `valid`, which was applied only once at the end on the final value. This means that it was applied on the entire array in the case of repeated fields. However, the behavior of `valid` + `repeat` wasn't tested anywhere, so I think it was an oversight. Note that the Kaitai Struct language doesn't define an equality `==` operation for true arrays, so it wouldn't even work. Running the `valid` and `contents` checks on each element is more flexible (and also seems more useful). Fixes the following tests for all languages except Go (will be fixed in the following commit), Nim, Perl and Construct: * ValidFailRepeatAnyofInt * ValidFailRepeatContents * ValidFailRepeatEqInt * ValidFailRepeatExpr * ValidFailRepeatInst * ValidFailRepeatMaxInt * ValidFailRepeatMinInt These tests were added in kaitai-io/kaitai_struct_tests@98a68fc
1 parent 06f5658 commit 7154301

File tree

3 files changed

+34
-21
lines changed

3 files changed

+34
-21
lines changed

shared/src/main/scala/io/kaitai/struct/format/Identifier.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,19 @@ object Identifier {
7070
}
7171
}
7272

73+
def itemExpr(id: Identifier, rep: RepeatSpec): Ast.expr = {
74+
val astId = Ast.expr.InternalName(id)
75+
rep match {
76+
case NoRepeat =>
77+
astId
78+
case _ =>
79+
Ast.expr.Subscript(
80+
astId,
81+
Ast.expr.Name(Ast.identifier(Identifier.INDEX))
82+
)
83+
}
84+
}
85+
7386
// Constants for special names used in expression language
7487
val ROOT = "_root"
7588
val PARENT = "_parent"

shared/src/main/scala/io/kaitai/struct/languages/components/CommonReads.scala

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,6 @@ trait CommonReads extends LanguageCompiler {
6060
case _ => // no seeking required for sequence attributes
6161
}
6262

63-
// Run validations (still inside "if", if applicable)
64-
attrValidateAll(attr)
65-
6663
attrParseIfFooter(attr.cond.ifExpr)
6764
}
6865

@@ -79,6 +76,7 @@ trait CommonReads extends LanguageCompiler {
7976
case NoRepeat =>
8077
}
8178
attrParse2(id, attr.dataType, io, attr.cond.repeat, false, defEndian)
79+
attrValidateAll(attr)
8280
attr.cond.repeat match {
8381
case RepeatEos =>
8482
condRepeatEosFooter

shared/src/main/scala/io/kaitai/struct/languages/components/ValidateOps.scala

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,23 @@ trait ValidateOps extends ExceptionNames {
1414
val typeProvider: ClassTypeProvider
1515

1616
def attrValidate(attrId: Identifier, attr: AttrLikeSpec, valid: ValidationSpec): Unit = {
17+
val itemValue = Identifier.itemExpr(attrId, attr.cond.repeat)
1718
valid match {
1819
case ValidationEq(expected) =>
19-
attrValidateExprCompare(attrId, attr, Ast.cmpop.Eq, expected, ValidationNotEqualError(attr.dataTypeComposite))
20+
attrValidateExprCompare(attrId, attr, Ast.cmpop.Eq, expected, ValidationNotEqualError(attr.dataType))
2021
case ValidationMin(min) =>
21-
attrValidateExprCompare(attrId, attr, Ast.cmpop.GtE, min, ValidationLessThanError(attr.dataTypeComposite))
22+
attrValidateExprCompare(attrId, attr, Ast.cmpop.GtE, min, ValidationLessThanError(attr.dataType))
2223
case ValidationMax(max) =>
23-
attrValidateExprCompare(attrId, attr, Ast.cmpop.LtE, max, ValidationGreaterThanError(attr.dataTypeComposite))
24+
attrValidateExprCompare(attrId, attr, Ast.cmpop.LtE, max, ValidationGreaterThanError(attr.dataType))
2425
case ValidationRange(min, max) =>
25-
attrValidateExprCompare(attrId, attr, Ast.cmpop.GtE, min, ValidationLessThanError(attr.dataTypeComposite))
26-
attrValidateExprCompare(attrId, attr, Ast.cmpop.LtE, max, ValidationGreaterThanError(attr.dataTypeComposite))
26+
attrValidateExprCompare(attrId, attr, Ast.cmpop.GtE, min, ValidationLessThanError(attr.dataType))
27+
attrValidateExprCompare(attrId, attr, Ast.cmpop.LtE, max, ValidationGreaterThanError(attr.dataType))
2728
case ValidationAnyOf(values) =>
2829
val bigOrExpr = Ast.expr.BoolOp(
2930
Ast.boolop.Or,
3031
values.map(expected =>
3132
Ast.expr.Compare(
32-
Ast.expr.InternalName(attrId),
33+
itemValue,
3334
Ast.cmpop.Eq,
3435
expected
3536
)
@@ -38,30 +39,30 @@ trait ValidateOps extends ExceptionNames {
3839

3940
attrValidateExpr(
4041
attrId,
41-
attr.dataTypeComposite,
42+
attr.dataType,
4243
checkExpr = bigOrExpr,
43-
err = ValidationNotAnyOfError(attr.dataTypeComposite),
44+
err = ValidationNotAnyOfError(attr.dataType),
4445
errArgs = List(
45-
Ast.expr.InternalName(attrId),
46+
itemValue,
4647
Ast.expr.InternalName(IoIdentifier),
4748
Ast.expr.Str(attr.path.mkString("/", "/", ""))
4849
)
4950
)
5051
case ValidationExpr(expr) =>
5152
blockScopeHeader
52-
typeProvider._currentIteratorType = Some(attr.dataTypeComposite)
53+
typeProvider._currentIteratorType = Some(attr.dataType)
5354
handleAssignmentTempVar(
54-
attr.dataTypeComposite,
55+
attr.dataType,
5556
translator.translate(Ast.expr.Name(Ast.identifier(Identifier.ITERATOR))),
56-
translator.translate(Ast.expr.InternalName(attrId))
57+
translator.translate(itemValue)
5758
)
5859
attrValidateExpr(
5960
attrId,
60-
attr.dataTypeComposite,
61+
attr.dataType,
6162
expr,
62-
ValidationExprError(attr.dataTypeComposite),
63+
ValidationExprError(attr.dataType),
6364
List(
64-
Ast.expr.InternalName(attrId),
65+
itemValue,
6566
Ast.expr.InternalName(IoIdentifier),
6667
Ast.expr.Str(attr.path.mkString("/", "/", ""))
6768
)
@@ -71,18 +72,19 @@ trait ValidateOps extends ExceptionNames {
7172
}
7273

7374
def attrValidateExprCompare(attrId: Identifier, attr: AttrLikeSpec, op: Ast.cmpop, expected: Ast.expr, err: KSError): Unit = {
75+
val itemValue = Identifier.itemExpr(attrId, attr.cond.repeat)
7476
attrValidateExpr(
7577
attrId,
76-
attr.dataTypeComposite,
78+
attr.dataType,
7779
checkExpr = Ast.expr.Compare(
78-
Ast.expr.InternalName(attrId),
80+
itemValue,
7981
op,
8082
expected
8183
),
8284
err = err,
8385
errArgs = List(
8486
expected,
85-
Ast.expr.InternalName(attrId),
87+
itemValue,
8688
Ast.expr.InternalName(IoIdentifier),
8789
Ast.expr.Str(attr.path.mkString("/", "/", ""))
8890
)

0 commit comments

Comments
 (0)