device.hpp 16 KB

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