zlib.hpp 15 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_ZLIB_HPP_INCLUDED
  9. #define BOOST_IOSTREAMS_ZLIB_HPP_INCLUDED
  10. #if defined(_MSC_VER)
  11. # pragma once
  12. #endif
  13. #include <cassert>
  14. #include <iosfwd> // streamsize.
  15. #include <memory> // allocator, bad_alloc.
  16. #include <new>
  17. #include <boost/config.hpp> // MSVC, STATIC_CONSTANT, DEDUCED_TYPENAME, DINKUM.
  18. #include <boost/cstdint.hpp> // uint*_t
  19. #include <boost/detail/workaround.hpp>
  20. #include <boost/iostreams/constants.hpp> // buffer size.
  21. #include <boost/iostreams/detail/config/auto_link.hpp>
  22. #include <boost/iostreams/detail/config/dyn_link.hpp>
  23. #include <boost/iostreams/detail/config/wide_streams.hpp>
  24. #include <boost/iostreams/detail/config/zlib.hpp>
  25. #include <boost/iostreams/detail/ios.hpp> // failure, streamsize.
  26. #include <boost/iostreams/filter/symmetric.hpp>
  27. #include <boost/iostreams/pipeline.hpp>
  28. #include <boost/type_traits/is_same.hpp>
  29. // Must come last.
  30. #ifdef BOOST_MSVC
  31. # pragma warning(push)
  32. # pragma warning(disable:4251 4275 4231 4660) // Dependencies not exported.
  33. #endif
  34. #include <boost/config/abi_prefix.hpp>
  35. namespace boost { namespace iostreams {
  36. namespace zlib {
  37. // Typedefs
  38. typedef uint32_t uint;
  39. typedef uint8_t byte;
  40. typedef uint32_t ulong;
  41. // Prefix 'x' prevents symbols from being redefined when Z_PREFIX is defined
  42. typedef void* (*xalloc_func)(void*, zlib::uint, zlib::uint);
  43. typedef void (*xfree_func)(void*, void*);
  44. // Compression levels
  45. BOOST_IOSTREAMS_DECL extern const int no_compression;
  46. BOOST_IOSTREAMS_DECL extern const int best_speed;
  47. BOOST_IOSTREAMS_DECL extern const int best_compression;
  48. BOOST_IOSTREAMS_DECL extern const int default_compression;
  49. // Compression methods
  50. BOOST_IOSTREAMS_DECL extern const int deflated;
  51. // Compression strategies
  52. BOOST_IOSTREAMS_DECL extern const int default_strategy;
  53. BOOST_IOSTREAMS_DECL extern const int filtered;
  54. BOOST_IOSTREAMS_DECL extern const int huffman_only;
  55. // Status codes
  56. BOOST_IOSTREAMS_DECL extern const int okay;
  57. BOOST_IOSTREAMS_DECL extern const int stream_end;
  58. BOOST_IOSTREAMS_DECL extern const int stream_error;
  59. BOOST_IOSTREAMS_DECL extern const int version_error;
  60. BOOST_IOSTREAMS_DECL extern const int data_error;
  61. BOOST_IOSTREAMS_DECL extern const int mem_error;
  62. BOOST_IOSTREAMS_DECL extern const int buf_error;
  63. // Flush codes
  64. BOOST_IOSTREAMS_DECL extern const int finish;
  65. BOOST_IOSTREAMS_DECL extern const int no_flush;
  66. BOOST_IOSTREAMS_DECL extern const int sync_flush;
  67. // Code for current OS
  68. //BOOST_IOSTREAMS_DECL extern const int os_code;
  69. // Null pointer constant.
  70. const int null = 0;
  71. // Default values
  72. const int default_window_bits = 15;
  73. const int default_mem_level = 8;
  74. const bool default_crc = false;
  75. const bool default_noheader = false;
  76. } // End namespace zlib.
  77. //
  78. // Class name: zlib_params.
  79. // Description: Encapsulates the parameters passed to deflateInit2
  80. // and inflateInit2 to customize compression and decompression.
  81. //
  82. struct zlib_params {
  83. // Non-explicit constructor.
  84. zlib_params( int level_ = zlib::default_compression,
  85. int method_ = zlib::deflated,
  86. int window_bits_ = zlib::default_window_bits,
  87. int mem_level_ = zlib::default_mem_level,
  88. int strategy_ = zlib::default_strategy,
  89. bool noheader_ = zlib::default_noheader,
  90. bool calculate_crc_ = zlib::default_crc )
  91. : level(level_), method(method_), window_bits(window_bits_),
  92. mem_level(mem_level_), strategy(strategy_),
  93. noheader(noheader_), calculate_crc(calculate_crc_)
  94. { }
  95. int level;
  96. int method;
  97. int window_bits;
  98. int mem_level;
  99. int strategy;
  100. bool noheader;
  101. bool calculate_crc;
  102. };
  103. //
  104. // Class name: zlib_error.
  105. // Description: Subclass of std::ios::failure thrown to indicate
  106. // zlib errors other than out-of-memory conditions.
  107. //
  108. class BOOST_IOSTREAMS_DECL zlib_error : public BOOST_IOSTREAMS_FAILURE {
  109. public:
  110. explicit zlib_error(int error);
  111. int error() const { return error_; }
  112. static void check BOOST_PREVENT_MACRO_SUBSTITUTION(int error);
  113. private:
  114. int error_;
  115. };
  116. namespace detail {
  117. template<typename Alloc>
  118. struct zlib_allocator_traits {
  119. #ifndef BOOST_NO_STD_ALLOCATOR
  120. #if defined(BOOST_NO_CXX11_ALLOCATOR)
  121. typedef typename Alloc::template rebind<char>::other type;
  122. #else
  123. typedef typename std::allocator_traits<Alloc>::template rebind_alloc<char> type;
  124. #endif
  125. #else
  126. typedef std::allocator<char> type;
  127. #endif
  128. };
  129. template< typename Alloc,
  130. typename Base = // VC6 workaround (C2516)
  131. BOOST_DEDUCED_TYPENAME zlib_allocator_traits<Alloc>::type >
  132. struct zlib_allocator : private Base {
  133. private:
  134. #if defined(BOOST_NO_CXX11_ALLOCATOR) || defined(BOOST_NO_STD_ALLOCATOR)
  135. typedef typename Base::size_type size_type;
  136. #else
  137. typedef typename std::allocator_traits<Base>::size_type size_type;
  138. #endif
  139. public:
  140. BOOST_STATIC_CONSTANT(bool, custom =
  141. (!is_same<std::allocator<char>, Base>::value));
  142. typedef typename zlib_allocator_traits<Alloc>::type allocator_type;
  143. static void* allocate(void* self, zlib::uint items, zlib::uint size);
  144. static void deallocate(void* self, void* address);
  145. };
  146. class BOOST_IOSTREAMS_DECL zlib_base {
  147. public:
  148. typedef char char_type;
  149. protected:
  150. zlib_base();
  151. ~zlib_base();
  152. void* stream() { return stream_; }
  153. template<typename Alloc>
  154. void init( const zlib_params& p,
  155. bool compress,
  156. zlib_allocator<Alloc>& zalloc )
  157. {
  158. bool custom = zlib_allocator<Alloc>::custom;
  159. do_init( p, compress,
  160. custom ? zlib_allocator<Alloc>::allocate : 0,
  161. custom ? zlib_allocator<Alloc>::deallocate : 0,
  162. &zalloc );
  163. }
  164. void before( const char*& src_begin, const char* src_end,
  165. char*& dest_begin, char* dest_end );
  166. void after( const char*& src_begin, char*& dest_begin,
  167. bool compress );
  168. int xdeflate(int flush); // Prefix 'x' prevents symbols from being
  169. int xinflate(int flush); // redefined when Z_PREFIX is defined
  170. void reset(bool compress, bool realloc);
  171. public:
  172. zlib::ulong crc() const { return crc_; }
  173. int total_in() const { return total_in_; }
  174. int total_out() const { return total_out_; }
  175. private:
  176. void do_init( const zlib_params& p, bool compress,
  177. zlib::xalloc_func,
  178. zlib::xfree_func,
  179. void* derived );
  180. void* stream_; // Actual type: z_stream*.
  181. bool calculate_crc_;
  182. zlib::ulong crc_;
  183. zlib::ulong crc_imp_;
  184. int total_in_;
  185. int total_out_;
  186. };
  187. //
  188. // Template name: zlib_compressor_impl
  189. // Description: Model of C-Style Filte implementing compression by
  190. // delegating to the zlib function deflate.
  191. //
  192. template<typename Alloc = std::allocator<char> >
  193. class zlib_compressor_impl : public zlib_base, public zlib_allocator<Alloc> {
  194. public:
  195. zlib_compressor_impl(const zlib_params& = zlib::default_compression);
  196. ~zlib_compressor_impl();
  197. bool filter( const char*& src_begin, const char* src_end,
  198. char*& dest_begin, char* dest_end, bool flush );
  199. void close();
  200. };
  201. //
  202. // Template name: zlib_compressor
  203. // Description: Model of C-Style Filte implementing decompression by
  204. // delegating to the zlib function inflate.
  205. //
  206. template<typename Alloc = std::allocator<char> >
  207. class zlib_decompressor_impl : public zlib_base, public zlib_allocator<Alloc> {
  208. public:
  209. zlib_decompressor_impl(const zlib_params&);
  210. zlib_decompressor_impl(int window_bits = zlib::default_window_bits);
  211. ~zlib_decompressor_impl();
  212. bool filter( const char*& begin_in, const char* end_in,
  213. char*& begin_out, char* end_out, bool flush );
  214. void close();
  215. bool eof() const { return eof_; }
  216. private:
  217. bool eof_;
  218. };
  219. } // End namespace detail.
  220. //
  221. // Template name: zlib_compressor
  222. // Description: Model of InputFilter and OutputFilter implementing
  223. // compression using zlib.
  224. //
  225. template<typename Alloc = std::allocator<char> >
  226. struct basic_zlib_compressor
  227. : symmetric_filter<detail::zlib_compressor_impl<Alloc>, Alloc>
  228. {
  229. private:
  230. typedef detail::zlib_compressor_impl<Alloc> impl_type;
  231. typedef symmetric_filter<impl_type, Alloc> base_type;
  232. public:
  233. typedef typename base_type::char_type char_type;
  234. typedef typename base_type::category category;
  235. basic_zlib_compressor( const zlib_params& = zlib::default_compression,
  236. std::streamsize buffer_size = default_device_buffer_size );
  237. zlib::ulong crc() { return this->filter().crc(); }
  238. int total_in() { return this->filter().total_in(); }
  239. };
  240. BOOST_IOSTREAMS_PIPABLE(basic_zlib_compressor, 1)
  241. typedef basic_zlib_compressor<> zlib_compressor;
  242. //
  243. // Template name: zlib_decompressor
  244. // Description: Model of InputFilter and OutputFilter implementing
  245. // decompression using zlib.
  246. //
  247. template<typename Alloc = std::allocator<char> >
  248. struct basic_zlib_decompressor
  249. : symmetric_filter<detail::zlib_decompressor_impl<Alloc>, Alloc>
  250. {
  251. private:
  252. typedef detail::zlib_decompressor_impl<Alloc> impl_type;
  253. typedef symmetric_filter<impl_type, Alloc> base_type;
  254. public:
  255. typedef typename base_type::char_type char_type;
  256. typedef typename base_type::category category;
  257. basic_zlib_decompressor( int window_bits = zlib::default_window_bits,
  258. std::streamsize buffer_size = default_device_buffer_size );
  259. basic_zlib_decompressor( const zlib_params& p,
  260. std::streamsize buffer_size = default_device_buffer_size );
  261. zlib::ulong crc() { return this->filter().crc(); }
  262. int total_out() { return this->filter().total_out(); }
  263. bool eof() { return this->filter().eof(); }
  264. };
  265. BOOST_IOSTREAMS_PIPABLE(basic_zlib_decompressor, 1)
  266. typedef basic_zlib_decompressor<> zlib_decompressor;
  267. //----------------------------------------------------------------------------//
  268. //------------------Implementation of zlib_allocator--------------------------//
  269. namespace detail {
  270. template<typename Alloc, typename Base>
  271. void* zlib_allocator<Alloc, Base>::allocate
  272. (void* self, zlib::uint items, zlib::uint size)
  273. {
  274. size_type len = items * size;
  275. char* ptr =
  276. static_cast<allocator_type*>(self)->allocate
  277. (len + sizeof(size_type)
  278. #if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1)
  279. , (char*)0
  280. #endif
  281. );
  282. *reinterpret_cast<size_type*>(ptr) = len;
  283. return ptr + sizeof(size_type);
  284. }
  285. template<typename Alloc, typename Base>
  286. void zlib_allocator<Alloc, Base>::deallocate(void* self, void* address)
  287. {
  288. char* ptr = reinterpret_cast<char*>(address) - sizeof(size_type);
  289. size_type len = *reinterpret_cast<size_type*>(ptr) + sizeof(size_type);
  290. static_cast<allocator_type*>(self)->deallocate(ptr, len);
  291. }
  292. //------------------Implementation of zlib_compressor_impl--------------------//
  293. template<typename Alloc>
  294. zlib_compressor_impl<Alloc>::zlib_compressor_impl(const zlib_params& p)
  295. { init(p, true, static_cast<zlib_allocator<Alloc>&>(*this)); }
  296. template<typename Alloc>
  297. zlib_compressor_impl<Alloc>::~zlib_compressor_impl()
  298. { reset(true, false); }
  299. template<typename Alloc>
  300. bool zlib_compressor_impl<Alloc>::filter
  301. ( const char*& src_begin, const char* src_end,
  302. char*& dest_begin, char* dest_end, bool flush )
  303. {
  304. before(src_begin, src_end, dest_begin, dest_end);
  305. int result = xdeflate(flush ? zlib::finish : zlib::no_flush);
  306. after(src_begin, dest_begin, true);
  307. zlib_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(result);
  308. return result != zlib::stream_end;
  309. }
  310. template<typename Alloc>
  311. void zlib_compressor_impl<Alloc>::close() { reset(true, true); }
  312. //------------------Implementation of zlib_decompressor_impl------------------//
  313. template<typename Alloc>
  314. zlib_decompressor_impl<Alloc>::zlib_decompressor_impl(const zlib_params& p)
  315. : eof_(false)
  316. { init(p, false, static_cast<zlib_allocator<Alloc>&>(*this)); }
  317. template<typename Alloc>
  318. zlib_decompressor_impl<Alloc>::~zlib_decompressor_impl()
  319. { reset(false, false); }
  320. template<typename Alloc>
  321. zlib_decompressor_impl<Alloc>::zlib_decompressor_impl(int window_bits)
  322. {
  323. zlib_params p;
  324. p.window_bits = window_bits;
  325. init(p, false, static_cast<zlib_allocator<Alloc>&>(*this));
  326. }
  327. template<typename Alloc>
  328. bool zlib_decompressor_impl<Alloc>::filter
  329. ( const char*& src_begin, const char* src_end,
  330. char*& dest_begin, char* dest_end, bool /* flush */ )
  331. {
  332. before(src_begin, src_end, dest_begin, dest_end);
  333. int result = xinflate(zlib::sync_flush);
  334. after(src_begin, dest_begin, false);
  335. zlib_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(result);
  336. return !(eof_ = result == zlib::stream_end);
  337. }
  338. template<typename Alloc>
  339. void zlib_decompressor_impl<Alloc>::close() {
  340. eof_ = false;
  341. reset(false, true);
  342. }
  343. } // End namespace detail.
  344. //------------------Implementation of zlib_decompressor-----------------------//
  345. template<typename Alloc>
  346. basic_zlib_compressor<Alloc>::basic_zlib_compressor
  347. (const zlib_params& p, std::streamsize buffer_size)
  348. : base_type(buffer_size, p) { }
  349. //------------------Implementation of zlib_decompressor-----------------------//
  350. template<typename Alloc>
  351. basic_zlib_decompressor<Alloc>::basic_zlib_decompressor
  352. (int window_bits, std::streamsize buffer_size)
  353. : base_type(buffer_size, window_bits) { }
  354. template<typename Alloc>
  355. basic_zlib_decompressor<Alloc>::basic_zlib_decompressor
  356. (const zlib_params& p, std::streamsize buffer_size)
  357. : base_type(buffer_size, p) { }
  358. //----------------------------------------------------------------------------//
  359. } } // End namespaces iostreams, boost.
  360. #include <boost/config/abi_suffix.hpp> // Pops abi_suffix.hpp pragmas.
  361. #ifdef BOOST_MSVC
  362. # pragma warning(pop)
  363. #endif
  364. #endif // #ifndef BOOST_IOSTREAMS_ZLIB_HPP_INCLUDED