Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/boost/gil/io/device.hpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 //
0002 // Copyright 2007-2012 Christian Henning, Andreas Pokorny
0003 // Copyright 2024 Dirk Stolle
0004 //
0005 // Distributed under the Boost Software License, Version 1.0
0006 // See accompanying file LICENSE_1_0.txt or copy at
0007 // http://www.boost.org/LICENSE_1_0.txt
0008 //
0009 #ifndef BOOST_GIL_IO_DEVICE_HPP
0010 #define BOOST_GIL_IO_DEVICE_HPP
0011 
0012 #include <boost/gil/detail/mp11.hpp>
0013 #include <boost/gil/io/base.hpp>
0014 
0015 #include <cstdio>
0016 #include <memory>
0017 #include <type_traits>
0018 
0019 namespace boost { namespace gil {
0020 
0021 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0022 #pragma warning(push)
0023 #pragma warning(disable:4512) //assignment operator could not be generated
0024 #endif
0025 
0026 namespace detail {
0027 
0028 template < typename T > struct buff_item
0029 {
0030     static const unsigned int size = sizeof( T );
0031 };
0032 
0033 template <> struct buff_item< void >
0034 {
0035     static const unsigned int size = 1;
0036 };
0037 
0038 /*!
0039  * Implements the IODevice concept c.f. to \ref IODevice required by Image libraries like
0040  * libjpeg and libpng.
0041  *
0042  * \todo switch to a sane interface as soon as there is
0043  * something good in boost. I.E. the IOChains library
0044  * would fit very well here.
0045  *
0046  * This implementation is based on FILE*.
0047  */
0048 template< typename FormatTag >
0049 class file_stream_device
0050 {
0051 public:
0052 
0053    using format_tag_t = FormatTag;
0054 
0055 public:
0056 
0057     /// Used to overload the constructor.
0058     struct read_tag {};
0059     struct write_tag {};
0060 
0061     ///
0062     /// Constructor
0063     ///
0064     file_stream_device( const std::string& file_name
0065                       , read_tag tag  = read_tag()
0066                       )
0067         : file_stream_device(file_name.c_str(), tag)
0068     {}
0069 
0070     ///
0071     /// Constructor
0072     ///
0073     file_stream_device( const char* file_name
0074                       , read_tag   = read_tag()
0075                       )
0076     {
0077         FILE* file = nullptr;
0078 
0079         io_error_if( ( file = fopen( file_name, "rb" )) == nullptr
0080                    , "file_stream_device: failed to open file for reading"
0081                    );
0082 
0083         _file = file_ptr_t( file
0084                           , file_deleter
0085                           );
0086     }
0087 
0088     ///
0089     /// Constructor
0090     ///
0091     file_stream_device( const std::string& file_name
0092                       , write_tag tag
0093                       )
0094         : file_stream_device(file_name.c_str(), tag)
0095     {}
0096 
0097     ///
0098     /// Constructor
0099     ///
0100     file_stream_device( const char* file_name
0101                       , write_tag
0102                       )
0103     {
0104         FILE* file = nullptr;
0105 
0106         io_error_if( ( file = fopen( file_name, "wb" )) == nullptr
0107                    , "file_stream_device: failed to open file for writing"
0108                    );
0109 
0110         _file = file_ptr_t( file
0111                           , file_deleter
0112                           );
0113     }
0114 
0115     ///
0116     /// Constructor
0117     ///
0118     file_stream_device( FILE* file )
0119     : _file( file
0120            , file_deleter
0121            )
0122     {}
0123 
0124     auto get() -> FILE* { return _file.get(); }
0125     auto get() const -> FILE const* { return _file.get(); }
0126 
0127     int getc_unchecked()
0128     {
0129         return std::getc( get() );
0130     }
0131 
0132     char getc()
0133     {
0134         int ch;
0135 
0136         io_error_if( ( ch = std::getc( get() )) == EOF
0137                    , "file_stream_device: unexpected EOF"
0138                    );
0139 
0140         return ( char ) ch;
0141     }
0142 
0143     ///@todo: change byte_t* to void*
0144     auto read(byte_t* data, std::size_t count) -> std::size_t
0145     {
0146         std::size_t num_elements = fread( data
0147                                         , 1
0148                                         , static_cast<int>( count )
0149                                         , get()
0150                                         );
0151 
0152         ///@todo: add compiler symbol to turn error checking on and off.
0153         io_error_if( ferror( get() )
0154                    , "file_stream_device: file read error"
0155                    );
0156 
0157         //libjpeg sometimes reads blocks in 4096 bytes even when the file is smaller than that.
0158         //return value indicates how much was actually read
0159         //returning less than "count" is not an error
0160         return num_elements;
0161     }
0162 
0163     /// Reads array
0164     template< typename T, int N>
0165     void read( T (&buf)[N] )
0166     {
0167         io_error_if( read( buf, N ) < N
0168                    , "file_stream_device: file read error"
0169                    );
0170     }
0171 
0172     /// Reads byte
0173     uint8_t read_uint8()
0174     {
0175         byte_t m[1];
0176 
0177         read( m );
0178         return m[0];
0179     }
0180 
0181     /// Reads 16 bit little endian integer
0182     uint16_t read_uint16()
0183     {
0184         byte_t m[2];
0185 
0186         read( m );
0187         return (m[1] << 8) | m[0];
0188     }
0189 
0190     /// Reads 32 bit little endian integer
0191     uint32_t read_uint32()
0192     {
0193         byte_t m[4];
0194 
0195         read( m );
0196         return (m[3] << 24) | (m[2] << 16) | (m[1] << 8) | m[0];
0197     }
0198 
0199     /// Writes number of elements from a buffer
0200     template < typename T >
0201     auto write(T const* buf, std::size_t count) -> std::size_t
0202     {
0203         std::size_t num_elements = fwrite( buf
0204                                          , buff_item<T>::size
0205                                          , count
0206                                          , get()
0207                                          );
0208 
0209         //return value indicates how much was actually written
0210         //returning less than "count" is not an error
0211         return num_elements;
0212     }
0213 
0214     /// Writes array
0215     template < typename    T
0216              , std::size_t N
0217              >
0218     void write( const T (&buf)[N] )
0219     {
0220         io_error_if( write( buf, N ) < N
0221                    , "file_stream_device: file write error"
0222                    );
0223         return ;
0224     }
0225 
0226     /// Writes byte
0227     void write_uint8( uint8_t x )
0228     {
0229         byte_t m[1] = { x };
0230         write(m);
0231     }
0232 
0233     /// Writes 16 bit little endian integer
0234     void write_uint16( uint16_t x )
0235     {
0236         byte_t m[2];
0237 
0238         m[0] = byte_t( x >> 0 );
0239         m[1] = byte_t( x >> 8 );
0240 
0241         write( m );
0242     }
0243 
0244     /// Writes 32 bit little endian integer
0245     void write_uint32( uint32_t x )
0246     {
0247         byte_t m[4];
0248 
0249         m[0] = byte_t( x >>  0 );
0250         m[1] = byte_t( x >>  8 );
0251         m[2] = byte_t( x >> 16 );
0252         m[3] = byte_t( x >> 24 );
0253 
0254         write( m );
0255     }
0256 
0257     void seek( long count, int whence = SEEK_SET )
0258     {
0259         io_error_if( fseek( get()
0260                           , count
0261                           , whence
0262                           ) != 0
0263                    , "file_stream_device: file seek error"
0264                    );
0265     }
0266 
0267     long int tell()
0268     {
0269         long int pos = ftell( get() );
0270 
0271         io_error_if( pos == -1L
0272                    , "file_stream_device: file position error"
0273                    );
0274 
0275         return pos;
0276     }
0277 
0278     void flush()
0279     {
0280         fflush( get() );
0281     }
0282 
0283     /// Prints formatted ASCII text
0284     void print_line( const std::string& line )
0285     {
0286         std::size_t num_elements = fwrite( line.c_str()
0287                                          , sizeof( char )
0288                                          , line.size()
0289                                          , get()
0290                                          );
0291 
0292         io_error_if( num_elements < line.size()
0293                    , "file_stream_device: line print error"
0294                    );
0295     }
0296 
0297     int error()
0298     {
0299         return ferror( get() );
0300     }
0301 
0302 private:
0303 
0304     static void file_deleter( FILE* file )
0305     {
0306         if( file )
0307         {
0308             fclose( file );
0309         }
0310     }
0311 
0312 private:
0313 
0314     using file_ptr_t = std::shared_ptr<FILE> ;
0315     file_ptr_t _file;
0316 };
0317 
0318 /**
0319  * Input stream device
0320  */
0321 template< typename FormatTag >
0322 class istream_device
0323 {
0324 public:
0325    istream_device( std::istream& in )
0326    : _in( in )
0327    {
0328        // does the file exists?
0329        io_error_if( !in
0330                   , "istream_device: Stream is not valid."
0331                   );
0332    }
0333 
0334     int getc_unchecked()
0335     {
0336         return _in.get();
0337     }
0338 
0339     char getc()
0340     {
0341         int ch;
0342 
0343         io_error_if( ( ch = _in.get() ) == EOF
0344                    , "istream_device: unexpected EOF"
0345                    );
0346 
0347         return ( char ) ch;
0348     }
0349 
0350     std::size_t read( byte_t*     data
0351                     , std::size_t count )
0352     {
0353         std::streamsize cr = 0;
0354 
0355         do
0356         {
0357             _in.peek();
0358             std::streamsize c = _in.readsome( reinterpret_cast< char* >( data )
0359                                             , static_cast< std::streamsize >( count ));
0360 
0361             count -= static_cast< std::size_t >( c );
0362             data += c;
0363             cr += c;
0364 
0365         } while( count && _in );
0366 
0367         return static_cast< std::size_t >( cr );
0368     }
0369 
0370     /// Reads array
0371     template<typename T, int N>
0372     void read(T (&buf)[N])
0373     {
0374         read(buf, N);
0375     }
0376 
0377     /// Reads byte
0378     uint8_t read_uint8()
0379     {
0380         byte_t m[1];
0381 
0382         read( m );
0383         return m[0];
0384     }
0385 
0386     /// Reads 16 bit little endian integer
0387     uint16_t read_uint16()
0388     {
0389         byte_t m[2];
0390 
0391         read( m );
0392         return (m[1] << 8) | m[0];
0393     }
0394 
0395     /// Reads 32 bit little endian integer
0396     uint32_t read_uint32()
0397     {
0398         byte_t m[4];
0399 
0400         read( m );
0401         return (m[3] << 24) | (m[2] << 16) | (m[1] << 8) | m[0];
0402     }
0403 
0404     void seek( long count, int whence = SEEK_SET )
0405     {
0406         _in.seekg( count
0407                  , whence == SEEK_SET ? std::ios::beg
0408                                       :( whence == SEEK_CUR ? std::ios::cur
0409                                                             : std::ios::end )
0410                  );
0411     }
0412 
0413     long int tell()
0414     {
0415         auto pos = _in.tellg();
0416 
0417         io_error_if( pos == std::istream::pos_type(-1)
0418                    , "istream_device: file position error"
0419                    );
0420 
0421         return static_cast<long int>(pos);
0422     }
0423 
0424     void write(const byte_t*, std::size_t)
0425     {
0426         io_error( "istream_device: Bad io error." );
0427     }
0428 
0429     void flush() {}
0430 
0431     int error()
0432     {
0433         return _in.fail();
0434     }
0435 
0436 private:
0437 
0438     std::istream& _in;
0439 };
0440 
0441 /**
0442  * Output stream device
0443  */
0444 template< typename FormatTag >
0445 class ostream_device
0446 {
0447 public:
0448     ostream_device( std::ostream & out )
0449         : _out( out )
0450     {
0451     }
0452 
0453     std::size_t read(byte_t *, std::size_t)
0454     {
0455         io_error( "ostream_device: Bad io error." );
0456         return 0;
0457     }
0458 
0459     void seek( long count, int whence )
0460     {
0461         _out.seekp( count
0462                   , whence == SEEK_SET
0463                     ? std::ios::beg
0464                     : ( whence == SEEK_CUR
0465                         ?std::ios::cur
0466                         :std::ios::end )
0467                   );
0468     }
0469 
0470     long int tell()
0471     {
0472         auto pos = _out.tellp();
0473 
0474         io_error_if( pos == std::ostream::pos_type(-1)
0475                    , "ostream_device: file position error"
0476                    );
0477 
0478         return static_cast<long int>(pos);
0479     }
0480 
0481     void write( const byte_t* data
0482               , std::size_t   count )
0483     {
0484         _out.write( reinterpret_cast<char const*>( data )
0485                  , static_cast<std::streamsize>( count )
0486                  );
0487     }
0488 
0489     /// Writes array
0490     template < typename    T
0491              , std::size_t N
0492              >
0493     void write( const T (&buf)[N] )
0494     {
0495         write( buf, N );
0496     }
0497 
0498     /// Writes byte
0499     void write_uint8( uint8_t x )
0500     {
0501         byte_t m[1] = { x };
0502         write(m);
0503     }
0504 
0505     /// Writes 16 bit little endian integer
0506     void write_uint16( uint16_t x )
0507     {
0508         byte_t m[2];
0509 
0510         m[0] = byte_t( x >> 0 );
0511         m[1] = byte_t( x >> 8 );
0512 
0513         write( m );
0514     }
0515 
0516     /// Writes 32 bit little endian integer
0517     void write_uint32( uint32_t x )
0518     {
0519         byte_t m[4];
0520 
0521         m[0] = byte_t( x >>  0 );
0522         m[1] = byte_t( x >>  8 );
0523         m[2] = byte_t( x >> 16 );
0524         m[3] = byte_t( x >> 24 );
0525 
0526         write( m );
0527     }
0528 
0529     void flush()
0530     {
0531         _out << std::flush;
0532     }
0533 
0534     /// Prints formatted ASCII text
0535     void print_line( const std::string& line )
0536     {
0537         _out << line;
0538     }
0539 
0540     int error()
0541     {
0542         return _out.fail();
0543     }
0544 
0545 private:
0546 
0547     std::ostream& _out;
0548 };
0549 
0550 
0551 /**
0552  * Metafunction to detect input devices.
0553  * Should be replaced by an external facility in the future.
0554  */
0555 template< typename IODevice  > struct is_input_device : std::false_type{};
0556 template< typename FormatTag > struct is_input_device< file_stream_device< FormatTag > > : std::true_type{};
0557 template< typename FormatTag > struct is_input_device<     istream_device< FormatTag > > : std::true_type{};
0558 
0559 template< typename FormatTag
0560         , typename T
0561         , typename D = void
0562         >
0563 struct is_adaptable_input_device : std::false_type{};
0564 
0565 template <typename FormatTag, typename T>
0566 struct is_adaptable_input_device
0567 <
0568     FormatTag,
0569     T,
0570     typename std::enable_if
0571     <
0572         mp11::mp_or
0573         <
0574             std::is_base_of<std::istream, T>,
0575             std::is_same<std::istream, T>
0576         >::value
0577     >::type
0578 > : std::true_type
0579 {
0580     using device_type = istream_device<FormatTag>;
0581 };
0582 
0583 template< typename FormatTag >
0584 struct is_adaptable_input_device< FormatTag
0585                                 , FILE*
0586                                 , void
0587                                 >
0588     : std::true_type
0589 {
0590     using device_type = file_stream_device<FormatTag>;
0591 };
0592 
0593 ///
0594 /// Metafunction to decide if a given type is an acceptable read device type.
0595 ///
0596 template< typename FormatTag
0597         , typename T
0598         , typename D = void
0599         >
0600 struct is_read_device : std::false_type
0601 {};
0602 
0603 template <typename FormatTag, typename T>
0604 struct is_read_device
0605 <
0606     FormatTag,
0607     T,
0608     typename std::enable_if
0609     <
0610         mp11::mp_or
0611         <
0612             is_input_device<FormatTag>,
0613             is_adaptable_input_device<FormatTag, T>
0614         >::value
0615     >::type
0616 > : std::true_type
0617 {
0618 };
0619 
0620 
0621 /**
0622  * Metafunction to detect output devices.
0623  * Should be replaced by an external facility in the future.
0624  */
0625 template<typename IODevice> struct is_output_device : std::false_type{};
0626 
0627 template< typename FormatTag > struct is_output_device< file_stream_device< FormatTag > > : std::true_type{};
0628 template< typename FormatTag > struct is_output_device< ostream_device    < FormatTag > > : std::true_type{};
0629 
0630 template< typename FormatTag
0631         , typename IODevice
0632         , typename D = void
0633         >
0634 struct is_adaptable_output_device : std::false_type {};
0635 
0636 template <typename FormatTag, typename T>
0637 struct is_adaptable_output_device
0638 <
0639     FormatTag,
0640     T,
0641     typename std::enable_if
0642     <
0643         mp11::mp_or
0644         <
0645             std::is_base_of<std::ostream, T>,
0646             std::is_same<std::ostream, T>
0647         >::value
0648     >::type
0649 > : std::true_type
0650 {
0651     using device_type = ostream_device<FormatTag>;
0652 };
0653 
0654 template<typename FormatTag> struct is_adaptable_output_device<FormatTag,FILE*,void>
0655   : std::true_type
0656 {
0657     using device_type = file_stream_device<FormatTag>;
0658 };
0659 
0660 
0661 ///
0662 /// Metafunction to decide if a given type is an acceptable read device type.
0663 ///
0664 template< typename FormatTag
0665         , typename T
0666         , typename D = void
0667         >
0668 struct is_write_device : std::false_type
0669 {};
0670 
0671 template <typename FormatTag, typename T>
0672 struct is_write_device
0673 <
0674     FormatTag,
0675     T,
0676     typename std::enable_if
0677     <
0678         mp11::mp_or
0679         <
0680             is_output_device<FormatTag>,
0681             is_adaptable_output_device<FormatTag, T>
0682         >::value
0683     >::type
0684 > : std::true_type
0685 {
0686 };
0687 
0688 } // namespace detail
0689 
0690 template< typename Device, typename FormatTag > class scanline_reader;
0691 template< typename Device, typename FormatTag, typename ConversionPolicy > class reader;
0692 
0693 template< typename Device, typename FormatTag, typename Log = no_log > class writer;
0694 
0695 template< typename Device, typename FormatTag > class dynamic_image_reader;
0696 template< typename Device, typename FormatTag, typename Log = no_log > class dynamic_image_writer;
0697 
0698 
0699 namespace detail {
0700 
0701 template< typename T >
0702 struct is_reader : std::false_type
0703 {};
0704 
0705 template< typename Device
0706         , typename FormatTag
0707         , typename ConversionPolicy
0708         >
0709 struct is_reader< reader< Device
0710                         , FormatTag
0711                         , ConversionPolicy
0712                         >
0713                 > : std::true_type
0714 {};
0715 
0716 template< typename T >
0717 struct is_dynamic_image_reader : std::false_type
0718 {};
0719 
0720 template< typename Device
0721         , typename FormatTag
0722         >
0723 struct is_dynamic_image_reader< dynamic_image_reader< Device
0724                                                     , FormatTag
0725                                                     >
0726                               > : std::true_type
0727 {};
0728 
0729 template< typename T >
0730 struct is_writer : std::false_type
0731 {};
0732 
0733 template< typename Device
0734         , typename FormatTag
0735         >
0736 struct is_writer< writer< Device
0737                         , FormatTag
0738                         >
0739                 > : std::true_type
0740 {};
0741 
0742 template< typename T >
0743 struct is_dynamic_image_writer : std::false_type
0744 {};
0745 
0746 template< typename Device
0747         , typename FormatTag
0748         >
0749 struct is_dynamic_image_writer< dynamic_image_writer< Device
0750                                                     , FormatTag
0751                                                     >
0752                 > : std::true_type
0753 {};
0754 
0755 } // namespace detail
0756 
0757 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0758 #pragma warning(pop)
0759 #endif
0760 
0761 } // namespace gil
0762 } // namespace boost
0763 
0764 #endif