Upgrade XZ for Java to v1.9 am: b219c5e34d am: a813ee2e1f am: 7c65c7cb31

Original change: https://android-review.googlesource.com/c/platform/external/xz-java/+/2850173

Change-Id: I2588b418bbb745f36e29d43e2ce0f67296c84620
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/COPYING b/COPYING
index c1d404d..8dd1764 100644
--- a/COPYING
+++ b/COPYING
@@ -2,9 +2,9 @@
 Licensing of XZ for Java
 ========================
 
-    All the files in this package have been written by Lasse Collin
-    and/or Igor Pavlov. All these files have been put into the
-    public domain. You can do whatever you want with these files.
+    All the files in this package have been written by Lasse Collin,
+    Igor Pavlov, and/or Brett Okken. All these files have been put into
+    the public domain. You can do whatever you want with these files.
 
     This software is provided "as is", without any warranty.
 
diff --git a/METADATA b/METADATA
index 942198e..abad0ef 100644
--- a/METADATA
+++ b/METADATA
@@ -1,19 +1,23 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update xz-java
+# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
+
 name: "XZ for Java"
 description: "This aims to be a complete implementation of XZ data compression in pure Java. Single-threaded streamed compression and decompression and random access decompression have been fully implemented. Threading is planned but it is unknown when it will be implemented."
 third_party {
-  url {
-    type: HOMEPAGE
-    value: "https://tukaani.org/xz/java.html"
-  }
-  url {
-    type: GIT
-    value: "https://git.tukaani.org/xz-java.git"
-  }
-  version: "v1.8"
   license_type: UNENCUMBERED
   last_upgrade_date {
-    year: 2019
-    month: 1
-    day: 18
+    year: 2023
+    month: 11
+    day: 28
+  }
+  identifier {
+    type: "HOMEPAGE"
+    value: "https://tukaani.org/xz/java.html"
+  }
+  identifier {
+    type: "GIT"
+    value: "https://github.com/tukaani-project/xz-java.git"
+    version: "v1.9"
   }
 }
diff --git a/NEWS b/NEWS
index 3183f2e..d18a53b 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,32 @@
 XZ for Java release notes
 =========================
 
+1.9 (2021-03-12)
+
+    * Add LZMAInputStream.enableRelaxedEndCondition(). It allows
+      decompression of LZMA streams whose uncompressed size is known
+      but it is unknown if the end of stream marker is present. This
+      method is meant to be useful in Apache Commons Compress to
+      support .7z files created by certain very old 7-Zip versions.
+      Such files have the end of stream marker in the LZMA data even
+      though the uncompressed size is known. 7-Zip supports such files
+      and thus other implementations of the .7z format should support
+      them too.
+
+    * Make LZMA/LZMA2 decompression faster. With files that compress
+      extremely well the performance can be a lot better but with
+      more typical files the improvement is minor.
+
+    * Make the CRC64 code faster.
+
+    * Add module-info.java as multi-release JAR. The attribute
+      Automatic-Module-Name was removed.
+
+    * The binaries for XZ for Java 1.9 in the Maven Central now
+      require Java 7. Building the package requires at least Java 9
+      for module-info support but otherwise the code should still be
+      Java 5 compatible (see README and comments in build.properties).
+
 1.8 (2018-01-04)
 
     * Fix a binary compatibility regression: XZ for Java 1.7 binaries
diff --git a/README b/README
index 8869996..ed592c8 100644
--- a/README
+++ b/README
@@ -18,23 +18,54 @@
 
         https://tukaani.org/xz/java.html
 
-    The source code is compatible with Java 5 and later.
+    The source code is compatible with Java 5 and later (except
+    module-info.java which is Java 9 or later). However, the default
+    build options require OpenJDK 11 or later, and create Java 7
+    compatible binaries.
 
-Building
+Building with Apache Ant
 
-    It is recommended to use Apache Ant. Type "ant" to compile the
-    classes and create the .jar files. Type "ant doc" to build the
-    javadoc HTML documentation. Note that building the documentation
-    will download a small file named "package-list" from Oracle to
-    enable linking to the documentation of the standard Java classes.
+    Type "ant" to compile the classes and create the .jar files.
+    Type "ant doc" to build the javadoc HTML documentation. Note
+    that building the documentation will download a small file named
+    "element-list" or "package-list" from Oracle to enable linking to
+    the documentation of the standard Java classes.
 
-    If you are using OpenJDK 9 or later, you will need to edit the
-    "sourcever = 1.5" line in the file "build.properties" before
-    running "ant". Set it to 1.6 or higher. The default value 1.5
-    isn't supported by OpenJDK 9 or later.
+    If you are using Ant older than 1.9.8:
 
-    If you cannot or don't want to use Ant, just compile all .java
-    files under the "src" directory.
+        Edit build.xml and remove the release attributes from <javac>
+        tags, that is, remove all occurrences of these two lines:
+
+            release="${sourcever}"
+
+            release="${sourcever9}"
+
+        The downside of the above is that then -source and -target
+        options will be used instead of --release.
+
+    If you are using OpenJDK version older than 11:
+
+        Adjust extdoc_url and extdoc_file to point to an older URL
+        and to use "package-list" instead of "element-list". This
+        modification isn't required if the documentation won't be
+        built.
+
+    If you are using OpenJDK version older than 9:
+
+        Comment the sourcever9 line in the file build.properties.
+        When it is commented, module-info.java won't be built and
+        xz.jar won't be a modular JAR.
+
+    If you are using OpenJDK version older than 7:
+
+        In build.properties, set "sourcever = 5" or "sourcever = 6"
+        to be compatible with Java 5 or 6.
+
+Building without Apache Ant
+
+    If you cannot or don't want to use Ant, just compile all .java files
+    under the "src" directory (possibly skip the demo files src/*.java).
+    For module support (Java >= 9) compile also src9/module-info.java.
 
 Demo programs
 
diff --git a/build.properties b/build.properties
index fd5c373..052d972 100644
--- a/build.properties
+++ b/build.properties
@@ -9,25 +9,51 @@
 
 title = XZ data compression
 homepage = https://tukaani.org/xz/java.html
-version = 1.8
+version = 1.9
 debug = false
 
-# sourcever sets -source and -target options for javac.
+# sourcever sets --release for javac 9 (or later) or -source and -target for
+# older javac versions which don't support --release. The main source code is
+# Java 5 compatible but the oldest -source/-target pair (and also --release)
+# that OpenJDK 15 supports is 7 (Java 7).
 #
-# The source code is Java 5 compatible but the oldest -source/-target pair
-# that OpenJDK 9 supports is 1.6 (Java 6). Edit this if you are using
-# OpenJDK 9 or later.
-sourcever = 1.5
+# sourcever9 does the same as sourcever but for files that require Java 9 or
+# later. The resulting classes are packaged as multi-release JAR, including
+# module-info.java. If sourcever9 is commented out, these files won't be
+# built but the package will still work.
+#
+# If you need to build this on an older JDK:
+#   - Set sourcever appropriately (5 or higher)
+#   - Comment the sourcever9 line below to disable building Java 9 files.
+#   - Adjust extdoc_url and extdoc_file to point to older documentation.
+sourcever = 7
+sourcever9 = 9
 
 src_dir = src
+src9_dir = src9
 build_dir = build
 dist_dir = ${build_dir}/dist
 dist_file = ${dist_dir}/xz-java-${version}.zip
 classes_dir = ${build_dir}/classes
+classes9_dir = ${build_dir}/classes9
 jar_dir = ${build_dir}/jar
 doc_dir = ${build_dir}/doc
 
-extdoc_url = https://docs.oracle.com/javase/9/docs/api
+# extdoc_url and extdoc_file must be modified as a pair.
+#
+# Possible values for extdoc_url:
+#     https://docs.oracle.com/javase/7/docs/api
+#     https://docs.oracle.com/javase/8/docs/api
+#     https://docs.oracle.com/javase/9/docs/api
+#     https://docs.oracle.com/en/java/javase/11/docs/api
+#     ...
+#     https://docs.oracle.com/en/java/javase/15/docs/api
+#
+# Possible values for extdoc_file:
+#   - Java 7, 8, and 9: package-list
+#   - Java 11 and later: element-list
+extdoc_url = https://docs.oracle.com/en/java/javase/15/docs/api
+extdoc_file = element-list
 extdoc_dir = extdoc
 
 pom_template = maven/pom_template.xml
diff --git a/build.xml b/build.xml
index 4abaec6..0559836 100644
--- a/build.xml
+++ b/build.xml
@@ -14,7 +14,7 @@
     <property file="build.properties"/>
 
     <target name="clean"
-            description="Deletes generated files except 'extdoc/package-list'">
+            description="Deletes generated files except 'extdoc'">
         <delete dir="${build_dir}"/>
     </target>
 
@@ -28,6 +28,7 @@
         <zip destfile="${dist_file}">
             <fileset dir="." includesfile="fileset-misc.txt"/>
             <fileset dir="." includesfile="fileset-src.txt"/>
+            <fileset dir="." includesfile="fileset-src9.txt"/>
         </zip>
     </target>
 
@@ -35,11 +36,15 @@
             description="Generates HTML documentation with javadoc">
         <mkdir dir="${doc_dir}"/>
         <mkdir dir="${extdoc_dir}"/>
-        <get src="${extdoc_url}/package-list"
+        <!-- Ant 1.10.9 doesn't recognize element-list. To workaround this
+             we rename element-list to package-list when downloading.
+             javadoc from Java 15 seems to be fine with this hack. -->
+        <get src="${extdoc_url}/${extdoc_file}"
              dest="${extdoc_dir}/package-list" skipexisting="true"/>
         <javadoc sourcepath="${src_dir}" destdir="${doc_dir}"
-                 source="${sourcever}" packagenames="org.tukaani.xz"
+                 packagenames="org.tukaani.xz"
                  windowtitle="XZ data compression"
+                 nodeprecatedlist="true" nohelp="true"
                  linkoffline="${extdoc_url} ${extdoc_dir}"/>
     </target>
 
@@ -48,9 +53,39 @@
         <javac srcdir="." sourcepath="${src_dir}" destdir="${classes_dir}"
                includeAntRuntime="false" debug="${debug}"
                source="${sourcever}" target="${sourcever}"
+               release="${sourcever}"
                includesfile="fileset-src.txt"
                excludes="**/package-info.java">
-            <compilerarg compiler="modern" value="-Xlint"/>
+            <compilerarg compiler="modern" line="-Xlint -Xlint:-options"/>
+        </javac>
+
+        <!-- Build Java 9 files only if sourcever9 is set: -->
+        <mkdir dir="${classes9_dir}"/>
+        <condition property="exclude_java9" value="**">
+            <not><isset property="sourcever9"/></not>
+        </condition>
+
+        <!-- Regular Java 9 files excluding module-info.java: -->
+        <javac srcdir="." sourcepath="${src_dir}"
+               destdir="${classes9_dir}"
+               classpath="${classes_dir}"
+               includeAntRuntime="false" debug="${debug}"
+               release="${sourcever9}"
+               includesfile="fileset-src9.txt"
+               excludes="${exclude_java9} **/module-info.java">
+            <compilerarg compiler="modern" line="-Xlint"/>
+        </javac>
+
+        <!-- module-info.java needs special treatment because it wants to
+             be on the source path and also see source files from the
+             package being exported. -->
+        <javac srcdir="." sourcepath="${src9_dir}:${src_dir}"
+               destdir="${classes9_dir}"
+               includeAntRuntime="false" debug="${debug}"
+               release="${sourcever9}"
+               includes="src9/module-info.java"
+               excludes="${exclude_java9}">
+            <compilerarg compiler="modern" line="-Xlint"/>
         </javac>
     </target>
 
@@ -58,15 +93,15 @@
             description="Creates JAR packages">
         <mkdir dir="${jar_dir}"/>
 
-        <jar destfile="${jar_dir}/xz.jar" basedir="${classes_dir}"
-             includes="org/tukaani/xz/**">
+        <jar destfile="${jar_dir}/xz.jar">
+            <fileset dir="${classes_dir}" includes="org/tukaani/xz/**"/>
+            <zipfileset prefix="META-INF/versions/9/" dir="${classes9_dir}"/>
             <manifest>
                 <attribute name="Implementation-Title" value="${title}"/>
                 <attribute name="Implementation-Version" value="${version}"/>
                 <attribute name="Implementation-URL" value="${homepage}"/>
                 <attribute name="Sealed" value="true"/>
-                <attribute name="Automatic-Module-Name"
-                           value="org.tukaani.xz"/>
+                <attribute name="Multi-Release" value="true"/>
                 <!-- Attributes required for OSGi bundles. -->
                 <attribute name="Bundle-ManifestVersion" value="2"/>
                 <attribute name="Bundle-SymbolicName" value="org.tukaani.xz"/>
@@ -155,8 +190,10 @@
         <jar destfile="${maven_dir}/xz-${version}-javadoc.jar"
              basedir="${doc_dir}"/>
 
-        <jar destfile="${maven_dir}/xz-${version}-sources.jar"
-             basedir="${src_dir}" includes="org/tukaani/xz/**"/>
+        <jar destfile="${maven_dir}/xz-${version}-sources.jar">
+            <fileset dir="${src_dir}" includes="org/tukaani/xz/**"/>
+            <zipfileset prefix="META-INF/versions/9/" dir="${src9_dir}"/>
+        </jar>
     </target>
 
 </project>
diff --git a/fileset-misc.txt b/fileset-misc.txt
index 9d16359..3b1d150 100644
--- a/fileset-misc.txt
+++ b/fileset-misc.txt
@@ -5,6 +5,7 @@
 build.xml
 build.properties
 fileset-src.txt
+fileset-src9.txt
 fileset-misc.txt
 .gitignore
 maven/README
diff --git a/fileset-src9.txt b/fileset-src9.txt
new file mode 100644
index 0000000..d060ebd
--- /dev/null
+++ b/fileset-src9.txt
@@ -0,0 +1 @@
+src9/module-info.java
diff --git a/maven/pom_template.xml b/maven/pom_template.xml
index 235844c..666c51a 100644
--- a/maven/pom_template.xml
+++ b/maven/pom_template.xml
@@ -53,6 +53,11 @@
             <name>Igor Pavlov</name>

             <url>http://7-zip.org/</url>

         </contributor>

+

+        <contributor>

+            <name>Brett Okken</name>

+            <email>brett.okken.os@gmail.com</email>

+        </contributor>

     </contributors>

 

 </project>

diff --git a/src/org/tukaani/xz/BlockInputStream.java b/src/org/tukaani/xz/BlockInputStream.java
index 1931bd6..a9fff5f 100644
--- a/src/org/tukaani/xz/BlockInputStream.java
+++ b/src/org/tukaani/xz/BlockInputStream.java
@@ -44,17 +44,18 @@
         this.verifyCheck = verifyCheck;
         inData = new DataInputStream(in);
 
-        byte[] buf = new byte[DecoderUtil.BLOCK_HEADER_SIZE_MAX];
-
         // Block Header Size or Index Indicator
-        inData.readFully(buf, 0, 1);
+        int b = inData.readUnsignedByte();
 
         // See if this begins the Index field.
-        if (buf[0] == 0x00)
+        if (b == 0x00)
             throw new IndexIndicatorException();
 
         // Read the rest of the Block Header.
-        headerSize = 4 * ((buf[0] & 0xFF) + 1);
+        headerSize = 4 * (b + 1);
+
+        final byte[] buf = new byte[headerSize];
+        buf[0] = (byte)b;
         inData.readFully(buf, 1, headerSize - 1);
 
         // Validate the CRC32.
diff --git a/src/org/tukaani/xz/CloseIgnoringInputStream.java b/src/org/tukaani/xz/CloseIgnoringInputStream.java
index db68ddb..c29f268 100644
--- a/src/org/tukaani/xz/CloseIgnoringInputStream.java
+++ b/src/org/tukaani/xz/CloseIgnoringInputStream.java
@@ -18,7 +18,7 @@
  * {@code close()} to release memory allocated from an {@link ArrayCache}
  * but don't want to close the underlying {@code InputStream}.
  * For example:
- * <p><blockquote><pre>
+ * <blockquote><pre>
  * InputStream rawdec = new LZMA2InputStream(
  *         new CloseIgnoringInputStream(myInputStream),
  *         myDictSize, null, myArrayCache);
diff --git a/src/org/tukaani/xz/LZMA2InputStream.java b/src/org/tukaani/xz/LZMA2InputStream.java
index 9708052..c494a07 100644
--- a/src/org/tukaani/xz/LZMA2InputStream.java
+++ b/src/org/tukaani/xz/LZMA2InputStream.java
@@ -13,6 +13,7 @@
 import java.io.InputStream;
 import java.io.DataInputStream;
 import java.io.IOException;
+import java.io.EOFException;
 import org.tukaani.xz.lz.LZDecoder;
 import org.tukaani.xz.rangecoder.RangeDecoderFromBuffer;
 import org.tukaani.xz.lzma.LZMADecoder;
diff --git a/src/org/tukaani/xz/LZMA2OutputStream.java b/src/org/tukaani/xz/LZMA2OutputStream.java
index a82a1a5..1bb2d85 100644
--- a/src/org/tukaani/xz/LZMA2OutputStream.java
+++ b/src/org/tukaani/xz/LZMA2OutputStream.java
@@ -10,7 +10,6 @@
 
 package org.tukaani.xz;
 
-import java.io.DataOutputStream;
 import java.io.IOException;
 import org.tukaani.xz.lz.LZEncoder;
 import org.tukaani.xz.rangecoder.RangeEncoderToBuffer;
@@ -22,7 +21,6 @@
     private final ArrayCache arrayCache;
 
     private FinishableOutputStream out;
-    private final DataOutputStream outData;
 
     private LZEncoder lz;
     private RangeEncoderToBuffer rc;
@@ -37,6 +35,8 @@
     private boolean finished = false;
     private IOException exception = null;
 
+    private final byte[] chunkHeader = new byte[6];
+
     private final byte[] tempBuf = new byte[1];
 
     private static int getExtraSizeBefore(int dictSize) {
@@ -60,7 +60,6 @@
 
         this.arrayCache = arrayCache;
         this.out = out;
-        outData = new DataOutputStream(out);
         rc = new RangeEncoderToBuffer(COMPRESSED_SIZE_MAX, arrayCache);
 
         int dictSize = options.getDictSize();
@@ -154,13 +153,18 @@
         }
 
         control |= (uncompressedSize - 1) >>> 16;
-        outData.writeByte(control);
+        chunkHeader[0] = (byte)control;
+        chunkHeader[1] = (byte)((uncompressedSize - 1) >>> 8);
+        chunkHeader[2] = (byte)(uncompressedSize - 1);
+        chunkHeader[3] = (byte)((compressedSize - 1) >>> 8);
+        chunkHeader[4] = (byte)(compressedSize - 1);
 
-        outData.writeShort(uncompressedSize - 1);
-        outData.writeShort(compressedSize - 1);
-
-        if (propsNeeded)
-            outData.writeByte(props);
+        if (propsNeeded) {
+            chunkHeader[5] = (byte)props;
+            out.write(chunkHeader, 0, 6);
+        } else {
+            out.write(chunkHeader, 0, 5);
+        }
 
         rc.write(out);
 
@@ -172,8 +176,10 @@
     private void writeUncompressed(int uncompressedSize) throws IOException {
         while (uncompressedSize > 0) {
             int chunkSize = Math.min(uncompressedSize, COMPRESSED_SIZE_MAX);
-            outData.writeByte(dictResetNeeded ? 0x01 : 0x02);
-            outData.writeShort(chunkSize - 1);
+            chunkHeader[0] = (byte)(dictResetNeeded ? 0x01 : 0x02);
+            chunkHeader[1] = (byte)((chunkSize - 1) >>> 8);
+            chunkHeader[2] = (byte)(chunkSize - 1);
+            out.write(chunkHeader, 0, 3);
             lz.copyUncompressed(out, uncompressedSize, chunkSize);
             uncompressedSize -= chunkSize;
             dictResetNeeded = false;
diff --git a/src/org/tukaani/xz/LZMAInputStream.java b/src/org/tukaani/xz/LZMAInputStream.java
index e46d5bb..1432eb1 100644
--- a/src/org/tukaani/xz/LZMAInputStream.java
+++ b/src/org/tukaani/xz/LZMAInputStream.java
@@ -13,6 +13,7 @@
 import java.io.InputStream;
 import java.io.DataInputStream;
 import java.io.IOException;
+import java.io.EOFException;
 import org.tukaani.xz.lz.LZDecoder;
 import org.tukaani.xz.rangecoder.RangeDecoderFromStream;
 import org.tukaani.xz.lzma.LZMADecoder;
@@ -53,6 +54,7 @@
     private LZMADecoder lzma;
 
     private boolean endReached = false;
+    private boolean relaxedEndCondition = false;
 
     private final byte[] tempBuf = new byte[1];
 
@@ -606,6 +608,33 @@
     }
 
     /**
+     * Enables relaxed end-of-stream condition when uncompressed size is known.
+     * This is useful if uncompressed size is known but it is unknown if
+     * the end of stream (EOS) marker is present. After calling this function,
+     * both are allowed.
+     * <p>
+     * Note that this doesn't actually check if the EOS marker is present.
+     * This introduces a few minor downsides:
+     * <ul>
+     *   <li>Some (not all!) streams that would have more data than
+     *   the specified uncompressed size, for example due to data corruption,
+     *   will be accepted as valid.</li>
+     *   <li>After <code>read</code> has returned <code>-1</code> the
+     *   input position might not be at the end of the stream (too little
+     *   input may have been read).</li>
+     * </ul>
+     * <p>
+     * This should be called after the constructor before reading any data
+     * from the stream. This is a separate function because adding even more
+     * constructors to this class didn't look like a good alternative.
+     *
+     * @since 1.9
+     */
+    public void enableRelaxedEndCondition() {
+        relaxedEndCondition = true;
+    }
+
+    /**
      * Decompresses the next byte from this input stream.
      * <p>
      * Reading lots of data with <code>read()</code> from this input stream
@@ -718,9 +747,10 @@
                 if (endReached) {
                     // Checking these helps a lot when catching corrupt
                     // or truncated .lzma files. LZMA Utils doesn't do
-                    // the first check and thus it accepts many invalid
+                    // the second check and thus it accepts many invalid
                     // files that this implementation and XZ Utils don't.
-                    if (!rc.isFinished() || lz.hasPending())
+                    if (lz.hasPending() || (!relaxedEndCondition
+                                            && !rc.isFinished()))
                         throw new CorruptedInputException();
 
                     putArraysToCache();
diff --git a/src/org/tukaani/xz/SeekableXZInputStream.java b/src/org/tukaani/xz/SeekableXZInputStream.java
index 74f130e..74da2e1 100644
--- a/src/org/tukaani/xz/SeekableXZInputStream.java
+++ b/src/org/tukaani/xz/SeekableXZInputStream.java
@@ -45,7 +45,7 @@
  * Block inside a Stream is located using binary search and thus is fast
  * even with a huge number of Blocks.
  *
- * <h4>Memory usage</h4>
+ * <h2>Memory usage</h2>
  * <p>
  * The amount of memory needed for the Indexes is taken into account when
  * checking the memory usage limit. Each Stream is calculated to need at
@@ -53,7 +53,7 @@
  * to the next kibibyte. So unless the file has a huge number of Streams or
  * Blocks, these don't take significant amount of memory.
  *
- * <h4>Creating random-accessible .xz files</h4>
+ * <h2>Creating random-accessible .xz files</h2>
  * <p>
  * When using {@link XZOutputStream}, a new Block can be started by calling
  * its {@link XZOutputStream#endBlock() endBlock} method. If you know
@@ -69,6 +69,21 @@
  * <code>--block-list=SIZES</code> which allows specifying sizes of
  * individual Blocks.
  *
+ * <h2>Example: getting the uncompressed size of a .xz file</h2>
+ * <blockquote><pre>
+ * String filename = "foo.xz";
+ * SeekableFileInputStream seekableFile
+ *         = new SeekableFileInputStream(filename);
+ *
+ * try {
+ *     SeekableXZInputStream seekableXZ
+ *             = new SeekableXZInputStream(seekableFile);
+ *     System.out.println("Uncompressed size: " + seekableXZ.length());
+ * } finally {
+ *     seekableFile.close();
+ * }
+ * </pre></blockquote>
+ *
  * @see SeekableFileInputStream
  * @see XZInputStream
  * @see XZOutputStream
diff --git a/src/org/tukaani/xz/SingleXZInputStream.java b/src/org/tukaani/xz/SingleXZInputStream.java
index 8da2be0..e106771 100644
--- a/src/org/tukaani/xz/SingleXZInputStream.java
+++ b/src/org/tukaani/xz/SingleXZInputStream.java
@@ -28,7 +28,7 @@
  * Unless you know what you are doing, don't use this class to decompress
  * standalone .xz files. For that purpose, use <code>XZInputStream</code>.
  *
- * <h4>When uncompressed size is known beforehand</h4>
+ * <h2>When uncompressed size is known beforehand</h2>
  * <p>
  * If you are decompressing complete XZ streams and your application knows
  * exactly how much uncompressed data there should be, it is good to try
diff --git a/src/org/tukaani/xz/XZInputStream.java b/src/org/tukaani/xz/XZInputStream.java
index 680f647..30374eb 100644
--- a/src/org/tukaani/xz/XZInputStream.java
+++ b/src/org/tukaani/xz/XZInputStream.java
@@ -22,10 +22,10 @@
  * its input stream until the end of the input or until an error occurs.
  * This supports decompressing concatenated .xz files.
  *
- * <h4>Typical use cases</h4>
+ * <h2>Typical use cases</h2>
  * <p>
  * Getting an input stream to decompress a .xz file:
- * <p><blockquote><pre>
+ * <blockquote><pre>
  * InputStream infile = new FileInputStream("foo.xz");
  * XZInputStream inxz = new XZInputStream(infile);
  * </pre></blockquote>
@@ -42,12 +42,12 @@
  * the specified limit, MemoryLimitException will be thrown when reading
  * from the stream. For example, the following sets the memory usage limit
  * to 100&nbsp;MiB:
- * <p><blockquote><pre>
+ * <blockquote><pre>
  * InputStream infile = new FileInputStream("foo.xz");
  * XZInputStream inxz = new XZInputStream(infile, 100 * 1024);
  * </pre></blockquote>
  *
- * <h4>When uncompressed size is known beforehand</h4>
+ * <h2>When uncompressed size is known beforehand</h2>
  * <p>
  * If you are decompressing complete files and your application knows
  * exactly how much uncompressed data there should be, it is good to try
diff --git a/src/org/tukaani/xz/XZOutputStream.java b/src/org/tukaani/xz/XZOutputStream.java
index 107ef7f..63cf5cf 100644
--- a/src/org/tukaani/xz/XZOutputStream.java
+++ b/src/org/tukaani/xz/XZOutputStream.java
@@ -19,18 +19,18 @@
 /**
  * Compresses into the .xz file format.
  *
- * <h4>Examples</h4>
+ * <h2>Examples</h2>
  * <p>
  * Getting an output stream to compress with LZMA2 using the default
  * settings and the default integrity check type (CRC64):
- * <p><blockquote><pre>
+ * <blockquote><pre>
  * FileOutputStream outfile = new FileOutputStream("foo.xz");
  * XZOutputStream outxz = new XZOutputStream(outfile, new LZMA2Options());
  * </pre></blockquote>
  * <p>
  * Using the preset level <code>8</code> for LZMA2 (the default
  * is <code>6</code>) and SHA-256 instead of CRC64 for integrity checking:
- * <p><blockquote><pre>
+ * <blockquote><pre>
  * XZOutputStream outxz = new XZOutputStream(outfile, new LZMA2Options(8),
  *                                           XZ.CHECK_SHA256);
  * </pre></blockquote>
@@ -38,7 +38,7 @@
  * Using the x86 BCJ filter together with LZMA2 to compress x86 executables
  * and printing the memory usage information before creating the
  * XZOutputStream:
- * <p><blockquote><pre>
+ * <blockquote><pre>
  * X86Options x86 = new X86Options();
  * LZMA2Options lzma2 = new LZMA2Options();
  * FilterOptions[] options = { x86, lzma2 };
diff --git a/src/org/tukaani/xz/check/CRC64.java b/src/org/tukaani/xz/check/CRC64.java
index 02b15b7..a590a25 100644
--- a/src/org/tukaani/xz/check/CRC64.java
+++ b/src/org/tukaani/xz/check/CRC64.java
@@ -1,7 +1,8 @@
 /*
  * CRC64
  *
- * Author: Lasse Collin <lasse.collin@tukaani.org>
+ * Authors: Brett Okken <brett.okken.os@gmail.com>
+ *          Lasse Collin <lasse.collin@tukaani.org>
  *
  * This file has been put into the public domain.
  * You can do whatever you want with this file.
@@ -10,37 +11,53 @@
 package org.tukaani.xz.check;
 
 public class CRC64 extends Check {
-    private static final long poly = 0xC96C5795D7870F42L;
-    private static final long[] crcTable = new long[256];
-
-    private long crc = -1;
+    private static final long[][] TABLE = new long[4][256];
 
     static {
-        for (int b = 0; b < crcTable.length; ++b) {
-                long r = b;
-                for (int i = 0; i < 8; ++i) {
-                        if ((r & 1) == 1)
-                                r = (r >>> 1) ^ poly;
-                        else
-                                r >>>= 1;
-                }
+        final long poly64 = 0xC96C5795D7870F42L;
 
-                crcTable[b] = r;
+        for (int s = 0; s < 4; ++s) {
+            for (int b = 0; b < 256; ++b) {
+                long r = s == 0 ? b : TABLE[s - 1][b];
+                for (int i = 0; i < 8; ++i) {
+                    if ((r & 1) == 1) {
+                        r = (r >>> 1) ^ poly64;
+                    } else {
+                        r >>>= 1;
+                    }
+                }
+                TABLE[s][b] = r;
+            }
         }
     }
 
+    private long crc = -1;
+
     public CRC64() {
         size = 8;
         name = "CRC64";
     }
 
+    @Override
     public void update(byte[] buf, int off, int len) {
-        int end = off + len;
+        final int end = off + len;
+        int i = off;
 
-        while (off < end)
-            crc = crcTable[(buf[off++] ^ (int)crc) & 0xFF] ^ (crc >>> 8);
+        for (int end4 = end - 3; i < end4; i += 4) {
+            final int tmp = (int)crc;
+            crc = TABLE[3][(tmp & 0xFF) ^ (buf[i] & 0xFF)] ^
+                  TABLE[2][((tmp >>> 8) & 0xFF) ^ (buf[i + 1] & 0xFF)] ^
+                  (crc >>> 32) ^
+                  TABLE[1][((tmp >>> 16) & 0xFF) ^ (buf[i + 2] & 0xFF)] ^
+                  TABLE[0][((tmp >>> 24) & 0xFF) ^ (buf[i + 3] & 0xFF)];
+        }
+
+        while (i < end)
+            crc = TABLE[0][(buf[i++] & 0xFF) ^ ((int)crc & 0xFF)] ^
+                  (crc >>> 8);
     }
 
+    @Override
     public byte[] finish() {
         long value = ~crc;
         crc = -1;
diff --git a/src/org/tukaani/xz/lz/Hash234.java b/src/org/tukaani/xz/lz/Hash234.java
index 299ec44..bfa51b0 100644
--- a/src/org/tukaani/xz/lz/Hash234.java
+++ b/src/org/tukaani/xz/lz/Hash234.java
@@ -94,9 +94,9 @@
         hash4Table[hash4Value] = pos;
     }
 
-    void normalize(int normalizeOffset) {
-        LZEncoder.normalize(hash2Table, HASH_2_SIZE, normalizeOffset);
-        LZEncoder.normalize(hash3Table, HASH_3_SIZE, normalizeOffset);
-        LZEncoder.normalize(hash4Table, hash4Size, normalizeOffset);
+    void normalize(int normalizationOffset) {
+        LZEncoder.normalize(hash2Table, HASH_2_SIZE, normalizationOffset);
+        LZEncoder.normalize(hash3Table, HASH_3_SIZE, normalizationOffset);
+        LZEncoder.normalize(hash4Table, hash4Size, normalizationOffset);
     }
 }
diff --git a/src/org/tukaani/xz/lz/LZDecoder.java b/src/org/tukaani/xz/lz/LZDecoder.java
index 85b2ca1..6115e54 100644
--- a/src/org/tukaani/xz/lz/LZDecoder.java
+++ b/src/org/tukaani/xz/lz/LZDecoder.java
@@ -92,14 +92,43 @@
         pendingDist = dist;
 
         int back = pos - dist - 1;
-        if (dist >= pos)
+        if (back < 0) {
+            // The distance wraps around to the end of the cyclic dictionary
+            // buffer. We cannot get here if the dictionary isn't full.
+            assert full == bufSize;
             back += bufSize;
 
+            // Here we will never copy more than dist + 1 bytes and
+            // so the copying won't repeat from its own output.
+            // Thus, we can always use arraycopy safely.
+            int copySize = Math.min(bufSize - back, left);
+            assert copySize <= dist + 1;
+
+            System.arraycopy(buf, back, buf, pos, copySize);
+            pos += copySize;
+            back = 0;
+            left -= copySize;
+
+            if (left == 0)
+                return;
+        }
+
+        assert back < pos;
+        assert left > 0;
+
         do {
-            buf[pos++] = buf[back++];
-            if (back == bufSize)
-                back = 0;
-        } while (--left > 0);
+            // Determine the number of bytes to copy on this loop iteration:
+            // copySize is set so that the source and destination ranges
+            // don't overlap. If "left" is large enough, the destination
+            // range will start right after the last byte of the source
+            // range. This way we don't need to advance "back" which
+            // allows the next iteration of this loop to copy (up to)
+            // twice the number of bytes.
+            int copySize = Math.min(left, pos - back);
+            System.arraycopy(buf, back, buf, pos, copySize);
+            pos += copySize;
+            left -= copySize;
+        } while (left > 0);
 
         if (full < pos)
             full = pos;
diff --git a/src/org/tukaani/xz/package-info.java b/src/org/tukaani/xz/package-info.java
index 4e961df..ad23233 100644
--- a/src/org/tukaani/xz/package-info.java
+++ b/src/org/tukaani/xz/package-info.java
@@ -10,7 +10,7 @@
 /**
  * XZ data compression support.
  *
- * <h4>Introduction</h4>
+ * <h2>Introduction</h2>
  * <p>
  * This aims to be a complete implementation of XZ data compression
  * in pure Java. Features:
@@ -25,20 +25,20 @@
  * Threading is planned but it is unknown when it will be implemented.
  * <p>
  * For the latest source code, see the
- * <a href="http://tukaani.org/xz/java.html">home page of XZ for Java</a>.
+ * <a href="https://tukaani.org/xz/java.html">home page of XZ for Java</a>.
  *
- * <h4>Getting started</h4>
+ * <h2>Getting started</h2>
  * <p>
  * Start by reading the documentation of {@link org.tukaani.xz.XZOutputStream}
  * and {@link org.tukaani.xz.XZInputStream}.
  * If you use XZ inside another file format or protocol,
  * see also {@link org.tukaani.xz.SingleXZInputStream}.
  *
- * <h4>Licensing</h4>
+ * <h2>Licensing</h2>
  * <p>
  * XZ for Java has been put into the public domain, thus you can do
  * whatever you want with it. All the files in the package have been
- * written by Lasse Collin and/or Igor Pavlov.
+ * written by Lasse Collin, Igor Pavlov, and/or Brett Okken.
  * <p>
  * This software is provided "as is", without any warranty.
  */
diff --git a/src/org/tukaani/xz/rangecoder/RangeDecoder.java b/src/org/tukaani/xz/rangecoder/RangeDecoder.java
index e63532e..7bcf718 100644
--- a/src/org/tukaani/xz/rangecoder/RangeDecoder.java
+++ b/src/org/tukaani/xz/rangecoder/RangeDecoder.java
@@ -10,7 +10,6 @@
 
 package org.tukaani.xz.rangecoder;
 
-import java.io.DataInputStream;
 import java.io.IOException;
 
 public abstract class RangeDecoder extends RangeCoder {
diff --git a/src9/module-info.java b/src9/module-info.java
new file mode 100644
index 0000000..1b28bc4
--- /dev/null
+++ b/src9/module-info.java
@@ -0,0 +1,12 @@
+/*
+ * module-info
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+module org.tukaani.xz {
+    exports org.tukaani.xz;
+}