Support decompressing files with unsupported check types.

This is enabled at compile time by defining XZ_DEC_ANY_CHECK.
If the Check ID is not supported, xz_dec_run() will return
XZ_UNSUPPORTED_CHECK. In multi-call mode, decoding can be
then continued normally. In single-call mode, decoding
cannot be continued, thus this feature is useful only
in multi-call mode.
diff --git a/linux/include/linux/xz.h b/linux/include/linux/xz.h
index 824c0a7..eb82706 100644
--- a/linux/include/linux/xz.h
+++ b/linux/include/linux/xz.h
@@ -31,20 +31,29 @@
 
 /**
  * enum xz_ret - Return codes
- * @XZ_OK:              Everything is OK so far. More input or more output
- *                      space is required to continue.
- * @XZ_STREAM_END:      Operation finished successfully.
- * @XZ_MEMLIMIT_ERROR:  Not enough memory was preallocated at decoder
- *                      initialization time.
- * @XZ_FORMAT_ERROR:    File format was not recognized (wrong magic bytes).
- * @XZ_OPTIONS_ERROR:   This implementation doesn't support the requested
- *                      compression options. In the decoder this means that
- *                      the header CRC32 matches, but the header itself
- *                      specifies something that we don't support.
- * @XZ_DATA_ERROR:      Compressed data is corrupt.
- * @XZ_BUF_ERROR:       Cannot make any progress. Details are slightly
- *                      different between multi-call and single-call mode;
- *                      more information below.
+ * @XZ_OK:                  Everything is OK so far. More input or more
+ *                          output space is required to continue.
+ * @XZ_STREAM_END:          Operation finished successfully.
+ * @XZ_UNSUPPORTED_CHECK:   Integrity check type is not supported. Decoding
+ *                          is still possible in multi-call mode by simply
+ *                          calling xz_dec_run() again.
+ *                          NOTE: This return value is used only if
+ *                          XZ_DEC_ANY_CHECK was defined at build time,
+ *                          which is not used in the kernel. Unsupported
+ *                          check types return XZ_OPTIONS_ERROR if
+ *                          XZ_DEC_ANY_CHECK was not defined at build time.
+ * @XZ_MEMLIMIT_ERROR:      Not enough memory was preallocated at decoder
+ *                          initialization time.
+ * @XZ_FORMAT_ERROR:        File format was not recognized (wrong magic
+ *                          bytes).
+ * @XZ_OPTIONS_ERROR:       This implementation doesn't support the requested
+ *                          compression options. In the decoder this means
+ *                          that the header CRC32 matches, but the header
+ *                          itself specifies something that we don't support.
+ * @XZ_DATA_ERROR:          Compressed data is corrupt.
+ * @XZ_BUF_ERROR:           Cannot make any progress. Details are slightly
+ *                          different between multi-call and single-call
+ *                          mode; more information below.
  *
  * In multi-call mode, XZ_BUF_ERROR is returned when two consecutive calls
  * to XZ code cannot consume any input and cannot produce any new output.
@@ -62,6 +71,7 @@
 enum xz_ret {
 	XZ_OK,
 	XZ_STREAM_END,
+	XZ_UNSUPPORTED_CHECK,
 	XZ_MEMLIMIT_ERROR,
 	XZ_FORMAT_ERROR,
 	XZ_OPTIONS_ERROR,
diff --git a/linux/lib/xz/xz_dec_stream.c b/linux/lib/xz/xz_dec_stream.c
index 76413c4..21db283 100644
--- a/linux/lib/xz/xz_dec_stream.c
+++ b/linux/lib/xz/xz_dec_stream.c
@@ -45,8 +45,8 @@
 	/* CRC32 value in Block or Index */
 	uint32_t crc32;
 
-	/* True if CRC32 is calculated from uncompressed data */
-	bool has_crc32;
+	/* Type of the integrity check calculated from uncompressed data */
+	enum xz_check check_type;
 
 	/* True if we are operating in single-call mode. */
 	bool single_call;
@@ -136,6 +136,18 @@
 #endif
 };
 
+#ifdef XZ_DEC_ANY_CHECK
+/* Sizes of the Check field with different Check IDs */
+static const uint8_t check_sizes[16] = {
+	0,
+	4, 4, 4,
+	8, 8, 8,
+	16, 16, 16,
+	32, 32, 32,
+	64, 64, 64
+};
+#endif
+
 /*
  * Fill s->temp by copying data starting from b->in[b->in_pos]. Caller
  * must have set s->temp.pos to indicate how much data we are supposed
@@ -229,7 +241,7 @@
 				> s->block_header.uncompressed)
 		return XZ_DATA_ERROR;
 
-	if (s->has_crc32)
+	if (s->check_type == XZ_CHECK_CRC32)
 		s->crc32 = xz_crc32(b->out + s->out_start,
 				b->out_pos - s->out_start, s->crc32);
 
@@ -246,8 +258,13 @@
 
 		s->block.hash.unpadded += s->block_header.size
 				+ s->block.compressed;
-		if (s->has_crc32)
+
+#ifdef XZ_DEC_ANY_CHECK
+		s->block.hash.unpadded += check_sizes[s->check_type];
+#else
+		if (s->check_type == XZ_CHECK_CRC32)
 			s->block.hash.unpadded += 4;
+#endif
 
 		s->block.hash.uncompressed += s->block.uncompressed;
 		s->block.hash.crc32 = xz_crc32(
@@ -345,6 +362,27 @@
 	return XZ_STREAM_END;
 }
 
+#ifdef XZ_DEC_ANY_CHECK
+/*
+ * Skip over the Check field when the Check ID is not supported.
+ * Returns true once the whole Check field has been skipped over.
+ */
+static bool XZ_FUNC check_skip(struct xz_dec *s, struct xz_buf *b)
+{
+	while (s->pos < check_sizes[s->check_type]) {
+		if (b->in_pos == b->in_size)
+			return false;
+
+		++b->in_pos;
+		++s->pos;
+	}
+
+	s->pos = 0;
+
+	return true;
+}
+#endif
+
 /* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */
 static enum xz_ret XZ_FUNC dec_stream_header(struct xz_dec *s)
 {
@@ -355,15 +393,27 @@
 			!= get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2))
 		return XZ_DATA_ERROR;
 
-	/*
-	 * Decode the Stream Flags field. Of integrity checks, we support
-	 * only none (Check ID = 0) and CRC32 (Check ID = 1).
-	 */
-	if (s->temp.buf[HEADER_MAGIC_SIZE] != 0
-			|| s->temp.buf[HEADER_MAGIC_SIZE + 1] > 1)
+	if (s->temp.buf[HEADER_MAGIC_SIZE] != 0)
 		return XZ_OPTIONS_ERROR;
 
-	s->has_crc32 = s->temp.buf[HEADER_MAGIC_SIZE + 1];
+	/*
+	 * Of integrity checks, we support only none (Check ID = 0) and
+	 * CRC32 (Check ID = 1). However, if XZ_DEC_ANY_CHECK is defined,
+	 * we will accept other check types too, but then the check won't
+	 * be verified and a warning (XZ_UNSUPPORTED_CHECK) will be given.
+	 */
+	s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1];
+
+#ifdef XZ_DEC_ANY_CHECK
+	if (s->check_type > XZ_CHECK_MAX)
+		return XZ_OPTIONS_ERROR;
+
+	if (s->check_type > XZ_CHECK_CRC32)
+		return XZ_UNSUPPORTED_CHECK;
+#else
+	if (s->check_type > XZ_CHECK_CRC32)
+		return XZ_OPTIONS_ERROR;
+#endif
 
 	return XZ_OK;
 }
@@ -385,7 +435,7 @@
 	if ((s->index.size >> 2) != get_le32(s->temp.buf + 4))
 		return XZ_DATA_ERROR;
 
-	if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->has_crc32)
+	if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type)
 		return XZ_DATA_ERROR;
 
 	/*
@@ -520,12 +570,19 @@
 			if (!fill_temp(s, b))
 				return XZ_OK;
 
+			/*
+			 * If dec_stream_header() returns
+			 * XZ_UNSUPPORTED_CHECK, it is still possible
+			 * to continue decoding if working in multi-call
+			 * mode. Thus, update s->sequence before calling
+			 * dec_stream_header().
+			 */
+			s->sequence = SEQ_BLOCK_START;
+
 			ret = dec_stream_header(s);
 			if (ret != XZ_OK)
 				return ret;
 
-			s->sequence = SEQ_BLOCK_START;
-
 		case SEQ_BLOCK_START:
 			/* We need one byte of input to continue. */
 			if (b->in_pos == b->in_size)
@@ -587,11 +644,16 @@
 			s->sequence = SEQ_BLOCK_CHECK;
 
 		case SEQ_BLOCK_CHECK:
-			if (s->has_crc32) {
+			if (s->check_type == XZ_CHECK_CRC32) {
 				ret = crc32_validate(s, b);
 				if (ret != XZ_STREAM_END)
 					return ret;
 			}
+#ifdef XZ_DEC_ANY_CHECK
+			else if (!check_skip(s, b)) {
+				return XZ_OK;
+			}
+#endif
 
 			s->sequence = SEQ_BLOCK_START;
 			break;
diff --git a/linux/lib/xz/xz_stream.h b/linux/lib/xz/xz_stream.h
index 5b9318b..36f2a7c 100644
--- a/linux/lib/xz/xz_stream.h
+++ b/linux/lib/xz/xz_stream.h
@@ -43,4 +43,15 @@
 /* Maximum encoded size of a VLI */
 #define VLI_BYTES_MAX (sizeof(vli_type) * 8 / 7)
 
+/* Integrity Check types */
+enum xz_check {
+	XZ_CHECK_NONE = 0,
+	XZ_CHECK_CRC32 = 1,
+	XZ_CHECK_CRC64 = 4,
+	XZ_CHECK_SHA256 = 10
+};
+
+/* Maximum possible Check ID */
+#define XZ_CHECK_MAX 15
+
 #endif
diff --git a/userspace/Makefile b/userspace/Makefile
index 761a251..52a98a4 100644
--- a/userspace/Makefile
+++ b/userspace/Makefile
@@ -10,6 +10,7 @@
 CC = gcc -std=gnu89
 BCJ_CPPFLAGS = -DXZ_DEC_X86 -DXZ_DEC_POWERPC -DXZ_DEC_IA64 \
 		-DXZ_DEC_ARM -DXZ_DEC_ARMTHUMB -DXZ_DEC_SPARC
+CPPFLAGS = -DXZ_DEC_ANY_CHECK
 CFLAGS = -ggdb3 -O2 -pedantic -Wall -Wextra
 RM = rm -f
 VPATH = ../linux/include/linux ../linux/lib/xz
diff --git a/userspace/xzminidec.c b/userspace/xzminidec.c
index 71feb49..91b27ba 100644
--- a/userspace/xzminidec.c
+++ b/userspace/xzminidec.c
@@ -72,6 +72,16 @@
 		if (ret == XZ_OK)
 			continue;
 
+#ifdef XZ_DEC_ANY_CHECK
+		if (ret == XZ_UNSUPPORTED_CHECK) {
+			fputs(argv[0], stderr);
+			fputs(": ", stderr);
+			fputs("Unsupported check; not verifying "
+					"file integrity\n", stderr);
+			continue;
+		}
+#endif
+
 		if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos
 				|| fclose(stdout)) {
 			msg = "Write error\n";