1    	// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
2    	// (C) Copyright 2003-2007 Jonathan Turkanis
3    	// Distributed under the Boost Software License, Version 1.0. (See accompanying
4    	// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
5    	
6    	// See http://www.boost.org/libs/iostreams for documentation.
7    	
8    	// Note: custom allocators are not supported on VC6, since that compiler
9    	// had trouble finding the function zlib_base::do_init.
10   	
11   	#ifndef BOOST_IOSTREAMS_ZLIB_HPP_INCLUDED
12   	#define BOOST_IOSTREAMS_ZLIB_HPP_INCLUDED
13   	
14   	#if defined(_MSC_VER)
15   	# pragma once
16   	#endif              
17   	
18   	#include <cassert>                            
19   	#include <iosfwd>            // streamsize.                 
20   	#include <memory>            // allocator, bad_alloc.
21   	#include <new>          
22   	#include <boost/config.hpp>  // MSVC, STATIC_CONSTANT, DEDUCED_TYPENAME, DINKUM.
23   	#include <boost/cstdint.hpp> // uint*_t
24   	#include <boost/detail/workaround.hpp>
25   	#include <boost/iostreams/constants.hpp>   // buffer size.
26   	#include <boost/iostreams/detail/config/auto_link.hpp>
27   	#include <boost/iostreams/detail/config/dyn_link.hpp>
28   	#include <boost/iostreams/detail/config/wide_streams.hpp>
29   	#include <boost/iostreams/detail/config/zlib.hpp>
30   	#include <boost/iostreams/detail/ios.hpp>  // failure, streamsize.
31   	#include <boost/iostreams/filter/symmetric.hpp>                
32   	#include <boost/iostreams/pipeline.hpp>                
33   	#include <boost/type_traits/is_same.hpp>
34   	
35   	// Must come last.
36   	#ifdef BOOST_MSVC
37   	# pragma warning(push)
38   	# pragma warning(disable:4251 4275 4231 4660)         // Dependencies not exported.
39   	#endif
40   	#include <boost/config/abi_prefix.hpp>           
41   	
42   	namespace boost { namespace iostreams {
43   	
44   	namespace zlib {
45   	                    // Typedefs
46   	
47   	typedef uint32_t uint;
48   	typedef uint8_t byte;
49   	typedef uint32_t ulong;
50   	
51   	// Prefix 'x' prevents symbols from being redefined when Z_PREFIX is defined
52   	typedef void* (*xalloc_func)(void*, zlib::uint, zlib::uint);
53   	typedef void (*xfree_func)(void*, void*);
54   	
55   	                    // Compression levels
56   	
57   	BOOST_IOSTREAMS_DECL extern const int no_compression;
58   	BOOST_IOSTREAMS_DECL extern const int best_speed;
59   	BOOST_IOSTREAMS_DECL extern const int best_compression;
60   	BOOST_IOSTREAMS_DECL extern const int default_compression;
61   	
62   	                    // Compression methods
63   	
64   	BOOST_IOSTREAMS_DECL extern const int deflated;
65   	
66   	                    // Compression strategies
67   	
68   	BOOST_IOSTREAMS_DECL extern const int default_strategy;
69   	BOOST_IOSTREAMS_DECL extern const int filtered;
70   	BOOST_IOSTREAMS_DECL extern const int huffman_only;
71   	
72   	                    // Status codes
73   	
74   	BOOST_IOSTREAMS_DECL extern const int okay;
75   	BOOST_IOSTREAMS_DECL extern const int stream_end;
76   	BOOST_IOSTREAMS_DECL extern const int stream_error;
77   	BOOST_IOSTREAMS_DECL extern const int version_error;
78   	BOOST_IOSTREAMS_DECL extern const int data_error;
79   	BOOST_IOSTREAMS_DECL extern const int mem_error;
80   	BOOST_IOSTREAMS_DECL extern const int buf_error;
81   	
82   	                    // Flush codes
83   	
84   	BOOST_IOSTREAMS_DECL extern const int finish;
85   	BOOST_IOSTREAMS_DECL extern const int no_flush;
86   	BOOST_IOSTREAMS_DECL extern const int sync_flush;
87   	
88   	                    // Code for current OS
89   	
90   	//BOOST_IOSTREAMS_DECL extern const int os_code;
91   	
92   	                    // Null pointer constant.
93   	
94   	const int null                               = 0;
95   	
96   	                    // Default values
97   	
98   	const int default_window_bits                = 15;
99   	const int default_mem_level                  = 8;
100  	const bool default_crc                       = false;
101  	const bool default_noheader                  = false;
102  	
103  	} // End namespace zlib. 
104  	
105  	//
106  	// Class name: zlib_params.
107  	// Description: Encapsulates the parameters passed to deflateInit2
108  	//      and inflateInit2 to customize compression and decompression.
109  	//
110  	struct zlib_params {
111  	
112  	    // Non-explicit constructor.
113  	    zlib_params( int level_          = zlib::default_compression,
114  	                 int method_         = zlib::deflated,
115  	                 int window_bits_    = zlib::default_window_bits, 
116  	                 int mem_level_      = zlib::default_mem_level, 
117  	                 int strategy_       = zlib::default_strategy,
118  	                 bool noheader_      = zlib::default_noheader,
119  	                 bool calculate_crc_ = zlib::default_crc )
120  	        : level(level_), method(method_), window_bits(window_bits_),
121  	          mem_level(mem_level_), strategy(strategy_),  
122  	          noheader(noheader_), calculate_crc(calculate_crc_)
123  	        { }
124  	    int level;
125  	    int method;
126  	    int window_bits;
127  	    int mem_level;
128  	    int strategy;
129  	    bool noheader;
130  	    bool calculate_crc;
131  	};
132  	
133  	//
134  	// Class name: zlib_error.
135  	// Description: Subclass of std::ios::failure thrown to indicate
136  	//     zlib errors other than out-of-memory conditions.
137  	//
138  	class BOOST_IOSTREAMS_DECL zlib_error : public BOOST_IOSTREAMS_FAILURE {
139  	public:
140  	    explicit zlib_error(int error);
141  	    int error() const { return error_; }
142  	    static void check BOOST_PREVENT_MACRO_SUBSTITUTION(int error);
143  	private:
144  	    int error_;
145  	};
146  	
147  	namespace detail {
148  	
149  	template<typename Alloc>
150  	struct zlib_allocator_traits {
151  	#ifndef BOOST_NO_STD_ALLOCATOR
152  	#if defined(BOOST_NO_CXX11_ALLOCATOR)
153  	    typedef typename Alloc::template rebind<char>::other type;
154  	#else
155  	    typedef typename std::allocator_traits<Alloc>::template rebind_alloc<char> type;
156  	#endif
157  	#else
158  	    typedef std::allocator<char> type;
159  	#endif
160  	};
161  	
162  	template< typename Alloc,
163  	          typename Base = // VC6 workaround (C2516)
164  	              BOOST_DEDUCED_TYPENAME zlib_allocator_traits<Alloc>::type >
165  	struct zlib_allocator : private Base {
166  	private:
167  	#if defined(BOOST_NO_CXX11_ALLOCATOR) || defined(BOOST_NO_STD_ALLOCATOR)
168  	    typedef typename Base::size_type size_type;
169  	#else
170  	    typedef typename std::allocator_traits<Base>::size_type size_type;
171  	#endif
172  	public:
173  	    BOOST_STATIC_CONSTANT(bool, custom = 
174  	        (!is_same<std::allocator<char>, Base>::value));
175  	    typedef typename zlib_allocator_traits<Alloc>::type allocator_type;
176  	    static void* allocate(void* self, zlib::uint items, zlib::uint size);
177  	    static void deallocate(void* self, void* address);
178  	};
179  	
180  	class BOOST_IOSTREAMS_DECL zlib_base { 
181  	public:
182  	    typedef char char_type;
183  	protected:
184  	    zlib_base();
185  	    ~zlib_base();
186  	    void* stream() { return stream_; }
187  	    template<typename Alloc> 
188  	    void init( const zlib_params& p, 
189  	               bool compress,
190  	               zlib_allocator<Alloc>& zalloc )
191  	        {
(1) Event assignment: Assigning: "custom" = "false".
Also see events: [const][dead_error_condition][dead_error_line][effectively_constant]
192  	            bool custom = zlib_allocator<Alloc>::custom;
(3) Event dead_error_condition: The condition "custom" cannot be true.
(4) Event dead_error_line: Execution cannot reach the expression "allocate" inside this statement: "this->do_init(p, compress, ...".
(5) Event effectively_constant: Local variable "custom" is assigned only once, to a constant value, making it effectively constant throughout its scope. If this is not the intent, examine the logic to see if there is a missing assignment that would make "custom" not remain constant. Otherwise, declaring "custom" as "const" will suppress this defect.
Also see events: [assignment][const]
193  	            do_init( p, compress,
(2) Event const: At condition "custom", the value of "custom" must be equal to 0.
Also see events: [assignment][dead_error_condition][dead_error_line][effectively_constant]
194  	                     custom ? zlib_allocator<Alloc>::allocate : 0,
195  	                     custom ? zlib_allocator<Alloc>::deallocate : 0,
196  	                     &zalloc );
197  	        }
198  	    void before( const char*& src_begin, const char* src_end,
199  	                 char*& dest_begin, char* dest_end );
200  	    void after( const char*& src_begin, char*& dest_begin, 
201  	                bool compress );
202  	    int xdeflate(int flush);  // Prefix 'x' prevents symbols from being 
203  	    int xinflate(int flush);  // redefined when Z_PREFIX is defined
204  	    void reset(bool compress, bool realloc);
205  	public:
206  	    zlib::ulong crc() const { return crc_; }
207  	    int total_in() const { return total_in_; }
208  	    int total_out() const { return total_out_; }
209  	private:
210  	    void do_init( const zlib_params& p, bool compress, 
211  	                  zlib::xalloc_func,
212  	                  zlib::xfree_func, 
213  	                  void* derived );
214  	    void*        stream_;         // Actual type: z_stream*.
215  	    bool         calculate_crc_;
216  	    zlib::ulong  crc_;
217  	    zlib::ulong  crc_imp_;
218  	    int          total_in_;
219  	    int          total_out_;
220  	};
221  	
222  	//
223  	// Template name: zlib_compressor_impl
224  	// Description: Model of C-Style Filte implementing compression by
225  	//      delegating to the zlib function deflate.
226  	//
227  	template<typename Alloc = std::allocator<char> >
228  	class zlib_compressor_impl : public zlib_base, public zlib_allocator<Alloc> { 
229  	public: 
230  	    zlib_compressor_impl(const zlib_params& = zlib::default_compression);
231  	    ~zlib_compressor_impl();
232  	    bool filter( const char*& src_begin, const char* src_end,
233  	                 char*& dest_begin, char* dest_end, bool flush );
234  	    void close();
235  	};
236  	
237  	//
238  	// Template name: zlib_compressor
239  	// Description: Model of C-Style Filte implementing decompression by
240  	//      delegating to the zlib function inflate.
241  	//
242  	template<typename Alloc = std::allocator<char> >
243  	class zlib_decompressor_impl : public zlib_base, public zlib_allocator<Alloc> {
244  	public:
245  	    zlib_decompressor_impl(const zlib_params&);
246  	    zlib_decompressor_impl(int window_bits = zlib::default_window_bits);
247  	    ~zlib_decompressor_impl();
248  	    bool filter( const char*& begin_in, const char* end_in,
249  	                 char*& begin_out, char* end_out, bool flush );
250  	    void close();
251  	    bool eof() const { return eof_; }
252  	private:
253  	    bool eof_;
254  	};
255  	
256  	} // End namespace detail.
257  	
258  	//
259  	// Template name: zlib_compressor
260  	// Description: Model of InputFilter and OutputFilter implementing
261  	//      compression using zlib.
262  	//
263  	template<typename Alloc = std::allocator<char> >
264  	struct basic_zlib_compressor 
265  	    : symmetric_filter<detail::zlib_compressor_impl<Alloc>, Alloc> 
266  	{
267  	private:
268  	    typedef detail::zlib_compressor_impl<Alloc>         impl_type;
269  	    typedef symmetric_filter<impl_type, Alloc>  base_type;
270  	public:
271  	    typedef typename base_type::char_type               char_type;
272  	    typedef typename base_type::category                category;
273  	    basic_zlib_compressor( const zlib_params& = zlib::default_compression, 
274  	                           std::streamsize buffer_size = default_device_buffer_size );
275  	    zlib::ulong crc() { return this->filter().crc(); }
276  	    int total_in() {  return this->filter().total_in(); }
277  	};
278  	BOOST_IOSTREAMS_PIPABLE(basic_zlib_compressor, 1)
279  	
280  	typedef basic_zlib_compressor<> zlib_compressor;
281  	
282  	//
283  	// Template name: zlib_decompressor
284  	// Description: Model of InputFilter and OutputFilter implementing
285  	//      decompression using zlib.
286  	//
287  	template<typename Alloc = std::allocator<char> >
288  	struct basic_zlib_decompressor 
289  	    : symmetric_filter<detail::zlib_decompressor_impl<Alloc>, Alloc> 
290  	{
291  	private:
292  	    typedef detail::zlib_decompressor_impl<Alloc>       impl_type;
293  	    typedef symmetric_filter<impl_type, Alloc>  base_type;
294  	public:
295  	    typedef typename base_type::char_type               char_type;
296  	    typedef typename base_type::category                category;
297  	    basic_zlib_decompressor( int window_bits = zlib::default_window_bits,
298  	                             std::streamsize buffer_size = default_device_buffer_size );
299  	    basic_zlib_decompressor( const zlib_params& p,
300  	                             std::streamsize buffer_size = default_device_buffer_size );
301  	    zlib::ulong crc() { return this->filter().crc(); }
302  	    int total_out() {  return this->filter().total_out(); }
303  	    bool eof() { return this->filter().eof(); }
304  	};
305  	BOOST_IOSTREAMS_PIPABLE(basic_zlib_decompressor, 1)
306  	
307  	typedef basic_zlib_decompressor<> zlib_decompressor;
308  	
309  	//----------------------------------------------------------------------------//
310  	
311  	//------------------Implementation of zlib_allocator--------------------------//
312  	
313  	namespace detail {
314  	
315  	template<typename Alloc, typename Base>
316  	void* zlib_allocator<Alloc, Base>::allocate
317  	    (void* self, zlib::uint items, zlib::uint size)
318  	{ 
319  	    size_type len = items * size;
320  	    char* ptr = 
321  	        static_cast<allocator_type*>(self)->allocate
322  	            (len + sizeof(size_type)
323  	            #if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1)
324  	                , (char*)0
325  	            #endif
326  	            );
327  	    *reinterpret_cast<size_type*>(ptr) = len;
328  	    return ptr + sizeof(size_type);
329  	}
330  	
331  	template<typename Alloc, typename Base>
332  	void zlib_allocator<Alloc, Base>::deallocate(void* self, void* address)
333  	{ 
334  	    char* ptr = reinterpret_cast<char*>(address) - sizeof(size_type);
335  	    size_type len = *reinterpret_cast<size_type*>(ptr) + sizeof(size_type);
336  	    static_cast<allocator_type*>(self)->deallocate(ptr, len); 
337  	}
338  	
339  	//------------------Implementation of zlib_compressor_impl--------------------//
340  	
341  	template<typename Alloc>
342  	zlib_compressor_impl<Alloc>::zlib_compressor_impl(const zlib_params& p)
343  	{ init(p, true, static_cast<zlib_allocator<Alloc>&>(*this)); }
344  	
345  	template<typename Alloc>
346  	zlib_compressor_impl<Alloc>::~zlib_compressor_impl()
347  	{ reset(true, false); }
348  	
349  	template<typename Alloc>
350  	bool zlib_compressor_impl<Alloc>::filter
351  	    ( const char*& src_begin, const char* src_end,
352  	      char*& dest_begin, char* dest_end, bool flush )
353  	{
354  	    before(src_begin, src_end, dest_begin, dest_end);
355  	    int result = xdeflate(flush ? zlib::finish : zlib::no_flush);
356  	    after(src_begin, dest_begin, true);
357  	    zlib_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(result);
358  	    return result != zlib::stream_end;
359  	}
360  	
361  	template<typename Alloc>
362  	void zlib_compressor_impl<Alloc>::close() { reset(true, true); }
363  	
364  	//------------------Implementation of zlib_decompressor_impl------------------//
365  	
366  	template<typename Alloc>
367  	zlib_decompressor_impl<Alloc>::zlib_decompressor_impl(const zlib_params& p)
368  	  : eof_(false)
369  	{ init(p, false, static_cast<zlib_allocator<Alloc>&>(*this)); }
370  	
371  	template<typename Alloc>
372  	zlib_decompressor_impl<Alloc>::~zlib_decompressor_impl()
373  	{ reset(false, false); }
374  	
375  	template<typename Alloc>
376  	zlib_decompressor_impl<Alloc>::zlib_decompressor_impl(int window_bits)
377  	{ 
378  	    zlib_params p;
379  	    p.window_bits = window_bits;
380  	    init(p, false, static_cast<zlib_allocator<Alloc>&>(*this)); 
381  	}
382  	
383  	template<typename Alloc>
384  	bool zlib_decompressor_impl<Alloc>::filter
385  	    ( const char*& src_begin, const char* src_end,
386  	      char*& dest_begin, char* dest_end, bool /* flush */ )
387  	{
388  	    before(src_begin, src_end, dest_begin, dest_end);
389  	    int result = xinflate(zlib::sync_flush);
390  	    after(src_begin, dest_begin, false);
391  	    zlib_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(result);
392  	    return !(eof_ = result == zlib::stream_end);
393  	}
394  	
395  	template<typename Alloc>
396  	void zlib_decompressor_impl<Alloc>::close() {
397  	    eof_ = false;
398  	    reset(false, true);
399  	}
400  	
401  	} // End namespace detail.
402  	
403  	//------------------Implementation of zlib_decompressor-----------------------//
404  	
405  	template<typename Alloc>
406  	basic_zlib_compressor<Alloc>::basic_zlib_compressor
407  	    (const zlib_params& p, std::streamsize buffer_size) 
408  	    : base_type(buffer_size, p) { }
409  	
410  	//------------------Implementation of zlib_decompressor-----------------------//
411  	
412  	template<typename Alloc>
413  	basic_zlib_decompressor<Alloc>::basic_zlib_decompressor
414  	    (int window_bits, std::streamsize buffer_size) 
415  	    : base_type(buffer_size, window_bits) { }
416  	
417  	template<typename Alloc>
418  	basic_zlib_decompressor<Alloc>::basic_zlib_decompressor
419  	    (const zlib_params& p, std::streamsize buffer_size) 
420  	    : base_type(buffer_size, p) { }
421  	
422  	//----------------------------------------------------------------------------//
423  	
424  	} } // End namespaces iostreams, boost.
425  	
426  	#include <boost/config/abi_suffix.hpp> // Pops abi_suffix.hpp pragmas.
427  	#ifdef BOOST_MSVC
428  	# pragma warning(pop)
429  	#endif
430  	
431  	#endif // #ifndef BOOST_IOSTREAMS_ZLIB_HPP_INCLUDED
432