From a27199b7722b857bc6c4bc4cad5afa6bebc5c5d2 Mon Sep 17 00:00:00 2001
From: Tsuda Kageyu <tsuda.kageyu@gmail.com>
Date: Wed, 24 Feb 2016 00:26:37 +0900
Subject: [PATCH] Support Boost iostreams library to decode compressed ID3v2
 frames in additiion to zlib.

This will help Windows users build TagLib without zlib source.
---
 ConfigureChecks.cmake    |  9 ++++++++
 config.h.cmake           |  1 +
 taglib/CMakeLists.txt    |  6 ++++-
 taglib/toolkit/tzlib.cpp | 47 +++++++++++++++++++++++++++++++++++-----
 4 files changed, 56 insertions(+), 7 deletions(-)

diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake
index 0f2b6d87..ee4fdc2e 100644
--- a/ConfigureChecks.cmake
+++ b/ConfigureChecks.cmake
@@ -225,6 +225,15 @@ if(NOT ZLIB_SOURCE)
   else()
     set(HAVE_ZLIB 0)
   endif()
+
+  if(NOT HAVE_ZLIB)
+    find_package(Boost COMPONENTS iostreams zlib)
+    if(Boost_IOSTREAMS_FOUND AND Boost_ZLIB_FOUND)
+      set(HAVE_BOOST_ZLIB 1)
+    else()
+      set(HAVE_BOOST_ZLIB 0)
+    endif()
+  endif()
 endif()
 
 # Determine whether CppUnit is installed.
diff --git a/config.h.cmake b/config.h.cmake
index 7ac72410..7eb5993f 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -25,6 +25,7 @@
 
 /* Defined if zlib is installed */
 #cmakedefine   HAVE_ZLIB 1
+#cmakedefine   HAVE_BOOST_ZLIB 1
 
 /* Indicates whether debug messages are shown even in release mode */
 #cmakedefine   TRACE_IN_RELEASE 1
diff --git a/taglib/CMakeLists.txt b/taglib/CMakeLists.txt
index f248d0d1..000f7937 100644
--- a/taglib/CMakeLists.txt
+++ b/taglib/CMakeLists.txt
@@ -32,7 +32,7 @@ elseif(HAVE_ZLIB_SOURCE)
   include_directories(${ZLIB_SOURCE})
 endif()
 
-if(HAVE_BOOST_BYTESWAP OR HAVE_BOOST_ATOMIC)
+if(HAVE_BOOST_BYTESWAP OR HAVE_BOOST_ATOMIC OR HAVE_BOOST_ZLIB)
   include_directories(${Boost_INCLUDE_DIR})
 endif()
 
@@ -352,6 +352,10 @@ if(HAVE_BOOST_ATOMIC)
   target_link_libraries(tag ${Boost_ATOMIC_LIBRARY})
 endif()
 
+if(HAVE_BOOST_ZLIB)
+  target_link_libraries(tag ${Boost_IOSTREAMS_LIBRARY} ${Boost_ZLIB_LIBRARY})
+endif()
+
 set_target_properties(tag PROPERTIES
   VERSION ${TAGLIB_SOVERSION_MAJOR}.${TAGLIB_SOVERSION_MINOR}.${TAGLIB_SOVERSION_PATCH}
   SOVERSION ${TAGLIB_SOVERSION_MAJOR}
diff --git a/taglib/toolkit/tzlib.cpp b/taglib/toolkit/tzlib.cpp
index 3d49732a..40158fd2 100644
--- a/taglib/toolkit/tzlib.cpp
+++ b/taglib/toolkit/tzlib.cpp
@@ -27,8 +27,11 @@
 # include <config.h>
 #endif
 
-#ifdef HAVE_ZLIB
+#if defined(HAVE_ZLIB)
 # include <zlib.h>
+#elif defined(HAVE_BOOST_ZLIB)
+# include <boost/iostreams/filtering_streambuf.hpp>
+# include <boost/iostreams/filter/zlib.hpp>
 #endif
 
 #include <tstring.h>
@@ -40,7 +43,7 @@ using namespace TagLib;
 
 bool zlib::isAvailable()
 {
-#ifdef HAVE_ZLIB
+#if defined(HAVE_ZLIB) || defined(HAVE_BOOST_ZLIB)
 
   return true;
 
@@ -53,7 +56,7 @@ bool zlib::isAvailable()
 
 ByteVector zlib::decompress(const ByteVector &data)
 {
-#ifdef HAVE_ZLIB
+#if defined(HAVE_ZLIB)
 
   z_stream stream = {};
 
@@ -81,9 +84,9 @@ ByteVector zlib::decompress(const ByteVector &data)
     const int result = inflate(&stream, Z_NO_FLUSH);
 
     if(result == Z_STREAM_ERROR ||
-        result == Z_NEED_DICT ||
-        result == Z_DATA_ERROR ||
-        result == Z_MEM_ERROR)
+       result == Z_NEED_DICT ||
+       result == Z_DATA_ERROR ||
+       result == Z_MEM_ERROR)
     {
       if(result != Z_STREAM_ERROR)
         inflateEnd(&stream);
@@ -99,6 +102,38 @@ ByteVector zlib::decompress(const ByteVector &data)
 
   return outData;
 
+#elif defined(HAVE_BOOST_ZLIB)
+
+  using namespace boost::iostreams;
+
+  struct : public sink
+  {
+    ByteVector data;
+
+    typedef char     char_type;
+    typedef sink_tag category;
+
+    std::streamsize write(char const* s, std::streamsize n)
+    {
+      const unsigned int originalSize = data.size();
+
+      data.resize(static_cast<unsigned int>(originalSize + n));
+      ::memcpy(data.data() + originalSize, s, static_cast<size_t>(n));
+
+      return n;
+    }
+  } sink;
+
+  try {
+    zlib_decompressor().write(sink, data.data(), data.size());
+  }
+  catch(const zlib_error &) {
+    debug("zlib::decompress() - Error reading compressed stream.");
+    return ByteVector();
+  }
+
+  return sink.data;
+
 #else
 
   return ByteVector();
-- 
2.40.0