]> granicus.if.org Git - taglib/commitdiff
Read the compressed data as a stream
authorScott Wheeler <scott@directededge.com>
Sun, 4 Jan 2015 18:58:18 +0000 (19:58 +0100)
committerScott Wheeler <scott@directededge.com>
Sun, 4 Jan 2015 18:58:18 +0000 (19:58 +0100)
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

taglib/mpeg/id3v2/id3v2frame.cpp

index 3cafcff9e6beecc27d9e0fddee65d3de8c4772b1..98ec2ff7471bf8e0789904155b02f9167079550c 100644 (file)
@@ -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