diff options
Diffstat (limited to 'archival/libunarchive/unxz/xz_dec_stream.c')
-rw-r--r-- | archival/libunarchive/unxz/xz_dec_stream.c | 113 |
1 files changed, 81 insertions, 32 deletions
diff --git a/archival/libunarchive/unxz/xz_dec_stream.c b/archival/libunarchive/unxz/xz_dec_stream.c index 121c3b5..21db283 100644 --- a/archival/libunarchive/unxz/xz_dec_stream.c +++ b/archival/libunarchive/unxz/xz_dec_stream.c @@ -45,8 +45,8 @@ struct xz_dec { /* CRC32 value in Block or Index */ uint32_t crc32; - /* True if CRC32 is calculated from uncompressed data */ - uint8_t crc_type; + /* 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; @@ -134,9 +134,19 @@ struct xz_dec { struct xz_dec_bcj *bcj; bool bcj_active; #endif +}; - uint32_t crc32_table[256]; +#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 @@ -231,9 +241,8 @@ static enum xz_ret XZ_FUNC dec_block(struct xz_dec *s, struct xz_buf *b) > s->block_header.uncompressed) return XZ_DATA_ERROR; - if (s->crc_type == 0x01) - s->crc32 = xz_crc32(s->crc32_table, - b->out + s->out_start, + if (s->check_type == XZ_CHECK_CRC32) + s->crc32 = xz_crc32(b->out + s->out_start, b->out_pos - s->out_start, s->crc32); if (ret == XZ_STREAM_END) { @@ -249,15 +258,16 @@ static enum xz_ret XZ_FUNC dec_block(struct xz_dec *s, struct xz_buf *b) s->block.hash.unpadded += s->block_header.size + s->block.compressed; - if (s->crc_type == 0x01) + +#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; - if (s->crc_type == 0x04) /* CRC64 */ - s->block.hash.unpadded += 8; - if (s->crc_type == 0x0A) /* SHA-256 */ - s->block.hash.unpadded += 32; +#endif s->block.hash.uncompressed += s->block.uncompressed; - s->block.hash.crc32 = xz_crc32(s->crc32_table, + s->block.hash.crc32 = xz_crc32( (const uint8_t *)&s->block.hash, sizeof(s->block.hash), s->block.hash.crc32); @@ -272,7 +282,7 @@ static void XZ_FUNC index_update(struct xz_dec *s, const struct xz_buf *b) { size_t in_used = b->in_pos - s->in_start; s->index.size += in_used; - s->crc32 = xz_crc32(s->crc32_table, b->in + s->in_start, in_used, s->crc32); + s->crc32 = xz_crc32(b->in + s->in_start, in_used, s->crc32); } /* @@ -316,7 +326,7 @@ static enum xz_ret XZ_FUNC dec_index(struct xz_dec *s, struct xz_buf *b) case SEQ_INDEX_UNCOMPRESSED: s->index.hash.uncompressed += s->vli; - s->index.hash.crc32 = xz_crc32(s->crc32_table, + s->index.hash.crc32 = xz_crc32( (const uint8_t *)&s->index.hash, sizeof(s->index.hash), s->index.hash.crc32); @@ -352,31 +362,58 @@ static enum xz_ret XZ_FUNC crc32_validate(struct xz_dec *s, struct xz_buf *b) 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) { if (!memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE)) return XZ_FORMAT_ERROR; - if (xz_crc32(s->crc32_table, s->temp.buf + HEADER_MAGIC_SIZE, 2, 0) + if (xz_crc32(s->temp.buf + HEADER_MAGIC_SIZE, 2, 0) != get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2)) return XZ_DATA_ERROR; + if (s->temp.buf[HEADER_MAGIC_SIZE] != 0) + return XZ_OPTIONS_ERROR; + /* - * Decode the Stream Flags field. Of integrity checks, we support - * only none (Check ID = 0) and CRC32 (Check ID = 1). - * We also accept CRC64 and SHA-256, but they will not be verified. + * 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. */ - if (s->temp.buf[HEADER_MAGIC_SIZE] != 0 - || (s->temp.buf[HEADER_MAGIC_SIZE + 1] > 1 - && s->temp.buf[HEADER_MAGIC_SIZE + 1] != 0x04 /* CRC64 */ - && s->temp.buf[HEADER_MAGIC_SIZE + 1] != 0x0A /* SHA-256 */ - ) - ) { + 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; - } - s->crc_type = s->temp.buf[HEADER_MAGIC_SIZE + 1]; + 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; } @@ -387,7 +424,7 @@ static enum xz_ret XZ_FUNC dec_stream_footer(struct xz_dec *s) if (!memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE)) return XZ_DATA_ERROR; - if (xz_crc32(s->crc32_table, s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf)) + if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf)) return XZ_DATA_ERROR; /* @@ -398,7 +435,7 @@ static enum xz_ret XZ_FUNC dec_stream_footer(struct xz_dec *s) 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->crc_type) + if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type) return XZ_DATA_ERROR; /* @@ -418,7 +455,7 @@ static enum xz_ret XZ_FUNC dec_block_header(struct xz_dec *s) * eight bytes so this is safe. */ s->temp.size -= 4; - if (xz_crc32(s->crc32_table, s->temp.buf, s->temp.size, 0) + if (xz_crc32(s->temp.buf, s->temp.size, 0) != get_le32(s->temp.buf + s->temp.size)) return XZ_DATA_ERROR; @@ -533,12 +570,19 @@ static enum xz_ret XZ_FUNC dec_main(struct xz_dec *s, struct xz_buf *b) 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) @@ -600,11 +644,16 @@ static enum xz_ret XZ_FUNC dec_main(struct xz_dec *s, struct xz_buf *b) s->sequence = SEQ_BLOCK_CHECK; case SEQ_BLOCK_CHECK: - if (s->crc_type == 0x01) { + 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; |