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