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