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 31b90579b Add requireLengthInWholeWords feature to byteSwap layer
31b90579b is described below

commit 31b90579b21b05e95c43896798a1801884542aec
Author: Michael Beckerle <[email protected]>
AuthorDate: Wed May 29 19:26:29 2024 -0400

    Add requireLengthInWholeWords feature to byteSwap layer
    
    Eliminates the need for a separate byteSwap layer just to get an error if 
the
    data is not a mulitple of the word size.
    
    DAFFODIL-2905
---
 .../daffodil/layers/xsd/byteSwapLayer.dfdl.xsd     |   8 +-
 .../daffodil/layers/runtime1/ByteSwapLayer.scala   |  81 +++++++--
 .../layers/runtime1/TestByteSwapStream.scala       |   4 +-
 .../apache/daffodil/layers/TestTwoByteSwap.tdml    | 192 +++++++++++++++++++++
 .../daffodil/layers/xsd/testTwoByteSwap.dfdl.xsd   |  90 ++++++++++
 .../layers/xsd/testTwoByteSwapByte.dfdl.xsd        |  86 +++++++++
 .../layers/xsd/testTwoByteSwapShort.dfdl.xsd       |  79 +++++++++
 .../daffodil/runtime1/layers/TestByteSwap.scala    |  57 ++++++
 8 files changed, 578 insertions(+), 19 deletions(-)

diff --git 
a/daffodil-runtime1-layers/src/main/resources/org/apache/daffodil/layers/xsd/byteSwapLayer.dfdl.xsd
 
b/daffodil-runtime1-layers/src/main/resources/org/apache/daffodil/layers/xsd/byteSwapLayer.dfdl.xsd
index 958b0a39c..a5ec47098 100644
--- 
a/daffodil-runtime1-layers/src/main/resources/org/apache/daffodil/layers/xsd/byteSwapLayer.dfdl.xsd
+++ 
b/daffodil-runtime1-layers/src/main/resources/org/apache/daffodil/layers/xsd/byteSwapLayer.dfdl.xsd
@@ -26,12 +26,10 @@
   <annotation>
     <appinfo source="http://www.ogf.org/dfdl/";>
 
-      <!--
-      The twobyteswap and fourbyteswap layers have no parameters nor
-      return variables
-      -->
+      <!-- set/bind to yes if you want a parse error when the length is not a 
multiple of the word size -->
+      <dfdl:defineVariable name="requireLengthInWholeWords" type="xs:string" 
defaultValue="no"/>
 
     </appinfo>
   </annotation>
 
-</schema>
\ No newline at end of file
+</schema>
diff --git 
a/daffodil-runtime1-layers/src/main/scala/org/apache/daffodil/layers/runtime1/ByteSwapLayer.scala
 
b/daffodil-runtime1-layers/src/main/scala/org/apache/daffodil/layers/runtime1/ByteSwapLayer.scala
index 387022288..fde77efb3 100644
--- 
a/daffodil-runtime1-layers/src/main/scala/org/apache/daffodil/layers/runtime1/ByteSwapLayer.scala
+++ 
b/daffodil-runtime1-layers/src/main/scala/org/apache/daffodil/layers/runtime1/ByteSwapLayer.scala
@@ -29,18 +29,51 @@ final class TwoByteSwapLayer extends 
ByteSwap("twobyteswap", 2)
 
 final class FourByteSwapLayer extends ByteSwap("fourbyteswap", 4)
 
-abstract class ByteSwap(name: String, count: Int)
+/**
+ * This class represents a byte swap layer that can be used to swap the byte 
order of data.
+ *
+ * DFDL Variable `requireLengthInWholeWords` can be used to request that the 
layer enforce
+ * the length being a multiple of the word size.
+ *
+ * @constructor Creates a new ByteSwap instance with the specified name and 
word size.
+ * @param name     The name of the byte swap layer.
+ * @param wordsize The word size in bytes.
+ */
+abstract class ByteSwap(name: String, wordsize: Int)
   extends Layer(name, "urn:org.apache.daffodil.layers.byteSwap") {
 
+  private var wholeWords: Boolean = false
+
+  lazy val notWordSize = new IllegalStateException(
+    "Data length is not a multiple of " + wordsize
+  )
+
+  /**
+   * Initialize from DFDL variables that are parameters.
+   * @param requireLengthInWholeWords a string that is the value of the DFDL 
variable of the same name in this layer's
+   *                                  namespace. Must be "yes" or "no" or it 
is a SDE.
+   */
+  def setLayerVariableParameters(requireLengthInWholeWords: String): Unit = {
+    requireLengthInWholeWords match {
+      case "yes" => this.wholeWords = true
+      case "no" => this.wholeWords = false // this is the default
+      case _ =>
+        runtimeSchemaDefinitionError(
+          "requireLengthInWholeWords variable must be either 'yes' or 'no', 
but was: " + requireLengthInWholeWords
+        )
+    }
+  }
+
   override def wrapLayerOutput(jos: OutputStream): OutputStream =
-    new ByteSwapOutputStream(count, jos)
+    new ByteSwapOutputStream(this, wordsize, jos, wholeWords)
 
   override def wrapLayerInput(jis: InputStream): InputStream =
-    new ByteSwapInputStream(count, jis)
+    new ByteSwapInputStream(this, wordsize, jis, wholeWords)
 }
 
 /**
- * An input stream wrapper that re-orders bytes according to wordsize.
+ * This class represents an input stream that performs byte swapping on
+ * the data read from another input stream.
  *
  * This is streaming - does not require buffering up the data. So can be used 
on
  * very large data objects.
@@ -50,11 +83,17 @@ abstract class ByteSwap(name: String, count: Int)
  * 4, then the bytes from the wrapped input stream are returned in the
  * order 4 3 2 1 8 7 6 5 10 9.  If wordsize were 2 then the bytes from the
  * wrapped input stream are returned in the order 2 1 4 3 6 5 8 7 10 9.
+ *
+ * @param layer      The layer object used for error reporting.
+ * @param wordsize   The number of bytes to swap at a time.
+ * @param jis        The underlying input stream.
+ * @param wholeWords It is a parse error if this is true and the length is not 
a multiple of the wordsize.
  */
-class ByteSwapInputStream(wordsize: Int, jis: InputStream) extends InputStream 
{
+class ByteSwapInputStream(layer: ByteSwap, wordsize: Int, jis: InputStream, 
wholeWords: Boolean)
+  extends InputStream {
 
   object State extends org.apache.daffodil.lib.util.Enum {
-    abstract sealed trait Type extends EnumValueType
+    sealed trait Type extends EnumValueType
 
     /**
      * Buffering bytes in a word.
@@ -94,6 +133,10 @@ class ByteSwapInputStream(wordsize: Int, jis: InputStream) 
extends InputStream {
           c = jis.read()
           if (c == -1) {
             state = Draining
+            if (wholeWords && (stack.size() % wordsize != 0)) {
+              // end of data but we have only a partial word on stack.
+              layer.processingError(layer.notWordSize)
+            }
           } else {
             stack.push(c)
             if (stack.size() == wordsize) {
@@ -102,7 +145,7 @@ class ByteSwapInputStream(wordsize: Int, jis: InputStream) 
extends InputStream {
           }
         }
         case Emptying => {
-          if (stack.isEmpty()) {
+          if (stack.isEmpty) {
             state = Filling
           } else {
             c = stack.pop()
@@ -110,7 +153,7 @@ class ByteSwapInputStream(wordsize: Int, jis: InputStream) 
extends InputStream {
           }
         }
         case Draining => {
-          if (stack.isEmpty()) {
+          if (stack.isEmpty) {
             state = Done
             return -1
           } else {
@@ -136,19 +179,33 @@ class ByteSwapInputStream(wordsize: Int, jis: 
InputStream) extends InputStream {
  * bytes are written to the wrapped output stream in the
  * order 4 3 2 1 8 7 6 5 10 9.  If wordsize were 2 then the bytes are written
  * to the wrapped output stream in the order 2 1 4 3 6 5 8 7 10 9.
+ *
+ * @param layer      The layer object used for error reporting.
+ * @param wordsize   The number of bytes to swap at a time.
+ * @param jos        OutputStream where the data is written after byte swapping
+ * @param wholeWords It is a unparse error if this is true and the length at 
close time is not a multiple of the wordsize.
  */
-class ByteSwapOutputStream(wordsize: Int, jos: OutputStream) extends 
OutputStream {
+class ByteSwapOutputStream(
+  layer: ByteSwap,
+  wordsize: Int,
+  jos: OutputStream,
+  wholeWords: Boolean
+) extends OutputStream {
 
   private val stack: Deque[Byte] = new ArrayDeque[Byte](wordsize)
   private var closed = false
 
   override def close(): Unit = {
     if (!closed) {
-      while (!stack.isEmpty()) {
+      closed = true
+      if (wholeWords && (stack.size() % wordsize != 0)) {
+        // end of data but we have only a partial word on stack.
+        layer.processingError(layer.notWordSize)
+      }
+      while (!stack.isEmpty) {
         jos.write(stack.pop())
       }
       jos.close()
-      closed = true
     }
   }
 
@@ -156,7 +213,7 @@ class ByteSwapOutputStream(wordsize: Int, jos: 
OutputStream) extends OutputStrea
     Assert.usage(!closed)
     stack.push(bInt.toByte)
     if (stack.size() == wordsize) {
-      while (!stack.isEmpty()) {
+      while (!stack.isEmpty) {
         jos.write(stack.pop())
       }
     }
diff --git 
a/daffodil-runtime1-layers/src/test/scala/org/apache/daffodil/layers/runtime1/TestByteSwapStream.scala
 
b/daffodil-runtime1-layers/src/test/scala/org/apache/daffodil/layers/runtime1/TestByteSwapStream.scala
index 142e41b73..6ff7abc66 100644
--- 
a/daffodil-runtime1-layers/src/test/scala/org/apache/daffodil/layers/runtime1/TestByteSwapStream.scala
+++ 
b/daffodil-runtime1-layers/src/test/scala/org/apache/daffodil/layers/runtime1/TestByteSwapStream.scala
@@ -34,7 +34,7 @@ class TestByteSwapStreams {
   @Test def testFourByteSwapInputStream() = {
     val data = unswapped32BitData
     val bba = new ByteArrayInputStream(data)
-    val bss = new ByteSwapInputStream(4, bba)
+    val bss = new ByteSwapInputStream(layer = null, 4, bba, wholeWords = false)
 
     val baos = new ByteArrayOutputStream()
     var c: Int = -1
@@ -55,7 +55,7 @@ class TestByteSwapStreams {
     val bba = new ByteArrayInputStream(data)
 
     val baos = new ByteArrayOutputStream()
-    val bsos = new ByteSwapOutputStream(4, baos)
+    val bsos = new ByteSwapOutputStream(layer = null, 4, baos, wholeWords = 
false)
     var c: Int = -1
     while ({
       c = bba.read()
diff --git 
a/daffodil-test/src/test/resources/org/apache/daffodil/layers/TestTwoByteSwap.tdml
 
b/daffodil-test/src/test/resources/org/apache/daffodil/layers/TestTwoByteSwap.tdml
new file mode 100644
index 000000000..ed228249b
--- /dev/null
+++ 
b/daffodil-test/src/test/resources/org/apache/daffodil/layers/TestTwoByteSwap.tdml
@@ -0,0 +1,192 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<testSuite
+  suiteName="TwoByteSwap"
+  description="TwoByteSwap tests"
+  xmlns="http://www.ibm.com/xmlns/dfdl/testData";
+  xmlns:tdml="http://www.ibm.com/xmlns/dfdl/testData";
+  xmlns:dfdl="http://www.ogf.org/dfdl/dfdl-1.0/";
+  xmlns:fn="http://www.w3.org/2005/xpath-functions";
+  xmlns:xs="http://www.w3.org/2001/XMLSchema";
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+  xmlns:ex="http://example.com";
+  defaultRoundTrip="onePass"
+  defaultValidation="on">
+
+  <!-- 0 and 1 byteswapped results in 00 00 and 01 00 or 0 and 256 -->
+  <parserTestCase name="test_twobyteswap_01" root="TwoByteSwapTest" 
model="org/apache/daffodil/layers/xsd/testTwoByteSwapShort.dfdl.xsd">
+    <document>
+      <documentPart type="byte">00 00 00 01</documentPart>
+    </document>
+    <infoset>
+      <dfdlInfoset>
+        <ex:TwoByteSwapTest xmlns="">
+          <Block>
+            <Data>0</Data>
+            <Data>256</Data>
+          </Block>
+        </ex:TwoByteSwapTest>
+      </dfdlInfoset>
+    </infoset>
+  </parserTestCase>
+
+  <unparserTestCase name="test_twobyteswap_unparse_odd" root="TwoByteSwapTest"
+                    
model="org/apache/daffodil/layers/xsd/testTwoByteSwapByte.dfdl.xsd"
+                    roundTrip="none">
+    <infoset>
+      <dfdlInfoset>
+        <ex:TwoByteSwapTest xmlns="">
+          <Block>
+            <Data>1</Data>
+            <Data>2</Data>
+            <Data>3</Data>
+          </Block>
+        </ex:TwoByteSwapTest>
+      </dfdlInfoset>
+    </infoset>
+    <errors>
+      <error>not a multiple of 2</error>
+    </errors>
+  </unparserTestCase>
+
+  <!-- 0 and 1 byteswapped results in 00 00 and 01 00 or 0 and 256-->
+  <parserTestCase name="test_twobyteswap_02" root="TwoByteSwapTest" 
model="org/apache/daffodil/layers/xsd/testTwoByteSwapShort.dfdl.xsd">
+    <document>
+      <documentPart type="byte">00 00 00 01</documentPart>
+    </document>
+    <infoset>
+      <dfdlInfoset>
+        <ex:TwoByteSwapTest xmlns="">
+          <Block>
+            <Data>0</Data>
+            <Data>256</Data>
+          </Block>
+        </ex:TwoByteSwapTest>
+      </dfdlInfoset>
+    </infoset>
+  </parserTestCase>
+
+  <!-- 1-9 byte swaped -->
+  <parserTestCase name="test_twobyteswap_03" root="TwoByteSwapTest" 
model="org/apache/daffodil/layers/xsd/testTwoByteSwapShort.dfdl.xsd">
+    <document>
+      <documentPart type="byte">00 01 00 02 00 03 00 04 00 05 00 06 00 07 00 
08 00 09</documentPart>
+    </document>
+    <infoset>
+      <dfdlInfoset>
+        <ex:TwoByteSwapTest xmlns="">
+          <Block>
+            <Data>256</Data>
+            <Data>512</Data>
+            <Data>768</Data>
+            <Data>1024</Data>
+            <Data>1280</Data>
+            <Data>1536</Data>
+            <Data>1792</Data>
+            <Data>2048</Data>
+            <Data>2304</Data>
+          </Block>
+        </ex:TwoByteSwapTest>
+      </dfdlInfoset>
+    </infoset>
+  </parserTestCase>
+
+  <!--The same as test 3 but reversed.-->
+  <parserTestCase name="test_twobyteswap_04" root="TwoByteSwapTest" 
model="org/apache/daffodil/layers/xsd/testTwoByteSwapShort.dfdl.xsd">
+    <document>
+      <documentPart type="byte">01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 
00 09 00</documentPart>
+    </document>
+    <infoset>
+      <dfdlInfoset>
+        <ex:TwoByteSwapTest xmlns="">
+          <Block>
+            <Data>1</Data>
+            <Data>2</Data>
+            <Data>3</Data>
+            <Data>4</Data>
+            <Data>5</Data>
+            <Data>6</Data>
+            <Data>7</Data>
+            <Data>8</Data>
+            <Data>9</Data>
+          </Block>
+        </ex:TwoByteSwapTest>
+      </dfdlInfoset>
+    </infoset>
+  </parserTestCase>
+
+  <parserTestCase name="test_twobyteswap_05" root="TwoByteSwapTest" 
model="org/apache/daffodil/layers/xsd/testTwoByteSwapShort.dfdl.xsd">
+    <document>
+      <documentPart type="byte">01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 
00 09 00</documentPart>
+    </document>
+    <infoset>
+      <dfdlInfoset>
+        <ex:TwoByteSwapTest xmlns="">
+          <Block>
+            <Data>1</Data>
+            <Data>2</Data>
+            <Data>3</Data>
+            <Data>4</Data>
+            <Data>5</Data>
+            <Data>6</Data>
+            <Data>7</Data>
+            <Data>8</Data>
+            <Data>9</Data>
+          </Block>
+        </ex:TwoByteSwapTest>
+      </dfdlInfoset>
+    </infoset>
+  </parserTestCase>
+
+  <!--Odd bytes.-->
+  <parserTestCase name="test_twobyteswap_bad_01" root="TwoByteSwapTest" 
model="org/apache/daffodil/layers/xsd/testTwoByteSwapShort.dfdl.xsd">
+    <document>
+      <documentPart type="byte">
+        01 00 02 00
+        03 00 04 00
+        05 00 06 00
+        07 00 08 00
+        09 00 00
+      </documentPart>
+    </document>
+    <errors>
+      <error>Data length is not a multiple of 2</error>
+    </errors>
+  </parserTestCase>
+
+  <!--Odd bytes.-->
+  <parserTestCase name="test_twobyteswap_bad_02" root="TwoByteSwapTest" 
model="org/apache/daffodil/layers/xsd/testTwoByteSwapByte.dfdl.xsd">
+    <document>
+      <documentPart type="byte">01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 
00 09 00 10</documentPart>
+    </document>
+    <errors>
+      <error>Data length is not a multiple of 2</error>
+    </errors>
+  </parserTestCase>
+
+  <!--Odd bytes.-->
+  <parserTestCase name="test_twobyteswap_bad_03" root="TwoByteSwapTest" 
model="org/apache/daffodil/layers/xsd/testTwoByteSwap.dfdl.xsd">
+    <document>
+      <documentPart type="byte">02 01 04 03 05 06</documentPart>
+    </document>
+    <errors>
+      <error>Failed to populate Data</error>
+      <error>Data length is not a multiple of 2</error>
+    </errors>
+  </parserTestCase>
+
+</testSuite>
diff --git 
a/daffodil-test/src/test/resources/org/apache/daffodil/layers/xsd/testTwoByteSwap.dfdl.xsd
 
b/daffodil-test/src/test/resources/org/apache/daffodil/layers/xsd/testTwoByteSwap.dfdl.xsd
new file mode 100644
index 000000000..544b878d9
--- /dev/null
+++ 
b/daffodil-test/src/test/resources/org/apache/daffodil/layers/xsd/testTwoByteSwap.dfdl.xsd
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<schema xmlns="http://www.w3.org/2001/XMLSchema";
+        xmlns:xs="http://www.w3.org/2001/XMLSchema";
+        xmlns:dfdl="http://www.ogf.org/dfdl/dfdl-1.0/";
+        xmlns:dfdlx="http://www.ogf.org/dfdl/dfdl-1.0/extensions";
+        xmlns:fn="http://www.w3.org/2005/xpath-functions";
+        xmlns:daf="urn:ogf:dfdl:2013:imp:daffodil.apache.org:2018:ext"
+        xmlns:twobyteSwap="urn:org.apache.daffodil.layers.byteSwap"
+        xmlns:ex="http://example.com";
+        targetNamespace="http://example.com";>
+
+  <include 
schemaLocation="/org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>
+
+  <xs:import namespace="urn:org.apache.daffodil.layers.byteSwap"
+             
schemaLocation="/org/apache/daffodil/layers/xsd/byteSwapLayer.dfdl.xsd"/>
+
+  <annotation>
+    <appinfo source="http://www.ogf.org/dfdl/";>
+      <dfdl:format ref="ex:GeneralFormat"
+                   representation="binary"
+                   lengthUnits="bits"
+      />
+    </appinfo>
+  </annotation>
+
+  <group name="setVars">
+    <sequence>
+      <annotation><appinfo source="http://www.ogf.org/dfdl/";>
+        <dfdl:setVariable ref="twobyteSwap:requireLengthInWholeWords" 
value="yes"/>
+      </appinfo></annotation>
+    </sequence>
+  </group>
+
+  <element name="TwoByteSwapTest">
+    <complexType>
+      <sequence>
+        <group ref="ex:setVars"/>
+        <element name="len5" dfdl:lengthKind="explicit" dfdl:length="5"
+                 dfdl:lengthUnits="bytes"><!-- note odd fixed length -->
+          <complexType>
+            <sequence>
+              <sequence dfdlx:layer="twobyteSwap:twobyteswap">
+                <element name="Block">
+                  <complexType>
+                    <sequence>
+                      <!-- this will not pull data from the underlying layer 2 
bytes at a time.
+                       Rather, the I/O layer tries to fill this and hits the 
end of data and detects odd length so
+                       causes a PE which ends the array with zero elements in 
it.
+                        That will not cause the layer to fail, just to 
backtrack to the start of the layer data. -->
+                      <element name="Data" type="unsignedShort"
+                               minOccurs="2"
+                               maxOccurs="30"
+                               dfdl:lengthKind="explicit"
+                               dfdl:length="16"
+                               dfdl:occursCountKind="implicit"/>
+                      <!-- Then this optional element is pulled. It will also 
fail due to the odd length of the layer. -->
+                      <element name="postData" type="unsignedByte" 
minOccurs="0"/>
+                    </sequence>
+                  </complexType>
+                </element><!-- end block -->
+              </sequence><!-- end layer -->
+              <!-- this postLayer is after the empty layer
+                 The layer -->
+              <element name="postLayer" type="unsignedByte" minOccurs="0"/>
+            </sequence>
+          </complexType>
+        </element><!-- end len5 -->
+        <element name="last" type="xs:unsignedByte" minOccurs="0"/>
+      </sequence>
+    </complexType>
+  </element>
+
+
+</schema>
diff --git 
a/daffodil-test/src/test/resources/org/apache/daffodil/layers/xsd/testTwoByteSwapByte.dfdl.xsd
 
b/daffodil-test/src/test/resources/org/apache/daffodil/layers/xsd/testTwoByteSwapByte.dfdl.xsd
new file mode 100644
index 000000000..3a17fb0d4
--- /dev/null
+++ 
b/daffodil-test/src/test/resources/org/apache/daffodil/layers/xsd/testTwoByteSwapByte.dfdl.xsd
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<schema xmlns="http://www.w3.org/2001/XMLSchema";
+        xmlns:xs="http://www.w3.org/2001/XMLSchema";
+        xmlns:dfdl="http://www.ogf.org/dfdl/dfdl-1.0/";
+        xmlns:dfdlx="http://www.ogf.org/dfdl/dfdl-1.0/extensions";
+        xmlns:fn="http://www.w3.org/2005/xpath-functions";
+        xmlns:daf="urn:ogf:dfdl:2013:imp:daffodil.apache.org:2018:ext"
+        xmlns:twobyteSwap="urn:org.apache.daffodil.layers.byteSwap"
+        xmlns:ex="http://example.com";
+        targetNamespace="http://example.com";>
+
+  <include 
schemaLocation="/org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>
+
+  <xs:import namespace="urn:org.apache.daffodil.layers.byteSwap"
+             
schemaLocation="/org/apache/daffodil/layers/xsd/byteSwapLayer.dfdl.xsd"/>
+
+  <annotation>
+    <appinfo source="http://www.ogf.org/dfdl/";>
+      <dfdl:format ref="ex:GeneralFormat"
+                   representation="binary"
+                   lengthUnits="bits"
+      />
+    </appinfo>
+  </annotation>
+
+  <group name="setVars">
+    <sequence>
+      <annotation><appinfo source="http://www.ogf.org/dfdl/";>
+        <dfdl:setVariable ref="twobyteSwap:requireLengthInWholeWords" 
value="yes"/>
+      </appinfo></annotation>
+    </sequence>
+  </group>
+
+  <element name="TwoByteSwapTest">
+    <complexType>
+      <sequence>
+        <group ref="ex:setVars"/>
+        <sequence dfdlx:layer="twobyteSwap:twobyteswap">
+          <element name="Block">
+            <complexType>
+              <sequence>
+                <element name="Data"
+                         minOccurs="1"
+                         maxOccurs="30"
+                         dfdl:lengthKind="explicit"
+                         dfdl:length="8"
+                         dfdl:occursCountKind="implicit">
+                  <simpleType>
+                    <restriction base="unsignedByte">
+                      <minInclusive value="0"/>
+                      <maxInclusive value="255"/>
+                    </restriction>
+                  </simpleType>
+                </element>
+                <element name="Extra"
+                         type="unsignedByte"
+                         minOccurs="0"
+                         maxOccurs="1"
+                         dfdl:lengthKind="explicit"
+                         dfdl:length="8"
+                         dfdl:occursCountKind="implicit"/>
+              </sequence>
+            </complexType>
+          </element>
+        </sequence>
+      </sequence>
+    </complexType>
+  </element>
+
+</schema>
diff --git 
a/daffodil-test/src/test/resources/org/apache/daffodil/layers/xsd/testTwoByteSwapShort.dfdl.xsd
 
b/daffodil-test/src/test/resources/org/apache/daffodil/layers/xsd/testTwoByteSwapShort.dfdl.xsd
new file mode 100644
index 000000000..3794d7e6b
--- /dev/null
+++ 
b/daffodil-test/src/test/resources/org/apache/daffodil/layers/xsd/testTwoByteSwapShort.dfdl.xsd
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<schema xmlns="http://www.w3.org/2001/XMLSchema";
+        xmlns:xs="http://www.w3.org/2001/XMLSchema";
+        xmlns:dfdl="http://www.ogf.org/dfdl/dfdl-1.0/";
+        xmlns:dfdlx="http://www.ogf.org/dfdl/dfdl-1.0/extensions";
+        xmlns:fn="http://www.w3.org/2005/xpath-functions";
+        xmlns:daf="urn:ogf:dfdl:2013:imp:daffodil.apache.org:2018:ext"
+        xmlns:twobyteSwap="urn:org.apache.daffodil.layers.byteSwap"
+        xmlns:ex="http://example.com";
+        targetNamespace="http://example.com";>
+
+  <include 
schemaLocation="/org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>
+
+  <xs:import namespace="urn:org.apache.daffodil.layers.byteSwap"
+             
schemaLocation="/org/apache/daffodil/layers/xsd/byteSwapLayer.dfdl.xsd"/>
+
+  <annotation>
+    <appinfo source="http://www.ogf.org/dfdl/";>
+      <dfdl:format ref="ex:GeneralFormat"
+                   representation="binary"
+                   lengthUnits="bits"
+      />
+    </appinfo>
+  </annotation>
+
+  <group name="setVars">
+    <sequence>
+      <annotation><appinfo source="http://www.ogf.org/dfdl/";>
+        <dfdl:setVariable ref="twobyteSwap:requireLengthInWholeWords" 
value="yes"/>
+      </appinfo></annotation>
+    </sequence>
+  </group>
+
+  <element name="TwoByteSwapTest">
+    <complexType>
+      <sequence>
+        <group ref="ex:setVars"/>
+        <sequence dfdlx:layer="twobyteSwap:twobyteswap">
+          <element name="Block">
+            <complexType>
+              <sequence>
+                <element name="Data"
+                         minOccurs="1"
+                         maxOccurs="30"
+                         dfdl:lengthKind="explicit"
+                         dfdl:length="16"
+                         dfdl:occursCountKind="implicit">
+                  <simpleType>
+                    <restriction base="unsignedShort">
+                      <minInclusive value="0"/>
+                      <maxInclusive value="65535"/>
+                    </restriction>
+                  </simpleType>
+                </element>
+              </sequence>
+            </complexType>
+          </element>
+        </sequence>
+      </sequence>
+    </complexType>
+  </element>
+
+</schema>
diff --git 
a/daffodil-test/src/test/scala/org/apache/daffodil/runtime1/layers/TestByteSwap.scala
 
b/daffodil-test/src/test/scala/org/apache/daffodil/runtime1/layers/TestByteSwap.scala
new file mode 100644
index 000000000..3c233455c
--- /dev/null
+++ 
b/daffodil-test/src/test/scala/org/apache/daffodil/runtime1/layers/TestByteSwap.scala
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.daffodil.runtime1.layers
+
+import org.apache.daffodil.tdml.Runner
+
+import org.junit.AfterClass
+import org.junit.Test
+
+object TestByteSwap {
+  private val testDir = "/org/apache/daffodil/layers/"
+
+  private lazy val runner = Runner(testDir, "TestTwoByteSwap.tdml")
+
+  @AfterClass def shutDown(): Unit = {
+    runner.reset()
+  }
+}
+
+class TestByteSwap {
+  import TestByteSwap._
+
+  @Test def test_twobyteswap_01(): Unit = { 
runner.runOneTest("test_twobyteswap_01") }
+
+  @Test def test_twobyteswap_02(): Unit = { 
runner.runOneTest("test_twobyteswap_02") }
+
+  @Test def test_twobyteswap_03(): Unit = { 
runner.runOneTest("test_twobyteswap_03") }
+
+  @Test def test_twobyteswap_04(): Unit = { 
runner.runOneTest("test_twobyteswap_04") }
+
+  @Test def test_twobyteswap_05(): Unit = { 
runner.runOneTest("test_twobyteswap_05") }
+
+  @Test def test_twobyteswap_bad_01(): Unit = { 
runner.runOneTest("test_twobyteswap_bad_01") }
+
+  @Test def test_twobyteswap_bad_02(): Unit = { 
runner.runOneTest("test_twobyteswap_bad_02") }
+
+  @Test def test_twobyteswap_bad_03(): Unit = { 
runner.runOneTest("test_twobyteswap_bad_03") }
+
+  @Test def test_twobyteswap_unparse_odd(): Unit = {
+    runner.runOneTest("test_twobyteswap_unparse_odd")
+  }
+
+}

Reply via email to