title: zlib inflate decompression operation
body: <p>I have a data buffer which contains multiple compressed members, it could be deflate or zlib compressed member.</p>
  
  <p>I found that zlib <code>inflate</code> call returns <code>Z_STREAM_END</code> after processing the first compressed block, Here multiple compressed member can be in any number(here in my example Its 3). But this data comes from other sides which doesn't communicated detail about number of compressed member in a data.</p>
  
  <p>So how could I implement the use of zlib inflate functionality so that it could work over multiple compressed member ? </p>
  
  <p>Following is a sample quick &amp; dirty example in which I try to elaborate my problem.
  This referred the case with zlib 1.2.5 library.</p>
  
  <pre><code>/* example.c -- understanding zlib inflate/decompression operation
   */
  
  #define CHECK_ERR(err, msg) { \
      if (err != Z_OK) { \
          std::cerr &lt;&lt; msg &lt;&lt; " error: " &lt;&lt; err &lt;&lt; std::endl; \
          exit(1); \
      } \
  }
  
  /* ===========================================================================
   * deflate() to create compressed data
   */
  void test_deflate(std::vector&lt;uint8_t&gt; &amp; input_data, std::vector&lt;uint8_t&gt;&amp; compr)
  {
      z_stream c_stream; /* compression stream */
      int err;
  
      compr.clear();
  
      c_stream.zalloc = (alloc_func)0;
      c_stream.zfree = (free_func)0;
      c_stream.opaque = (voidpf)0;
  
      err = deflateInit(&amp;c_stream, Z_DEFAULT_COMPRESSION);
      CHECK_ERR(err, "deflateInit");
  
      c_stream.next_in  = &amp;input_data[0];
      c_stream.avail_in = input_data.size();
  
      for (;;) {
          uint8_t c_buffer[10] = {};
          c_stream.next_out  = &amp;c_buffer[0];
          c_stream.avail_out = 10;
  
          err = deflate(&amp;c_stream, Z_FINISH);
          if (err == Z_STREAM_END)
          {
              for (int i = 0; i &lt; (10 - c_stream.avail_out); i++)
                  compr.push_back(c_buffer[i]);
              break;
          }
          CHECK_ERR(err, "deflate");
          for (int i = 0; i &lt; (10 - c_stream.avail_out); i++)
              compr.push_back(c_buffer[i]);
      }
  
      std::cout &lt;&lt; "Compressed data (size = " &lt;&lt; std::dec &lt;&lt; compr.size() &lt;&lt; ") = ";
      for (int i = 0; i &lt; compr.size(); i++)
          std::cout &lt;&lt; (uint32_t) compr[i];
      std::cout &lt;&lt; std::endl;
  
      err = deflateEnd(&amp;c_stream);
      CHECK_ERR(err, "deflateEnd");
  }
  
  /* ===========================================================================
   * Test inflate()
   */
  void test_inflate(std::vector&lt;uint8_t&gt; &amp;compr,
                    std::vector&lt;uint8_t&gt; &amp;uncompr)
  {
      int err;
      z_stream d_stream; /* decompression stream */
  
      uncompr.clear();
  
      d_stream.zalloc = Z_NULL;
      d_stream.zfree = Z_NULL;
      d_stream.opaque = Z_NULL;
      d_stream.avail_in = 0;
      d_stream.next_in = Z_NULL;
      err = inflateInit(&amp;d_stream);
      CHECK_ERR(err, "inflateInit");
  
      d_stream.avail_in = compr.size();
      d_stream.next_in  = &amp;compr[0];
  
      for(;;) {
          uint8_t d_buffer[10] = {};
          d_stream.next_out = &amp;d_buffer[0];
          d_stream.avail_out = 10;
  
          err = inflate(&amp;d_stream, Z_NO_FLUSH);
  
          if (err == Z_STREAM_END) {
              for (int i = 0; i &lt; (10 - d_stream.avail_out); i++)
                  uncompr.push_back(d_buffer[i]);
              if (d_stream.avail_in == 0)
                  break;
          }
  
          CHECK_ERR(err, "inflate");
          for (int i = 0; i &lt; (10 - d_stream.avail_out); i++)
              uncompr.push_back(d_buffer[i]);
      }
      err = inflateEnd(&amp;d_stream);
      CHECK_ERR(err, "inflateEnd");
  
      std::cout &lt;&lt; "Uncompressed data (size = " &lt;&lt; std::dec &lt;&lt; uncompr.size() &lt;&lt; ") = ";
      for (int i = 0; i &lt; uncompr.size(); i++)
          std::cout &lt;&lt; (uint32_t) uncompr[i];
      std::cout &lt;&lt; std::endl;
  }
  
  
  /* ===========================================================================
   * Usage:  example
   */
  
  int main(int argc, char **argv)
  {
      std::vector&lt;uint8_t&gt; input_data;
      std::vector&lt;uint8_t&gt; compr, multiple_compr;
      std::vector&lt;uint8_t&gt; uncompr;
  
      std::cout &lt;&lt; "Input Data (in hex) = ";
      for (int i=0; i&lt;32; i++) {
          input_data.push_back((uint8_t)i);
          if( i &amp;&amp; (i % 2 == 0))
              std::cout &lt;&lt; " ";
          std::cout &lt;&lt; std::hex &lt;&lt; (uint32_t)input_data[i];
      }
      std::cout &lt;&lt; std::endl;
  
      // create compressed buffer-1 from input data
      test_deflate(input_data, compr);
  
      // copy compressed buffer-1 data into multiple compressed member buffer
      multiple_compr = compr;
      compr.clear();
  
      // create compressed buffer-2 from input data
      test_deflate(input_data, compr);
  
      // append data of compressed buffer-2 into multiple compressed member buffer
      for(int i=0; i&lt; compr.size(); i++)
      {
          multiple_compr.push_back(compr[i]);
      }
  
      // create decompressed output
      test_inflate(multiple_compr, uncompr);
  
      // compare decompressed data with input data
      std::vector&lt;uint8_t&gt; final_data;
      final_data.push_back(input_data);
      final_data.push_back(input_data);
      if (final_data == uncompr)
         std::cout &lt;&lt; "Matched" &lt;&lt; std::endl;
      else
         std::cout &lt;&lt; "Not Matched" &lt;&lt; std::endl;
  
      return 0;
  }
  </code></pre>
  
  <p>1) Here second time inflate call returns error, But I wants it proceed successfully why it work like this ?</p>
  
  <p>2) When I use Z_FINISH in the inflate call argument it returns with error, why can't I use Z_FINISH here ?</p>
  
  <p>Kindly correct my example and suggest some optimized approach to do the same.</p>