diff options
-rw-r--r-- | archival/libarchive/unxz/xz_dec_bcj.c | 27 |
1 files changed, 20 insertions, 7 deletions
diff --git a/archival/libarchive/unxz/xz_dec_bcj.c b/archival/libarchive/unxz/xz_dec_bcj.c index a01a4cdcf..e0f913a94 100644 --- a/archival/libarchive/unxz/xz_dec_bcj.c +++ b/archival/libarchive/unxz/xz_dec_bcj.c | |||
@@ -446,8 +446,12 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s, | |||
446 | * next filter in the chain. Apply the BCJ filter on the new data | 446 | * next filter in the chain. Apply the BCJ filter on the new data |
447 | * in the output buffer. If everything cannot be filtered, copy it | 447 | * in the output buffer. If everything cannot be filtered, copy it |
448 | * to temp and rewind the output buffer position accordingly. | 448 | * to temp and rewind the output buffer position accordingly. |
449 | * | ||
450 | * This needs to be always run when temp.size == 0 to handle a special | ||
451 | * case where the output buffer is full and the next filter has no | ||
452 | * more output coming but hasn't returned XZ_STREAM_END yet. | ||
449 | */ | 453 | */ |
450 | if (s->temp.size < b->out_size - b->out_pos) { | 454 | if (s->temp.size < b->out_size - b->out_pos || s->temp.size == 0) { |
451 | out_start = b->out_pos; | 455 | out_start = b->out_pos; |
452 | memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size); | 456 | memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size); |
453 | b->out_pos += s->temp.size; | 457 | b->out_pos += s->temp.size; |
@@ -470,16 +474,25 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s, | |||
470 | s->temp.size = b->out_pos - out_start; | 474 | s->temp.size = b->out_pos - out_start; |
471 | b->out_pos -= s->temp.size; | 475 | b->out_pos -= s->temp.size; |
472 | memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size); | 476 | memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size); |
477 | |||
478 | /* | ||
479 | * If there wasn't enough input to the next filter to fill | ||
480 | * the output buffer with unfiltered data, there's no point | ||
481 | * to try decoding more data to temp. | ||
482 | */ | ||
483 | if (b->out_pos + s->temp.size < b->out_size) | ||
484 | return XZ_OK; | ||
473 | } | 485 | } |
474 | 486 | ||
475 | /* | 487 | /* |
476 | * If we have unfiltered data in temp, try to fill by decoding more | 488 | * We have unfiltered data in temp. If the output buffer isn't full |
477 | * data from the next filter. Apply the BCJ filter on temp. Then we | 489 | * yet, try to fill the temp buffer by decoding more data from the |
478 | * hopefully can fill the actual output buffer by copying filtered | 490 | * next filter. Apply the BCJ filter on temp. Then we hopefully can |
479 | * data from temp. A mix of filtered and unfiltered data may be left | 491 | * fill the actual output buffer by copying filtered data from temp. |
480 | * in temp; it will be taken care on the next call to this function. | 492 | * A mix of filtered and unfiltered data may be left in temp; it will |
493 | * be taken care on the next call to this function. | ||
481 | */ | 494 | */ |
482 | if (s->temp.size > 0) { | 495 | if (b->out_pos < b->out_size) { |
483 | /* Make b->out{,_pos,_size} temporarily point to s->temp. */ | 496 | /* Make b->out{,_pos,_size} temporarily point to s->temp. */ |
484 | s->out = b->out; | 497 | s->out = b->out; |
485 | s->out_pos = b->out_pos; | 498 | s->out_pos = b->out_pos; |