I updated the schema to define the fillByte property at the global level (under 
xs:annotation). Now the unparsing is working without error.  
The fillByte property defined for the sequence has no impact whether it is 
present or not -- it is not overriding the global fillByte value.

Do the code changes you suggest impact the above behavior? 

On a related note, there is an open ticket that says fillByte allows only raw 
byte values and not DFDL entities: 
https://issues.apache.org/jira/browse/DAFFODIL-1646 
The example XSD uses DFDL entity value for fillByte. Can DAFFODIL-1646 be 
closed? 


Regards,

   Shashi Ramaka
   sram...@owlcyberdefense.com 
   Tel: 703-965-3656

-----Original Message-----
From: Steve Lawrence <slawre...@apache.org> 
Sent: Friday, October 16, 2020 1:43 PM
To: dev@daffodil.apache.org
Subject: Re: DAFFODIL-2377

The issue appears to be with how we don't really require fillByte until runtime.

RuntimePropertyMixins.scala defines maybeFillByteEv, which returns the 
FillByteEv if the dfdl:fillByte property is provided on the schema element. If 
it's not provided, it's just a Nope and we don't have a fill byte. So our code 
for creating FillByteEv implies that the dfdl:fillByte property is not 
mandatory.

But then in ProcessorStateBases.scala, the def fillByte function does

  maybeFillByteEv.get

So that requires that maybeFillByteEv is defined when we determine we needed to 
fill some bytes, and thus the dfdl:fillByteProperty is mandatory.

Seems to me we should just make the fill byte property mandatory. I don't know 
if there are cases where we should actually consider it optional.

Solution 1:

Change RuntimePropertyMixins.scala so that maybeFillByEv is no longer a Maybe, 
and it becomes something like this:

  final lazy val fillByteEv = {
    val ev = new FillByteEv(fillByte, charsetEv, tci)
    ev.compile(tunable)
    ev
  }

So fill byte is always required to be defined in the schema. And then change 
all references to maybeFillByteEv to just fillByteEv. And follow the variable 
until ProcessorStateBases.scala just becomes

  filleByteEv

instead of

  maybeFillByteEv.get

This way, if anything ever uses the fillByteEv variable, we require the 
fillByte property to exist, and if it doesn't we'll get an SDE at schema 
compile time. And then if fillByte is ever needed, then it will be available.

The only issue with this approach is it might break schemas that don't provide 
fillByte, since we now will always require fill byte where it might not have 
been technically needed before. But I think we were just getting lucky, and 
probably most schemas already defined it.

Solution 2:

Another option would be to just change ProcessorStateBases to be something like 
this:

    if (termRuntimeData.maybeFillByteEv.isEmpty) {
      SDE("fillByte property required")
    } else {
      maybeCachedFillByte =
MaybeInt(termRuntimeData.maybeFillByteEv.get....)
    }

So at runtime, if we need to fill some bytes but maybeFillByteEv isn't defined 
(i.e. the schema didn't define fillByte), then we throw a Runtime SDE. This 
maintains backwards compatibility, but doesn't detect the missing property 
until runtime, which is unfortunately. I'm not sure if it's wroth maintaining 
that for this issue though. I'd probably lean towards the first solution and 
just always require fillByte.


On 10/16/20 1:16 PM, Ramaka, Shashi wrote:
> I am working on DAFFODIL-2377: Abort instead of diagnostic message. 
> (https://issues.apache.org/jira/browse/DAFFODIL-2377
> <https://issues.apache.org/jira/browse/DAFFODIL-2377>)
> 
> The attached files can be used to illustrate the bug.
> 
> daffodil parse -s s2377.xsd -o d2377.xml d2377.bin
> 
> daffodil unparse -s s2377.xsd d2377.xml
> 
> Unparsing results in the below error:
> 
> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
> 
> !!   An unexpected exception occurred. This is a bug!   !!
> 
> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
> 
> The schema has three elements. The first element has a length of 1 
> byte and alignment of 1 byte while the next two elements have length = 
> 1 and alignment = 2. The unparser is unparsing the first element 
> correctly but throwing the above exception while determining the 
> second element. Specifically it is failing figuring out the fill byte to be 
> used.
> 
> The unparser is failing on the highlighted line in 
> ProcessorStateBase.scala in
> daffodil-runtime1:
> 
> final def fillByte: Byte = {
>    if (maybeCachedFillByte.isEmpty)
> *    maybeCachedFillByte = 
> MaybeInt(termRuntimeData.maybeFillByteEv.get.evaluate(this).toInt)
> *  maybeCachedFillByte.get.toByte
> }
> 
> Seems like the processor state in termRuntimeData does not have the 
> fill byte value from the schema. If I update the above fillByte to 
> return a hard coded byte value, unparse is working fine.
> 
> I'd appreciate any pointers on how to proceed from here.
> 
> Regards,
> 
>     Shashi Ramaka
> 
> sram...@owlcyberdefense.com <mailto:sram...@owlcyberdefense.com>
> 
>     Tel: 703-965-3656
> 

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema";
     xmlns:dfdl="http://www.ogf.org/dfdl/dfdl-1.0/";
     xmlns:fn="http://www.w3.org/2005/xpath-functions";
     elementFormDefault="qualified">
     
     <xs:annotation>
         <xs:appinfo source="http://www.ogf.org/dfdl/";>
             <dfdl:format
                 textBidi="no"
                 floating="no"
                 encodingErrorPolicy="replace"
                 leadingSkip="0" 
                 alignmentUnits="bytes"
                 alignment="1" 
                 trailingSkip="0"
                 textPadKind="none"
                 escapeSchemeRef=""
                 truncateSpecifiedLengthString="no"
                 textTrimKind="none" 
                 binaryNumberRep="binary"
                 
                 representation="binary"
                 byteOrder="littleEndian"
                 encoding="ISO-8859-1"
                 sequenceKind="ordered"
                 initiator=""
                 terminator=""
                 separator=""
                 ignoreCase = "yes"
                 initiatedContent="no"
                 fillByte="%NUL;"
             />
         </xs:appinfo>
     </xs:annotation>
     
     <xs:element name="input"
         dfdl:lengthKind="implicit"
         dfdl:lengthUnits="bytes"
         >
         <xs:complexType>
             <xs:sequence dfdl:fillByte="%FF;">
                    <xs:element name="A" type="xs:unsignedInt" 
                     dfdl:lengthKind="explicit"
                     dfdl:length="1"
                     dfdl:lengthUnits="bytes"
                     dfdl:alignment="1"
                     dfdl:alignmentUnits="bytes"
                 />
                 <xs:element name="B" type="xs:unsignedInt" 
                     dfdl:lengthKind="explicit"
                     dfdl:length="1"
                     dfdl:lengthUnits="bytes"
                     dfdl:alignment="2"
                     dfdl:alignmentUnits="bytes"
                 />
                 <xs:element name="C" type="xs:unsignedInt" 
                     dfdl:lengthKind="explicit"
                     dfdl:length="1"
                     dfdl:lengthUnits="bytes"
                     dfdl:alignment="2"
                     dfdl:alignmentUnits="bytes"
                 />
             </xs:sequence>
         </xs:complexType>
     </xs:element>
     
 </xs:schema>

Reply via email to