aboutsummaryrefslogtreecommitdiff
path: root/linux/lib
diff options
context:
space:
mode:
authorLasse Collin <lasse.collin@tukaani.org>2021-05-06 20:18:46 +0300
committerLasse Collin <lasse.collin@tukaani.org>2021-05-06 20:18:46 +0300
commit6f0e0c41e3682254c2e0be245f275f77df821ffe (patch)
treedfc5c38f1b6fee2660fae9825aa7d0e1daf2e5a3 /linux/lib
parentd8a12bc0c61282b38439ee76b05dbde0200002e1 (diff)
downloadxz-embedded-6f0e0c41e3682254c2e0be245f275f77df821ffe.tar.gz
Add xz_dec_catrun() to support concatenated .xz files.
Diffstat (limited to 'linux/lib')
-rw-r--r--linux/lib/xz/xz_dec_stream.c80
1 files changed, 79 insertions, 1 deletions
diff --git a/linux/lib/xz/xz_dec_stream.c b/linux/lib/xz/xz_dec_stream.c
index f69581b..e4aab73 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 */
@@ -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);