tuxji commented on a change in pull request #529:
URL: https://github.com/apache/daffodil/pull/529#discussion_r614236577
##########
File path:
daffodil-runtime1/src/main/scala/org/apache/daffodil/layers/GZipTransformer.scala
##########
@@ -69,3 +69,84 @@ object GZIPTransformerFactory
xformer
}
}
+
+
+object GZIPFixedOutputStream {
+
+ private val fixIsNeeded = !scala.util.Properties.isJavaAtLeast("16")
+
+ /**
+ * Create a GZIPOutputStream that, if necessary, proxies writes through an
+ * OutputStream that fixes inconsistencies between Java versions
+ */
+ def apply(os: java.io.OutputStream) = {
+ val fixedOS = if (fixIsNeeded) new GZIPFixedOutputStream(os) else os
+ new java.util.zip.GZIPOutputStream(fixedOS)
+ }
+}
+
+/**
+ * Prior to Java 16, the java.util.zip.GZIPOutputStream wrote a value of zero
for
+ * the OS field in the header (byte index 9). In Java 16, this was changed to a
+ * value of 255 to better abide by the GZIP specification. Unfortunately, this
+ * means unparsed data using a GZIP layer might have a single byte difference,
+ * depending on the Java version used. This can lead to inconsistent behavior
of
+ * test failures that expect a certain byte value.
+ *
+ * To resolve this issue, we create this GZIPFixedOutputStream. This should
wrap
+ * the underlying OutputStream and be passed as the OutputStream to the
+ * GZIPOutputStream. When the GZIPOutputStream writes the 9th byte to this
+ * GZIPFixedOutputStream, this will always write a value of 255, making all
Java
+ * versions prior to 16 consistent with Java 16+ behavior.
+ */
+class GZIPFixedOutputStream private (os: java.io.OutputStream) extends
java.io.OutputStream {
+
+ /**
+ * The next byte position that byte will be written to. If this is negative,
+ * that means we have already fixed the output and everything should just
+ * pass straight through.
+ */
+ private var bytePosition = 0
+
+ override def close(): Unit = os.close()
+ override def flush(): Unit = os.flush()
+
+ override def write(b: Array[Byte], off: Int, len: Int): Unit = {
+ if (bytePosition < 0) {
+ // The bad byte has been fixed, pass all writes directly through to the
+ // underlying OutputStream. This may be more efficient than the default
+ // OutputStream write() function, which writes the bytes from his array
+ // one at a time
+ os.write(b, off, len)
+ } else {
+ // The bad byte has not been fixed yet. Unless a newer version of Java
+ // has made changes, the GZIPOutputStreamm will have passed in a 10 byte
+ // array to this function that includes the bad byte. Let's just write
+ // that array using the default write(array) method that writes these
+ // bytes one at a time and will call the write(int) method that will fix
+ // that byte. Calling write() one at a time is maybe inefficient but for
+ // such a small array it should not have a noticeable effect.
+ super.write(b, off, len)
+ }
+ }
+
+ override def write(b: Int): Unit = {
+ if (bytePosition < 0) {
+ // The bad byte has already been fixed, simply pass this byte through to
+ // the underlying OutputStream
+ os.write(b)
Review comment:
We have a check warning at this line saying this line was not covered by
tests. Why didn't the tests call this line?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]