aboutsummaryrefslogtreecommitdiff
path: root/linux/lib/xz/xz_dec_stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/lib/xz/xz_dec_stream.c')
-rw-r--r--linux/lib/xz/xz_dec_stream.c86
1 files changed, 82 insertions, 4 deletions
diff --git a/linux/lib/xz/xz_dec_stream.c b/linux/lib/xz/xz_dec_stream.c
index f69581b..2c41f5f 100644
--- a/linux/lib/xz/xz_dec_stream.c
+++ b/linux/lib/xz/xz_dec_stream.c
@@ -35,7 +35,8 @@ struct xz_dec {
SEQ_INDEX,
SEQ_INDEX_PADDING,
SEQ_INDEX_CRC32,
- SEQ_STREAM_FOOTER
+ SEQ_STREAM_FOOTER,
+ SEQ_STREAM_PADDING
} sequence;
/* Position in variable-length integers and Check fields */
@@ -423,12 +424,12 @@ static enum xz_ret dec_stream_header(struct xz_dec *s)
* check types too, but then the check won't be verified and
* a warning (XZ_UNSUPPORTED_CHECK) will be given.
*/
+ if (s->temp.buf[HEADER_MAGIC_SIZE + 1] > XZ_CHECK_MAX)
+ return XZ_OPTIONS_ERROR;
+
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 && !IS_CRC64(s->check_type))
return XZ_UNSUPPORTED_CHECK;
#else
@@ -742,6 +743,10 @@ static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
return XZ_OK;
return dec_stream_footer(s);
+
+ case SEQ_STREAM_PADDING:
+ /* Never reached, only silencing a warning */
+ break;
}
}
@@ -809,6 +814,79 @@ XZ_EXTERN enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b)
return ret;
}
+#ifdef XZ_DEC_CONCATENATED
+XZ_EXTERN enum xz_ret xz_dec_catrun(struct xz_dec *s, struct xz_buf *b,
+ int finish)
+{
+ enum xz_ret ret;
+
+ if (DEC_IS_SINGLE(s->mode)) {
+ xz_dec_reset(s);
+ finish = true;
+ }
+
+ while (true) {
+ if (s->sequence == SEQ_STREAM_PADDING) {
+ /*
+ * Skip Stream Padding. Its size must be a multiple
+ * of four bytes which is tracked with s->pos.
+ */
+ while (true) {
+ if (b->in_pos == b->in_size) {
+ /*
+ * Note that if we are repeatedly
+ * given no input and finish is false,
+ * we will keep returning XZ_OK even
+ * though no progress is being made.
+ * The lack of XZ_BUF_ERROR support
+ * isn't a problem here because a
+ * reasonable caller will eventually
+ * provide more input or set finish
+ * to true.
+ */
+ if (!finish)
+ return XZ_OK;
+
+ if (s->pos != 0)
+ return XZ_DATA_ERROR;
+
+ return XZ_STREAM_END;
+ }
+
+ if (b->in[b->in_pos] != 0x00) {
+ if (s->pos != 0)
+ return XZ_DATA_ERROR;
+
+ break;
+ }
+
+ ++b->in_pos;
+ s->pos = (s->pos + 1) & 3;
+ }
+
+ /*
+ * More input remains. It should be a new Stream.
+ *
+ * In single-call mode xz_dec_run() will always call
+ * xz_dec_reset(). Thus, we need to do it here only
+ * in multi-call mode.
+ */
+ if (DEC_IS_MULTI(s->mode))
+ xz_dec_reset(s);
+ }
+
+ ret = xz_dec_run(s, b);
+
+ if (ret != XZ_STREAM_END)
+ break;
+
+ s->sequence = SEQ_STREAM_PADDING;
+ }
+
+ return ret;
+}
+#endif
+
XZ_EXTERN struct xz_dec *xz_dec_init(enum xz_mode mode, uint32_t dict_max)
{
struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL);