mirror of
https://github.com/libretro/pcsx2.git
synced 2024-12-18 07:38:33 +00:00
isoreader:gzip: Avoid shallow copying z_stream objects
This prevents the internal state of the objects from becoming inconsistent, which causes inflate() to fail with recent zlib versions (1.2.9 and later).
This commit is contained in:
parent
c218ef3970
commit
1ff6eec1e3
@ -429,8 +429,13 @@ int GzippedFileReader::_ReadSync(void* pBuffer, PX_off_t offset, uint bytesToRea
|
|||||||
// move the state to the appropriate span because it will be faster than using the index
|
// move the state to the appropriate span because it will be faster than using the index
|
||||||
int targetix = (extractOffset + res) / span;
|
int targetix = (extractOffset + res) / span;
|
||||||
m_zstates[targetix].Kill();
|
m_zstates[targetix].Kill();
|
||||||
m_zstates[targetix] = m_zstates[spanix]; // We have elements for the entire file, and another one.
|
// We have elements for the entire file, and another one.
|
||||||
m_zstates[spanix].state.isValid = 0; // Not killing because we need the state.
|
m_zstates[targetix].state.in_offset = m_zstates[spanix].state.in_offset;
|
||||||
|
m_zstates[targetix].state.isValid = m_zstates[spanix].state.isValid;
|
||||||
|
m_zstates[targetix].state.out_offset = m_zstates[spanix].state.out_offset;
|
||||||
|
inflateCopy(&m_zstates[targetix].state.strm, &m_zstates[spanix].state.strm);
|
||||||
|
|
||||||
|
m_zstates[spanix].Kill();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size <= GZFILE_READ_CHUNK_SIZE)
|
if (size <= GZFILE_READ_CHUNK_SIZE)
|
||||||
|
@ -344,33 +344,29 @@ static inline PX_off_t getInOffset(zstate *state) {
|
|||||||
was generated. extract() may also return Z_ERRNO if there is an error on
|
was generated. extract() may also return Z_ERRNO if there is an error on
|
||||||
reading or seeking the input file. */
|
reading or seeking the input file. */
|
||||||
local int extract(FILE *in, struct access *index, PX_off_t offset,
|
local int extract(FILE *in, struct access *index, PX_off_t offset,
|
||||||
unsigned char *buf, int len, zstate *state = 0)
|
unsigned char *buf, int len, zstate *state)
|
||||||
{
|
{
|
||||||
int ret, skip;
|
int ret, skip;
|
||||||
z_stream strm;
|
|
||||||
struct point *here;
|
struct point *here;
|
||||||
unsigned char input[CHUNK];
|
unsigned char input[CHUNK];
|
||||||
unsigned char discard[WINSIZE];
|
unsigned char discard[WINSIZE];
|
||||||
int isEnd = 0;
|
int isEnd = 0;
|
||||||
|
|
||||||
/* proceed only if something reasonable to do */
|
/* proceed only if something reasonable to do */
|
||||||
if (len < 0)
|
if (len < 0 || state == nullptr)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (state) {
|
if (state->isValid && offset != state->out_offset) {
|
||||||
if (state->isValid && offset != state->out_offset) {
|
// state doesn't match offset, free allocations before strm is overwritten
|
||||||
// state doesn't match offset, free allocations before strm is overwritten
|
inflateEnd(&state->strm);
|
||||||
(void)inflateEnd(&state->strm);
|
state->isValid = 0;
|
||||||
state->isValid = 0;
|
|
||||||
}
|
|
||||||
state->out_offset = offset;
|
|
||||||
}
|
}
|
||||||
|
state->out_offset = offset;
|
||||||
|
|
||||||
if (state && state->isValid) {
|
if (state->isValid) {
|
||||||
strm = state->strm;
|
|
||||||
state->isValid = 0; // we took control over strm. revalidate when/if we give it back
|
state->isValid = 0; // we took control over strm. revalidate when/if we give it back
|
||||||
PX_fseeko(in, state->in_offset, SEEK_SET);
|
PX_fseeko(in, state->in_offset, SEEK_SET);
|
||||||
strm.avail_in = 0;
|
state->strm.avail_in = 0;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
skip = 1;
|
skip = 1;
|
||||||
} else {
|
} else {
|
||||||
@ -381,12 +377,12 @@ local int extract(FILE *in, struct access *index, PX_off_t offset,
|
|||||||
here++;
|
here++;
|
||||||
|
|
||||||
/* initialize file and inflate state to start there */
|
/* initialize file and inflate state to start there */
|
||||||
strm.zalloc = Z_NULL;
|
state->strm.zalloc = Z_NULL;
|
||||||
strm.zfree = Z_NULL;
|
state->strm.zfree = Z_NULL;
|
||||||
strm.opaque = Z_NULL;
|
state->strm.opaque = Z_NULL;
|
||||||
strm.avail_in = 0;
|
state->strm.avail_in = 0;
|
||||||
strm.next_in = Z_NULL;
|
state->strm.next_in = Z_NULL;
|
||||||
ret = inflateInit2(&strm, -15); /* raw inflate */
|
ret = inflateInit2(&state->strm, -15); /* raw inflate */
|
||||||
if (ret != Z_OK)
|
if (ret != Z_OK)
|
||||||
return ret;
|
return ret;
|
||||||
ret = PX_fseeko(in, here->in - (here->bits ? 1 : 0), SEEK_SET);
|
ret = PX_fseeko(in, here->in - (here->bits ? 1 : 0), SEEK_SET);
|
||||||
@ -398,59 +394,59 @@ local int extract(FILE *in, struct access *index, PX_off_t offset,
|
|||||||
ret = ferror(in) ? Z_ERRNO : Z_DATA_ERROR;
|
ret = ferror(in) ? Z_ERRNO : Z_DATA_ERROR;
|
||||||
goto extract_ret;
|
goto extract_ret;
|
||||||
}
|
}
|
||||||
(void)inflatePrime(&strm, here->bits, ret >> (8 - here->bits));
|
inflatePrime(&state->strm, here->bits, ret >> (8 - here->bits));
|
||||||
}
|
}
|
||||||
(void)inflateSetDictionary(&strm, here->window, WINSIZE);
|
inflateSetDictionary(&state->strm, here->window, WINSIZE);
|
||||||
|
|
||||||
/* skip uncompressed bytes until offset reached, then satisfy request */
|
/* skip uncompressed bytes until offset reached, then satisfy request */
|
||||||
offset -= here->out;
|
offset -= here->out;
|
||||||
strm.avail_in = 0;
|
state->strm.avail_in = 0;
|
||||||
skip = 1; /* while skipping to offset */
|
skip = 1; /* while skipping to offset */
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
/* define where to put uncompressed data, and how much */
|
/* define where to put uncompressed data, and how much */
|
||||||
if (offset == 0 && skip) { /* at offset now */
|
if (offset == 0 && skip) { /* at offset now */
|
||||||
strm.avail_out = len;
|
state->strm.avail_out = len;
|
||||||
strm.next_out = buf;
|
state->strm.next_out = buf;
|
||||||
skip = 0; /* only do this once */
|
skip = 0; /* only do this once */
|
||||||
}
|
}
|
||||||
if (offset > WINSIZE) { /* skip WINSIZE bytes */
|
if (offset > WINSIZE) { /* skip WINSIZE bytes */
|
||||||
strm.avail_out = WINSIZE;
|
state->strm.avail_out = WINSIZE;
|
||||||
strm.next_out = discard;
|
state->strm.next_out = discard;
|
||||||
offset -= WINSIZE;
|
offset -= WINSIZE;
|
||||||
}
|
}
|
||||||
else if (offset != 0) { /* last skip */
|
else if (offset != 0) { /* last skip */
|
||||||
strm.avail_out = (unsigned)offset;
|
state->strm.avail_out = (unsigned)offset;
|
||||||
strm.next_out = discard;
|
state->strm.next_out = discard;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* uncompress until avail_out filled, or end of stream */
|
/* uncompress until avail_out filled, or end of stream */
|
||||||
do {
|
do {
|
||||||
if (strm.avail_in == 0) {
|
if (state->strm.avail_in == 0) {
|
||||||
state && (state->in_offset = PX_ftello(in));
|
state->in_offset = PX_ftello(in);
|
||||||
strm.avail_in = fread(input, 1, CHUNK, in);
|
state->strm.avail_in = fread(input, 1, CHUNK, in);
|
||||||
if (ferror(in)) {
|
if (ferror(in)) {
|
||||||
ret = Z_ERRNO;
|
ret = Z_ERRNO;
|
||||||
goto extract_ret;
|
goto extract_ret;
|
||||||
}
|
}
|
||||||
if (strm.avail_in == 0) {
|
if (state->strm.avail_in == 0) {
|
||||||
ret = Z_DATA_ERROR;
|
ret = Z_DATA_ERROR;
|
||||||
goto extract_ret;
|
goto extract_ret;
|
||||||
}
|
}
|
||||||
strm.next_in = input;
|
state->strm.next_in = input;
|
||||||
}
|
}
|
||||||
uint prev_in = strm.avail_in;
|
uint prev_in = state->strm.avail_in;
|
||||||
ret = inflate(&strm, Z_NO_FLUSH); /* normal inflate */
|
ret = inflate(&state->strm, Z_NO_FLUSH); /* normal inflate */
|
||||||
state && (state->in_offset += (prev_in - strm.avail_in));
|
state->in_offset += (prev_in - state->strm.avail_in);
|
||||||
if (ret == Z_NEED_DICT)
|
if (ret == Z_NEED_DICT)
|
||||||
ret = Z_DATA_ERROR;
|
ret = Z_DATA_ERROR;
|
||||||
if (ret == Z_MEM_ERROR || ret == Z_DATA_ERROR)
|
if (ret == Z_MEM_ERROR || ret == Z_DATA_ERROR)
|
||||||
goto extract_ret;
|
goto extract_ret;
|
||||||
if (ret == Z_STREAM_END)
|
if (ret == Z_STREAM_END)
|
||||||
break;
|
break;
|
||||||
} while (strm.avail_out != 0);
|
} while (state->strm.avail_out != 0);
|
||||||
|
|
||||||
/* if reach end of stream, then don't keep trying to get more */
|
/* if reach end of stream, then don't keep trying to get more */
|
||||||
if (ret == Z_STREAM_END)
|
if (ret == Z_STREAM_END)
|
||||||
@ -461,16 +457,15 @@ local int extract(FILE *in, struct access *index, PX_off_t offset,
|
|||||||
|
|
||||||
isEnd = ret == Z_STREAM_END;
|
isEnd = ret == Z_STREAM_END;
|
||||||
/* compute number of uncompressed bytes read after offset */
|
/* compute number of uncompressed bytes read after offset */
|
||||||
ret = skip ? 0 : len - strm.avail_out;
|
ret = skip ? 0 : len - state->strm.avail_out;
|
||||||
|
|
||||||
/* clean up and return bytes read or error */
|
/* clean up and return bytes read or error */
|
||||||
extract_ret:
|
extract_ret:
|
||||||
if (state && ret == len && !isEnd) {
|
if (ret == len && !isEnd) {
|
||||||
state->out_offset += len;
|
state->out_offset += len;
|
||||||
state->strm = strm;
|
|
||||||
state->isValid = 1;
|
state->isValid = 1;
|
||||||
} else
|
} else
|
||||||
(void)inflateEnd(&strm);
|
inflateEnd(&state->strm);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user