From: Scott Wheeler Date: Sun, 4 Jan 2015 18:58:18 +0000 (+0100) Subject: Read the compressed data as a stream X-Git-Tag: v1.10beta~129 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=caa53e8de5591a75138f90cced544908d016222b;p=taglib Read the compressed data as a stream This avoids allocating the complete buffer at first based solely on the value read from the frame header. This then does a sanity check at the end of reading to make sure that the two values match. At present, it just prints a debugging message if the values do not match. Fixes #466 --- diff --git a/taglib/mpeg/id3v2/id3v2frame.cpp b/taglib/mpeg/id3v2/id3v2frame.cpp index 3cafcff9..98ec2ff7 100644 --- a/taglib/mpeg/id3v2/id3v2frame.cpp +++ b/taglib/mpeg/id3v2/id3v2frame.cpp @@ -254,12 +254,44 @@ ByteVector Frame::fieldData(const ByteVector &frameData) const if(d->header->compression() && !d->header->encryption()) { - ByteVector data(frameDataLength); - uLongf uLongTmp = frameDataLength; - ::uncompress((Bytef *) data.data(), - (uLongf *) &uLongTmp, - (Bytef *) frameData.data() + frameDataOffset, - size()); + z_stream stream; + memset(&stream, 0, sizeof(z_stream)); + + if(inflateInit(&stream) != Z_OK) + return ByteVector(); + + stream.avail_in = (uLongf) frameDataLength; + stream.next_in = (Bytef *) frameData.data() + frameDataOffset; + + static const uint chunkSize = 1024; + + ByteVector data; + ByteVector chunk(chunkSize); + + do { + stream.avail_out = (uLongf) chunk.size(); + stream.next_out = (Bytef *) chunk.data(); + + int result = inflate(&stream, Z_NO_FLUSH); + + if(result == Z_STREAM_ERROR) + return ByteVector(); + else if(result == Z_NEED_DICT || + result == Z_DATA_ERROR || + result == Z_MEM_ERROR) + { + inflateEnd(&stream); + return ByteVector(); + } + + data.append(stream.avail_out == 0 ? chunk : chunk.mid(0, chunk.size() - stream.avail_out)); + } while(stream.avail_out == 0); + + inflateEnd(&stream); + + if(frameDataLength != data.size()) + debug("frameDataLength does not match the data length returned by zlib"); + return data; } else