bzip2.hpp 14 KB

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