Skip to content

Commit 698387d

Browse files
committed
Add dfdlx:currentPosition function
This is for some DFDL experiments with data formats that DFDL can't currently represent. The function is only meaningful at parse time. DAFFODIL-2974
1 parent 1a51c31 commit 698387d

File tree

4 files changed

+152
-0
lines changed

4 files changed

+152
-0
lines changed

daffodil-core/src/main/scala/org/apache/daffodil/core/dpath/Expression.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1802,6 +1802,21 @@ case class FunctionCallExpression(functionQNameString: String, expressions: List
18021802
DFDLXBitBinaryExpr(functionQNameString, functionQName, args, DFDLXBitOr(_, _))
18031803
case (RefQName(_, "bitNot", DFDLX), args) =>
18041804
DFDLXBitUnaryExpr(functionQNameString, functionQName, args, DFDLXBitNot(_, _))
1805+
//
1806+
// Returns the current position in bits or bytes. This is 1-based.
1807+
// Experimental Feature: Why? because well... is this even well defined
1808+
// when unparsing given that expressions can get
1809+
// retried, and the position may not be well known yet at that time.
1810+
//
1811+
case (RefQName(_, "currentPosition", DFDLX), args) =>
1812+
FNOneArgExpr(
1813+
functionQNameString,
1814+
functionQName,
1815+
args,
1816+
NodeInfo.Long,
1817+
NodeInfo.String,
1818+
DFDLXCurrentPosition(_, _)
1819+
)
18051820

18061821
case (RefQName(_, "year-from-dateTime", FUNC), args) =>
18071822
FNOneArgExpr(

daffodil-core/src/main/scala/org/apache/daffodil/runtime1/dpath/DFDLXFunctions.scala

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,3 +347,28 @@ case class DFDLXDoubleToRawLong(recipes: CompiledDPath, argType: NodeInfo.Kind)
347347
JDouble.doubleToRawLongBits(value.getDouble)
348348
}
349349
}
350+
/**
351+
* Computes the current position in the data stream in unis of bits or bytes.
352+
*
353+
* Not well defined for unparsing since an absolute position may not be available
354+
* at the time this is called.
355+
*/
356+
case class DFDLXCurrentPosition(recipes: CompiledDPath, argType: NodeInfo.Kind)
357+
extends FNOneArg(recipes, NodeInfo.String) {
358+
Assert.invariant(argType == NodeInfo.String)
359+
360+
override def computeValue(arg1: DataValuePrimitive, dstate: DState): DataValueLong = {
361+
val units = arg1.getString
362+
val maybeState = dstate.parseOrUnparseState
363+
val bitpos1b =
364+
if (maybeState.isDefined) maybeState.get.bitPos1b
365+
else throw new IllegalStateException() // when constant folding, this can't be folded.
366+
val res: Long = units match {
367+
case "bits" => bitpos1b
368+
case "bytes" =>
369+
maybeState.get.bytePos1b // note: if bitpos is not on a byte boundary, this will be first prior byte pos.
370+
case _ => dstate.SDE("Units argument was not 'bits' or 'bytes'. Value was: '%s'.", units)
371+
}
372+
res
373+
}
374+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
Licensed to the Apache Software Foundation (ASF) under one or more
4+
contributor license agreements. See the NOTICE file distributed with
5+
this work for additional information regarding copyright ownership.
6+
The ASF licenses this file to You under the Apache License, Version 2.0
7+
(the "License"); you may not use this file except in compliance with
8+
the License. You may obtain a copy of the License at
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
-->
16+
17+
<tdml:testSuite suiteName="CurrentPosition" description="Current Position DFDL Extension Function"
18+
xmlns:dfdlx="http://www.ogf.org/dfdl/dfdl-1.0/extensions"
19+
xmlns:tdml="http://www.ibm.com/xmlns/dfdl/testData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
20+
xmlns:dfdl="http://www.ogf.org/dfdl/dfdl-1.0/" xmlns:xs="http://www.w3.org/2001/XMLSchema"
21+
xmlns:fn="http://www.w3.org/2005/xpath-functions"
22+
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
23+
xmlns:ex="http://example.com"
24+
xmlns:home="http://home.com"
25+
xmlns:first="http://first.com"
26+
defaultRoundTrip="onePass">
27+
28+
<tdml:defineSchema elementFormDefault="unqualified" useDefaultNamespace="false"
29+
name="cp">
30+
<xs:include schemaLocation="/org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>
31+
<dfdl:format
32+
ref="ex:GeneralFormat"
33+
representation="binary"
34+
binaryNumberRep="binary"
35+
lengthUnits="bits"
36+
alignmentUnits="bits"
37+
alignment="1"/>
38+
39+
<xs:simpleType name="uLongN" dfdl:lengthKind="explicit">
40+
<xs:restriction base="xs:unsignedLong"/>
41+
</xs:simpleType>
42+
43+
<xs:element name="bits1">
44+
<xs:complexType>
45+
<xs:sequence>
46+
<xs:element name="bitPos1bAtStart" type="xs:long" dfdl:inputValueCalc='{ dfdlx:currentPosition("bits") }'/>
47+
<xs:element name="oneBit" type="ex:uLongN" dfdl:length="1"/>
48+
<xs:element name="bitPos1bAfterOneBit" type="xs:long" dfdl:inputValueCalc='{ dfdlx:currentPosition("bits") }'/>
49+
<xs:element name="bytePos1bAfterOneBit" type="xs:long" dfdl:inputValueCalc='{ dfdlx:currentPosition("bytes") }'/>
50+
<xs:element name="eightBits" type="ex:uLongN" dfdl:length="8"/>
51+
<xs:element name="bitPos1bAfter9Bits" type="xs:long" dfdl:inputValueCalc='{ dfdlx:currentPosition("bits") }'/>
52+
<xs:element name="bytePos1bAfter9Bits" type="xs:long" dfdl:inputValueCalc='{ dfdlx:currentPosition("bytes") }'/>
53+
<xs:element name="sevenBits" type="ex:uLongN" dfdl:length="7"/>
54+
</xs:sequence>
55+
</xs:complexType>
56+
</xs:element>
57+
58+
</tdml:defineSchema>
59+
60+
<tdml:parserTestCase name="testCurrentPosition1" root="bits1" model="cp">
61+
<tdml:document>
62+
<tdml:documentPart type="bits">1000 0010 1001 1111</tdml:documentPart>
63+
</tdml:document>
64+
<tdml:infoset>
65+
<tdml:dfdlInfoset>
66+
<ex:bits1>
67+
<bitPos1bAtStart>1</bitPos1bAtStart>
68+
<oneBit>1</oneBit>
69+
<bitPos1bAfterOneBit>2</bitPos1bAfterOneBit>
70+
<bytePos1bAfterOneBit>1</bytePos1bAfterOneBit>
71+
<eightBits>5</eightBits>
72+
<bitPos1bAfter9Bits>10</bitPos1bAfter9Bits>
73+
<bytePos1bAfter9Bits>2</bytePos1bAfter9Bits>
74+
<sevenBits>31</sevenBits>
75+
</ex:bits1>
76+
</tdml:dfdlInfoset>
77+
</tdml:infoset>
78+
</tdml:parserTestCase>
79+
80+
</tdml:testSuite>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.daffodil.section23.dfdl_expressions
19+
20+
import org.apache.daffodil.junit.tdml.{ TdmlSuite, TdmlTests }
21+
22+
import org.junit.Test
23+
24+
object TestCurrentPositionFunction extends TdmlSuite {
25+
val tdmlResource = "/org/apache/daffodil/section23/dfdl_functions/CurrentPosition.tdml"
26+
}
27+
28+
class TestCurrentPositionFunction extends TdmlTests {
29+
val tdmlSuite = TestCurrentPositionFunction
30+
31+
@Test def testCurrentPosition1 = test
32+
}

0 commit comments

Comments
 (0)