device.hpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  1. /*
  2. Copyright 2007-2012 Andreas Pokorny, Christian Henning
  3. Use, modification and distribution are subject to the Boost Software License,
  4. Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  5. http://www.boost.org/LICENSE_1_0.txt).
  6. */
  7. /*************************************************************************************************/
  8. #ifndef BOOST_GIL_IO_DEVICE_HPP
  9. #define BOOST_GIL_IO_DEVICE_HPP
  10. ////////////////////////////////////////////////////////////////////////////////////////
  11. /// \file
  12. /// \brief
  13. /// \author Andreas Pokorny, Christian Henning \n
  14. ///
  15. /// \date 2007-2012 \n
  16. ///
  17. ////////////////////////////////////////////////////////////////////////////////////////
  18. #include <cstdio>
  19. #include <boost/utility/enable_if.hpp>
  20. #include <boost/gil/io/base.hpp>
  21. #include <memory>
  22. namespace boost { namespace gil {
  23. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  24. #pragma warning(push)
  25. #pragma warning(disable:4512) //assignment operator could not be generated
  26. #endif
  27. namespace detail {
  28. template < typename T > struct buff_item
  29. {
  30. static const unsigned int size = sizeof( T );
  31. };
  32. template <> struct buff_item< void >
  33. {
  34. static const unsigned int size = 1;
  35. };
  36. /*!
  37. * Implements the IODevice concept c.f. to \ref IODevice required by Image libraries like
  38. * libjpeg and libpng.
  39. *
  40. * \todo switch to a sane interface as soon as there is
  41. * something good in boost. I.E. the IOChains library
  42. * would fit very well here.
  43. *
  44. * This implementation is based on FILE*.
  45. */
  46. template< typename FormatTag >
  47. class file_stream_device
  48. {
  49. public:
  50. typedef FormatTag format_tag_t;
  51. public:
  52. /// Used to overload the constructor.
  53. struct read_tag {};
  54. struct write_tag {};
  55. ///
  56. /// Constructor
  57. ///
  58. file_stream_device( const std::string& file_name
  59. , read_tag = read_tag()
  60. )
  61. {
  62. FILE* file = NULL;
  63. io_error_if( ( file = fopen( file_name.c_str(), "rb" )) == NULL
  64. , "file_stream_device: failed to open file"
  65. );
  66. _file = file_ptr_t( file
  67. , file_deleter
  68. );
  69. }
  70. ///
  71. /// Constructor
  72. ///
  73. file_stream_device( const char* file_name
  74. , read_tag = read_tag()
  75. )
  76. {
  77. FILE* file = NULL;
  78. io_error_if( ( file = fopen( file_name, "rb" )) == NULL
  79. , "file_stream_device: failed to open file"
  80. );
  81. _file = file_ptr_t( file
  82. , file_deleter
  83. );
  84. }
  85. ///
  86. /// Constructor
  87. ///
  88. file_stream_device( const std::string& file_name
  89. , write_tag
  90. )
  91. {
  92. FILE* file = NULL;
  93. io_error_if( ( file = fopen( file_name.c_str(), "wb" )) == NULL
  94. , "file_stream_device: failed to open file"
  95. );
  96. _file = file_ptr_t( file
  97. , file_deleter
  98. );
  99. }
  100. ///
  101. /// Constructor
  102. ///
  103. file_stream_device( const char* file_name
  104. , write_tag
  105. )
  106. {
  107. FILE* file = NULL;
  108. io_error_if( ( file = fopen( file_name, "wb" )) == NULL
  109. , "file_stream_device: failed to open file"
  110. );
  111. _file = file_ptr_t( file
  112. , file_deleter
  113. );
  114. }
  115. ///
  116. /// Constructor
  117. ///
  118. file_stream_device( FILE* file )
  119. : _file( file
  120. , file_deleter
  121. )
  122. {}
  123. FILE* get() { return _file.get(); }
  124. const FILE* get() const { return _file.get(); }
  125. int getc_unchecked()
  126. {
  127. return std::getc( get() );
  128. }
  129. char getc()
  130. {
  131. int ch;
  132. if(( ch = std::getc( get() )) == EOF )
  133. io_error( "file_stream_device: unexpected EOF" );
  134. return ( char ) ch;
  135. }
  136. ///@todo: change byte_t* to void*
  137. std::size_t read( byte_t* data
  138. , std::size_t count
  139. )
  140. {
  141. std::size_t num_elements = fread( data
  142. , 1
  143. , static_cast<int>( count )
  144. , get()
  145. );
  146. ///@todo: add compiler symbol to turn error checking on and off.
  147. if(ferror( get() ))
  148. {
  149. assert( false );
  150. }
  151. //libjpeg sometimes reads blocks in 4096 bytes even when the file is smaller than that.
  152. //assert( num_elements == count );
  153. assert( num_elements > 0 );
  154. return num_elements;
  155. }
  156. /// Reads array
  157. template< typename T
  158. , int N
  159. >
  160. std::size_t read( T (&buf)[N] )
  161. {
  162. return read( buf, N );
  163. }
  164. /// Reads byte
  165. uint8_t read_uint8() throw()
  166. {
  167. byte_t m[1];
  168. read( m );
  169. return m[0];
  170. }
  171. /// Reads 16 bit little endian integer
  172. uint16_t read_uint16() throw()
  173. {
  174. byte_t m[2];
  175. read( m );
  176. return (m[1] << 8) | m[0];
  177. }
  178. /// Reads 32 bit little endian integer
  179. uint32_t read_uint32() throw()
  180. {
  181. byte_t m[4];
  182. read( m );
  183. return (m[3] << 24) | (m[2] << 16) | (m[1] << 8) | m[0];
  184. }
  185. /// Writes number of elements from a buffer
  186. template < typename T >
  187. std::size_t write( const T* buf
  188. , std::size_t count
  189. )
  190. throw()
  191. {
  192. std::size_t num_elements = fwrite( buf
  193. , buff_item<T>::size
  194. , count
  195. , get()
  196. );
  197. assert( num_elements == count );
  198. return num_elements;
  199. }
  200. /// Writes array
  201. template < typename T
  202. , std::size_t N
  203. >
  204. std::size_t write( const T (&buf)[N] ) throw()
  205. {
  206. return write( buf, N );
  207. }
  208. /// Writes byte
  209. void write_uint8( uint8_t x ) throw()
  210. {
  211. byte_t m[1] = { x };
  212. write(m);
  213. }
  214. /// Writes 16 bit little endian integer
  215. void write_uint16( uint16_t x ) throw()
  216. {
  217. byte_t m[2];
  218. m[0] = byte_t( x >> 0 );
  219. m[1] = byte_t( x >> 8 );
  220. write( m );
  221. }
  222. /// Writes 32 bit little endian integer
  223. void write_uint32( uint32_t x ) throw()
  224. {
  225. byte_t m[4];
  226. m[0] = byte_t( x >> 0 );
  227. m[1] = byte_t( x >> 8 );
  228. m[2] = byte_t( x >> 16 );
  229. m[3] = byte_t( x >> 24 );
  230. write( m );
  231. }
  232. void seek( long count, int whence = SEEK_SET )
  233. {
  234. io_error_if( fseek( get()
  235. , count
  236. , whence
  237. ) != 0
  238. , "file read error"
  239. );
  240. }
  241. long int tell()
  242. {
  243. long int pos = ftell( get() );
  244. io_error_if( pos == -1L
  245. , "file read error"
  246. );
  247. return pos;
  248. }
  249. void flush()
  250. {
  251. fflush( get() );
  252. }
  253. /// Prints formatted ASCII text
  254. void print_line( const std::string& line )
  255. {
  256. std::size_t num_elements = fwrite( line.c_str()
  257. , sizeof( char )
  258. , line.size()
  259. , get()
  260. );
  261. assert( num_elements == line.size() );
  262. }
  263. int error()
  264. {
  265. return ferror( get() );
  266. }
  267. private:
  268. static void file_deleter( FILE* file )
  269. {
  270. if( file )
  271. {
  272. fclose( file );
  273. }
  274. }
  275. private:
  276. using file_ptr_t = std::shared_ptr<FILE> ;
  277. file_ptr_t _file;
  278. };
  279. /**
  280. * Input stream device
  281. */
  282. template< typename FormatTag >
  283. class istream_device
  284. {
  285. public:
  286. istream_device( std::istream& in )
  287. : _in( in )
  288. {
  289. if (!in)
  290. {
  291. // does the file exists?
  292. io_error("Stream is not valid.");
  293. }
  294. }
  295. int getc_unchecked()
  296. {
  297. return _in.get();
  298. }
  299. char getc()
  300. {
  301. int ch;
  302. if(( ch = _in.get() ) == EOF )
  303. io_error( "file_stream_device: unexpected EOF" );
  304. return ( char ) ch;
  305. }
  306. std::size_t read( byte_t* data
  307. , std::size_t count )
  308. {
  309. std::streamsize cr = 0;
  310. do
  311. {
  312. _in.peek();
  313. std::streamsize c = _in.readsome( reinterpret_cast< char* >( data )
  314. , static_cast< std::streamsize >( count ));
  315. count -= static_cast< std::size_t >( c );
  316. data += c;
  317. cr += c;
  318. } while( count && _in );
  319. return static_cast< std::size_t >( cr );
  320. }
  321. /// Reads array
  322. template< typename T
  323. , int N
  324. >
  325. size_t read( T (&buf)[N] )
  326. {
  327. return read( buf, N );
  328. }
  329. /// Reads byte
  330. uint8_t read_uint8() throw()
  331. {
  332. byte_t m[1];
  333. read( m );
  334. return m[0];
  335. }
  336. /// Reads 16 bit little endian integer
  337. uint16_t read_uint16() throw()
  338. {
  339. byte_t m[2];
  340. read( m );
  341. return (m[1] << 8) | m[0];
  342. }
  343. /// Reads 32 bit little endian integer
  344. uint32_t read_uint32() throw()
  345. {
  346. byte_t m[4];
  347. read( m );
  348. return (m[3] << 24) | (m[2] << 16) | (m[1] << 8) | m[0];
  349. }
  350. void seek( long count, int whence = SEEK_SET )
  351. {
  352. _in.seekg( count
  353. , whence == SEEK_SET ? std::ios::beg
  354. :( whence == SEEK_CUR ? std::ios::cur
  355. : std::ios::end )
  356. );
  357. }
  358. void write(const byte_t*, std::size_t)
  359. {
  360. io_error( "Bad io error." );
  361. }
  362. void flush() {}
  363. private:
  364. std::istream& _in;
  365. };
  366. /**
  367. * Output stream device
  368. */
  369. template< typename FormatTag >
  370. class ostream_device
  371. {
  372. public:
  373. ostream_device( std::ostream & out )
  374. : _out( out )
  375. {
  376. }
  377. std::size_t read(byte_t *, std::size_t)
  378. {
  379. io_error( "Bad io error." );
  380. return 0;
  381. }
  382. void seek( long count, int whence )
  383. {
  384. _out.seekp( count
  385. , whence == SEEK_SET
  386. ? std::ios::beg
  387. : ( whence == SEEK_CUR
  388. ?std::ios::cur
  389. :std::ios::end )
  390. );
  391. }
  392. void write( const byte_t* data
  393. , std::size_t count )
  394. {
  395. _out.write( reinterpret_cast<char const*>( data )
  396. , static_cast<std::streamsize>( count )
  397. );
  398. }
  399. /// Writes array
  400. template < typename T
  401. , std::size_t N
  402. >
  403. void write( const T (&buf)[N] ) throw()
  404. {
  405. write( buf, N );
  406. }
  407. /// Writes byte
  408. void write_uint8( uint8_t x ) throw()
  409. {
  410. byte_t m[1] = { x };
  411. write(m);
  412. }
  413. /// Writes 16 bit little endian integer
  414. void write_uint16( uint16_t x ) throw()
  415. {
  416. byte_t m[2];
  417. m[0] = byte_t( x >> 0 );
  418. m[1] = byte_t( x >> 8 );
  419. write( m );
  420. }
  421. /// Writes 32 bit little endian integer
  422. void write_uint32( uint32_t x ) throw()
  423. {
  424. byte_t m[4];
  425. m[0] = byte_t( x >> 0 );
  426. m[1] = byte_t( x >> 8 );
  427. m[2] = byte_t( x >> 16 );
  428. m[3] = byte_t( x >> 24 );
  429. write( m );
  430. }
  431. void flush()
  432. {
  433. _out << std::flush;
  434. }
  435. /// Prints formatted ASCII text
  436. void print_line( const std::string& line )
  437. {
  438. _out << line;
  439. }
  440. private:
  441. std::ostream& _out;
  442. };
  443. /**
  444. * Metafunction to detect input devices.
  445. * Should be replaced by an external facility in the future.
  446. */
  447. template< typename IODevice > struct is_input_device : mpl::false_{};
  448. template< typename FormatTag > struct is_input_device< file_stream_device< FormatTag > > : mpl::true_{};
  449. template< typename FormatTag > struct is_input_device< istream_device< FormatTag > > : mpl::true_{};
  450. template< typename FormatTag
  451. , typename T
  452. , typename D = void
  453. >
  454. struct is_adaptable_input_device : mpl::false_{};
  455. template< typename FormatTag
  456. , typename T
  457. >
  458. struct is_adaptable_input_device< FormatTag
  459. , T
  460. , typename enable_if< mpl::or_< is_base_and_derived< std::istream, T >
  461. , is_same < std::istream, T >
  462. >
  463. >::type
  464. > : mpl::true_
  465. {
  466. typedef istream_device< FormatTag > device_type;
  467. };
  468. template< typename FormatTag >
  469. struct is_adaptable_input_device< FormatTag
  470. , FILE*
  471. , void
  472. >
  473. : mpl::true_
  474. {
  475. typedef file_stream_device< FormatTag > device_type;
  476. };
  477. ///
  478. /// Metafunction to decide if a given type is an acceptable read device type.
  479. ///
  480. template< typename FormatTag
  481. , typename T
  482. , typename D = void
  483. >
  484. struct is_read_device : mpl::false_
  485. {};
  486. template< typename FormatTag
  487. , typename T
  488. >
  489. struct is_read_device< FormatTag
  490. , T
  491. , typename enable_if< mpl::or_< is_input_device< FormatTag >
  492. , is_adaptable_input_device< FormatTag
  493. , T
  494. >
  495. >
  496. >::type
  497. > : mpl::true_
  498. {};
  499. /**
  500. * Metafunction to detect output devices.
  501. * Should be replaced by an external facility in the future.
  502. */
  503. template<typename IODevice> struct is_output_device : mpl::false_{};
  504. template< typename FormatTag > struct is_output_device< file_stream_device< FormatTag > > : mpl::true_{};
  505. template< typename FormatTag > struct is_output_device< ostream_device < FormatTag > > : mpl::true_{};
  506. template< typename FormatTag
  507. , typename IODevice
  508. , typename D = void
  509. >
  510. struct is_adaptable_output_device : mpl::false_ {};
  511. template< typename FormatTag
  512. , typename T
  513. > struct is_adaptable_output_device< FormatTag
  514. , T
  515. , typename enable_if< mpl::or_< is_base_and_derived< std::ostream, T >
  516. , is_same < std::ostream, T >
  517. >
  518. >::type
  519. > : mpl::true_
  520. {
  521. typedef ostream_device< FormatTag > device_type;
  522. };
  523. template<typename FormatTag> struct is_adaptable_output_device<FormatTag,FILE*,void>
  524. : mpl::true_
  525. {
  526. typedef file_stream_device< FormatTag > device_type;
  527. };
  528. ///
  529. /// Metafunction to decide if a given type is an acceptable read device type.
  530. ///
  531. template< typename FormatTag
  532. , typename T
  533. , typename D = void
  534. >
  535. struct is_write_device : mpl::false_
  536. {};
  537. template< typename FormatTag
  538. , typename T
  539. >
  540. struct is_write_device< FormatTag
  541. , T
  542. , typename enable_if< mpl::or_< is_output_device< FormatTag >
  543. , is_adaptable_output_device< FormatTag
  544. , T
  545. >
  546. >
  547. >::type
  548. > : mpl::true_
  549. {};
  550. } // namespace detail
  551. template< typename Device, typename FormatTag > class scanline_reader;
  552. template< typename Device, typename FormatTag, typename ConversionPolicy > class reader;
  553. template< typename Device, typename FormatTag, typename Log = no_log > class writer;
  554. template< typename Device, typename FormatTag > class dynamic_image_reader;
  555. template< typename Device, typename FormatTag, typename Log = no_log > class dynamic_image_writer;
  556. namespace detail {
  557. template< typename T >
  558. struct is_reader : mpl::false_
  559. {};
  560. template< typename Device
  561. , typename FormatTag
  562. , typename ConversionPolicy
  563. >
  564. struct is_reader< reader< Device
  565. , FormatTag
  566. , ConversionPolicy
  567. >
  568. > : mpl::true_
  569. {};
  570. template< typename T >
  571. struct is_dynamic_image_reader : mpl::false_
  572. {};
  573. template< typename Device
  574. , typename FormatTag
  575. >
  576. struct is_dynamic_image_reader< dynamic_image_reader< Device
  577. , FormatTag
  578. >
  579. > : mpl::true_
  580. {};
  581. template< typename T >
  582. struct is_writer : mpl::false_
  583. {};
  584. template< typename Device
  585. , typename FormatTag
  586. >
  587. struct is_writer< writer< Device
  588. , FormatTag
  589. >
  590. > : mpl::true_
  591. {};
  592. template< typename T >
  593. struct is_dynamic_image_writer : mpl::false_
  594. {};
  595. template< typename Device
  596. , typename FormatTag
  597. >
  598. struct is_dynamic_image_writer< dynamic_image_writer< Device
  599. , FormatTag
  600. >
  601. > : mpl::true_
  602. {};
  603. } // namespace detail
  604. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  605. #pragma warning(pop)
  606. #endif
  607. } // namespace gil
  608. } // namespace boost
  609. #endif