• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_BZIP2_HPP_INCLUDED
12 #define BOOST_IOSTREAMS_BZIP2_HPP_INCLUDED
13 
14 #if defined(_MSC_VER)
15 # pragma once
16 #endif
17 
18 #include <cassert>
19 #include <memory>            // allocator.
20 #include <new>               // bad_alloc.
21 #include <boost/config.hpp>  // MSVC, STATIC_CONSTANT, DEDUCED_TYPENAME, DINKUM.
22 #include <boost/detail/workaround.hpp>
23 #include <boost/iostreams/constants.hpp>   // buffer size.
24 #include <boost/iostreams/detail/config/auto_link.hpp>
25 #include <boost/iostreams/detail/config/bzip2.hpp>
26 #include <boost/iostreams/detail/config/dyn_link.hpp>
27 #include <boost/iostreams/detail/config/wide_streams.hpp>
28 #include <boost/iostreams/detail/ios.hpp>  // failure, streamsize.
29 #include <boost/iostreams/filter/symmetric.hpp>
30 #include <boost/iostreams/pipeline.hpp>
31 #include <boost/type_traits/is_same.hpp>
32 
33 // Must come last.
34 #ifdef BOOST_MSVC
35 # pragma warning(push)
36 # pragma warning(disable:4251 4231 4660)
37 #endif
38 #include <boost/config/abi_prefix.hpp>
39 
40 // Temporary fix.
41 #undef small
42 
43 namespace boost { namespace iostreams {
44 
45 namespace bzip2 {
46 
47                     // Typedefs.
48 
49 typedef void* (*alloc_func)(void*, int, int);
50 typedef void (*free_func)(void*, void*);
51 
52                     // Status codes
53 
54 BOOST_IOSTREAMS_DECL extern const int ok;
55 BOOST_IOSTREAMS_DECL extern const int run_ok;
56 BOOST_IOSTREAMS_DECL extern const int flush_ok;
57 BOOST_IOSTREAMS_DECL extern const int finish_ok;
58 BOOST_IOSTREAMS_DECL extern const int stream_end;
59 BOOST_IOSTREAMS_DECL extern const int sequence_error;
60 BOOST_IOSTREAMS_DECL extern const int param_error;
61 BOOST_IOSTREAMS_DECL extern const int mem_error;
62 BOOST_IOSTREAMS_DECL extern const int data_error;
63 BOOST_IOSTREAMS_DECL extern const int data_error_magic;
64 BOOST_IOSTREAMS_DECL extern const int io_error;
65 BOOST_IOSTREAMS_DECL extern const int unexpected_eof;
66 BOOST_IOSTREAMS_DECL extern const int outbuff_full;
67 BOOST_IOSTREAMS_DECL extern const int config_error;
68 
69                     // Action codes
70 
71 BOOST_IOSTREAMS_DECL extern const int finish;
72 BOOST_IOSTREAMS_DECL extern const int run;
73 
74                     // Default values
75 
76 const int default_block_size   = 9;
77 const int default_work_factor  = 30;
78 const bool default_small       = false;
79 
80 } // End namespace bzip2.
81 
82 //
83 // Class name: bzip2_params.
84 // Description: Encapsulates the parameters passed to deflateInit2
85 //      to customize compression.
86 //
87 struct bzip2_params {
88 
89     // Non-explicit constructor for compression.
bzip2_paramsboost::iostreams::bzip2_params90     bzip2_params( int block_size_  = bzip2::default_block_size,
91                   int work_factor_ = bzip2::default_work_factor )
92         : block_size(block_size_), work_factor(work_factor_)
93         { }
94 
95     // Constructor for decompression.
bzip2_paramsboost::iostreams::bzip2_params96     bzip2_params(bool small)
97         : small(small), work_factor(0)
98         { }
99 
100     union {
101         int   block_size;    // For compression.
102         bool  small;         // For decompression.
103     };
104     int       work_factor;
105 };
106 
107 //
108 // Class name: bzip2_error.
109 // Description: Subclass of std::ios_base::failure thrown to indicate
110 //     bzip2 errors other than out-of-memory conditions.
111 //
112 class BOOST_IOSTREAMS_DECL bzip2_error : public BOOST_IOSTREAMS_FAILURE {
113 public:
114     explicit bzip2_error(int error);
error() const115     int error() const { return error_; }
116     static void check BOOST_PREVENT_MACRO_SUBSTITUTION(int error);
117 private:
118     int error_;
119 };
120 
121 namespace detail {
122 
123 template<typename Alloc>
124 struct bzip2_allocator_traits {
125 #ifndef BOOST_NO_STD_ALLOCATOR
126 #if defined(BOOST_NO_CXX11_ALLOCATOR)
127     typedef typename Alloc::template rebind<char>::other type;
128 #else
129     typedef typename std::allocator_traits<Alloc>::template rebind_alloc<char> type;
130 #endif
131 #else
132     typedef std::allocator<char> type;
133 #endif
134 };
135 
136 template< typename Alloc,
137           typename Base = // VC6 workaround (C2516)
138               BOOST_DEDUCED_TYPENAME bzip2_allocator_traits<Alloc>::type >
139 struct bzip2_allocator : private Base {
140 private:
141 #if defined(BOOST_NO_CXX11_ALLOCATOR) || defined(BOOST_NO_STD_ALLOCATOR)
142     typedef typename Base::size_type size_type;
143 #else
144     typedef typename std::allocator_traits<Base>::size_type size_type;
145 #endif
146 public:
147     BOOST_STATIC_CONSTANT(bool, custom =
148         (!is_same<std::allocator<char>, Base>::value));
149     typedef typename bzip2_allocator_traits<Alloc>::type allocator_type;
150     static void* allocate(void* self, int items, int size);
151     static void deallocate(void* self, void* address);
152 };
153 
154 class BOOST_IOSTREAMS_DECL bzip2_base  {
155 public:
156     typedef char char_type;
157 protected:
158     bzip2_base(const bzip2_params& params);
159     ~bzip2_base();
params()160     bzip2_params& params() { return params_; }
ready()161     bool& ready() { return ready_; }
162     template<typename Alloc>
init(bool compress,bzip2_allocator<Alloc> & alloc)163     void init( bool compress,
164                bzip2_allocator<Alloc>& alloc )
165         {
166             bool custom = bzip2_allocator<Alloc>::custom;
167             do_init( compress,
168                      custom ? bzip2_allocator<Alloc>::allocate : 0,
169                      custom ? bzip2_allocator<Alloc>::deallocate : 0,
170                      custom ? &alloc : 0 );
171         }
172     void before( const char*& src_begin, const char* src_end,
173                  char*& dest_begin, char* dest_end );
174     void after(const char*& src_begin, char*& dest_begin);
175     int check_end(const char* src_begin, const char* dest_begin);
176     int compress(int action);
177     int decompress();
178     int end(bool compress, std::nothrow_t);
179     void end(bool compress);
180 private:
181     void do_init( bool compress,
182                   bzip2::alloc_func,
183                   bzip2::free_func,
184                   void* derived );
185     bzip2_params  params_;
186     void*         stream_; // Actual type: bz_stream*.
187     bool          ready_;
188 };
189 
190 //
191 // Template name: bzip2_compressor_impl
192 // Description: Model of SymmetricFilter implementing compression by
193 //      delegating to the libbzip2 function BZ_bzCompress.
194 //
195 template<typename Alloc = std::allocator<char> >
196 class bzip2_compressor_impl
197     : public bzip2_base,
198       #if BOOST_WORKAROUND(__BORLANDC__, < 0x600)
199           public
200       #endif
201       bzip2_allocator<Alloc>
202 {
203 public:
204     bzip2_compressor_impl(const bzip2_params&);
205     ~bzip2_compressor_impl();
206     bool filter( const char*& src_begin, const char* src_end,
207                  char*& dest_begin, char* dest_end, bool flush );
208     void close();
209 private:
210     void init();
211     bool eof_; // Guard to make sure filter() isn't called after it returns false.
212 };
213 
214 //
215 // Template name: bzip2_compressor
216 // Description: Model of SymmetricFilter implementing decompression by
217 //      delegating to the libbzip2 function BZ_bzDecompress.
218 //
219 template<typename Alloc = std::allocator<char> >
220 class bzip2_decompressor_impl
221     : public bzip2_base,
222       #if BOOST_WORKAROUND(__BORLANDC__, < 0x600)
223           public
224       #endif
225       bzip2_allocator<Alloc>
226 {
227 public:
228     bzip2_decompressor_impl(bool small = bzip2::default_small);
229     ~bzip2_decompressor_impl();
230     bool filter( const char*& begin_in, const char* end_in,
231                  char*& begin_out, char* end_out, bool flush );
232     void close();
233 private:
234     void init();
235     bool eof_; // Guard to make sure filter() isn't called after it returns false.
236 };
237 
238 } // End namespace detail.
239 
240 //
241 // Template name: bzip2_compressor
242 // Description: Model of InputFilter and OutputFilter implementing
243 //      compression using libbzip2.
244 //
245 template<typename Alloc = std::allocator<char> >
246 struct basic_bzip2_compressor
247     : symmetric_filter<detail::bzip2_compressor_impl<Alloc>, Alloc>
248 {
249 private:
250     typedef detail::bzip2_compressor_impl<Alloc>        impl_type;
251     typedef symmetric_filter<impl_type, Alloc>  base_type;
252 public:
253     typedef typename base_type::char_type               char_type;
254     typedef typename base_type::category                category;
255     basic_bzip2_compressor( const bzip2_params& = bzip2::default_block_size,
256                             std::streamsize buffer_size =  default_device_buffer_size );
257 };
258 BOOST_IOSTREAMS_PIPABLE(basic_bzip2_compressor, 1)
259 
260 typedef basic_bzip2_compressor<> bzip2_compressor;
261 
262 //
263 // Template name: bzip2_decompressor
264 // Description: Model of InputFilter and OutputFilter implementing
265 //      decompression using libbzip2.
266 //
267 template<typename Alloc = std::allocator<char> >
268 struct basic_bzip2_decompressor
269     : symmetric_filter<detail::bzip2_decompressor_impl<Alloc>, Alloc>
270 {
271 private:
272     typedef detail::bzip2_decompressor_impl<Alloc>      impl_type;
273     typedef symmetric_filter<impl_type, Alloc>  base_type;
274 public:
275     typedef typename base_type::char_type               char_type;
276     typedef typename base_type::category                category;
277     basic_bzip2_decompressor( bool small = bzip2::default_small,
278                               std::streamsize buffer_size = default_device_buffer_size );
279 };
280 BOOST_IOSTREAMS_PIPABLE(basic_bzip2_decompressor, 1)
281 
282 typedef basic_bzip2_decompressor<> bzip2_decompressor;
283 
284 //----------------------------------------------------------------------------//
285 
286 //------------------Implementation of bzip2_allocator-------------------------//
287 
288 namespace detail {
289 
290 template<typename Alloc, typename Base>
allocate(void * self,int items,int size)291 void* bzip2_allocator<Alloc, Base>::allocate(void* self, int items, int size)
292 {
293     size_type len = items * size;
294     char* ptr =
295         static_cast<allocator_type*>(self)->allocate
296             (len + sizeof(size_type)
297             #if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1)
298                 , (char*)0
299             #endif
300             );
301     *reinterpret_cast<size_type*>(ptr) = len;
302     return ptr + sizeof(size_type);
303 }
304 
305 template<typename Alloc, typename Base>
deallocate(void * self,void * address)306 void bzip2_allocator<Alloc, Base>::deallocate(void* self, void* address)
307 {
308     char* ptr = reinterpret_cast<char*>(address) - sizeof(size_type);
309     size_type len = *reinterpret_cast<size_type*>(ptr) + sizeof(size_type);
310     static_cast<allocator_type*>(self)->deallocate(ptr, len);
311 }
312 
313 //------------------Implementation of bzip2_compressor_impl-------------------//
314 
315 template<typename Alloc>
bzip2_compressor_impl(const bzip2_params & p)316 bzip2_compressor_impl<Alloc>::bzip2_compressor_impl(const bzip2_params& p)
317     : bzip2_base(p), eof_(false) { }
318 
319 template<typename Alloc>
~bzip2_compressor_impl()320 bzip2_compressor_impl<Alloc>::~bzip2_compressor_impl()
321 { (void) bzip2_base::end(true, std::nothrow); }
322 
323 template<typename Alloc>
filter(const char * & src_begin,const char * src_end,char * & dest_begin,char * dest_end,bool flush)324 bool bzip2_compressor_impl<Alloc>::filter
325     ( const char*& src_begin, const char* src_end,
326       char*& dest_begin, char* dest_end, bool flush )
327 {
328     if (!ready()) init();
329     if (eof_) return false;
330     before(src_begin, src_end, dest_begin, dest_end);
331     int result = compress(flush ? bzip2::finish : bzip2::run);
332     after(src_begin, dest_begin);
333     bzip2_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(result);
334     return !(eof_ = result == bzip2::stream_end);
335 }
336 
337 template<typename Alloc>
close()338 void bzip2_compressor_impl<Alloc>::close()
339 {
340     try {
341         end(true);
342     } catch (...) {
343         eof_ = false;
344         throw;
345     }
346     eof_ = false;
347 }
348 
349 template<typename Alloc>
init()350 inline void bzip2_compressor_impl<Alloc>::init()
351 { bzip2_base::init(true, static_cast<bzip2_allocator<Alloc>&>(*this)); }
352 
353 //------------------Implementation of bzip2_decompressor_impl-----------------//
354 
355 template<typename Alloc>
bzip2_decompressor_impl(bool small)356 bzip2_decompressor_impl<Alloc>::bzip2_decompressor_impl(bool small)
357     : bzip2_base(bzip2_params(small)), eof_(false) { }
358 
359 template<typename Alloc>
~bzip2_decompressor_impl()360 bzip2_decompressor_impl<Alloc>::~bzip2_decompressor_impl()
361 { (void) bzip2_base::end(false, std::nothrow); }
362 
363 template<typename Alloc>
filter(const char * & src_begin,const char * src_end,char * & dest_begin,char * dest_end,bool flush)364 bool bzip2_decompressor_impl<Alloc>::filter
365     ( const char*& src_begin, const char* src_end,
366       char*& dest_begin, char* dest_end, bool flush )
367 {
368     do {
369         if (eof_) {
370             // reset the stream if there are more characters
371             if(src_begin == src_end)
372                 return false;
373             else
374                 close();
375         }
376         if (!ready())
377             init();
378         before(src_begin, src_end, dest_begin, dest_end);
379         int result = decompress();
380         if(result == bzip2::ok && flush)
381             result = check_end(src_begin, dest_begin);
382         after(src_begin, dest_begin);
383         bzip2_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(result);
384         eof_ = result == bzip2::stream_end;
385     } while (eof_ && src_begin != src_end && dest_begin != dest_end);
386     return true;
387 }
388 
389 template<typename Alloc>
close()390 void bzip2_decompressor_impl<Alloc>::close()
391 {
392     try {
393         end(false);
394     } catch (...) {
395         eof_ = false;
396         throw;
397     }
398     eof_ = false;
399 }
400 
401 template<typename Alloc>
init()402 inline void bzip2_decompressor_impl<Alloc>::init()
403 { bzip2_base::init(false, static_cast<bzip2_allocator<Alloc>&>(*this)); }
404 } // End namespace detail.
405 
406 //------------------Implementation of bzip2_decompressor----------------------//
407 
408 template<typename Alloc>
basic_bzip2_compressor(const bzip2_params & p,std::streamsize buffer_size)409 basic_bzip2_compressor<Alloc>::basic_bzip2_compressor
410         (const bzip2_params& p, std::streamsize buffer_size)
411     : base_type(buffer_size, p)
412     { }
413 
414 //------------------Implementation of bzip2_decompressor----------------------//
415 
416 template<typename Alloc>
basic_bzip2_decompressor(bool small,std::streamsize buffer_size)417 basic_bzip2_decompressor<Alloc>::basic_bzip2_decompressor
418         (bool small, std::streamsize buffer_size)
419     : base_type(buffer_size, small)
420     { }
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_BZIP2_HPP_INCLUDED
432