| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739 | //// Copyright 2007-2012 Christian Henning, Andreas Pokorny//// Distributed under the Boost Software License, Version 1.0// See accompanying file LICENSE_1_0.txt or copy at// http://www.boost.org/LICENSE_1_0.txt//#ifndef BOOST_GIL_IO_DEVICE_HPP#define BOOST_GIL_IO_DEVICE_HPP#include <boost/gil/detail/mp11.hpp>#include <boost/gil/io/base.hpp>#include <cstdio>#include <memory>#include <type_traits>namespace boost { namespace gil {#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)#pragma warning(push)#pragma warning(disable:4512) //assignment operator could not be generated#endifnamespace detail {template < typename T > struct buff_item{    static const unsigned int size = sizeof( T );};template <> struct buff_item< void >{    static const unsigned int size = 1;};/*! * Implements the IODevice concept c.f. to \ref IODevice required by Image libraries like * libjpeg and libpng. * * \todo switch to a sane interface as soon as there is * something good in boost. I.E. the IOChains library * would fit very well here. * * This implementation is based on FILE*. */template< typename FormatTag >class file_stream_device{public:   using format_tag_t = FormatTag;public:    /// Used to overload the constructor.    struct read_tag {};    struct write_tag {};    ///    /// Constructor    ///    file_stream_device( const std::string& file_name                      , read_tag tag  = read_tag()                      )        : file_stream_device(file_name.c_str(), tag)    {}    ///    /// Constructor    ///    file_stream_device( const char* file_name                      , read_tag   = read_tag()                      )    {        FILE* file = nullptr;        io_error_if( ( file = fopen( file_name, "rb" )) == nullptr                   , "file_stream_device: failed to open file for reading"                   );        _file = file_ptr_t( file                          , file_deleter                          );    }    ///    /// Constructor    ///    file_stream_device( const std::string& file_name                      , write_tag tag                      )        : file_stream_device(file_name.c_str(), tag)    {}    ///    /// Constructor    ///    file_stream_device( const char* file_name                      , write_tag                      )    {        FILE* file = nullptr;        io_error_if( ( file = fopen( file_name, "wb" )) == nullptr                   , "file_stream_device: failed to open file for writing"                   );        _file = file_ptr_t( file                          , file_deleter                          );    }    ///    /// Constructor    ///    file_stream_device( FILE* file )    : _file( file           , file_deleter           )    {}    FILE*       get()       { return _file.get(); }    const FILE* get() const { return _file.get(); }    int getc_unchecked()    {        return std::getc( get() );    }    char getc()    {        int ch;        io_error_if( ( ch = std::getc( get() )) == EOF                   , "file_stream_device: unexpected EOF"                   );        return ( char ) ch;    }    ///@todo: change byte_t* to void*    std::size_t read( byte_t*     data                    , std::size_t count                    )    {        std::size_t num_elements = fread( data                                        , 1                                        , static_cast<int>( count )                                        , get()                                        );        ///@todo: add compiler symbol to turn error checking on and off.        io_error_if( ferror( get() )                   , "file_stream_device: file read error"                   );        //libjpeg sometimes reads blocks in 4096 bytes even when the file is smaller than that.        //return value indicates how much was actually read        //returning less than "count" is not an error        return num_elements;    }    /// Reads array    template< typename T            , int      N            >    void read( T (&buf)[N] )    {        io_error_if( read( buf, N ) < N                   , "file_stream_device: file read error"                   );    }    /// Reads byte    uint8_t read_uint8()    {        byte_t m[1];        read( m );        return m[0];    }    /// Reads 16 bit little endian integer    uint16_t read_uint16()    {        byte_t m[2];        read( m );        return (m[1] << 8) | m[0];    }    /// Reads 32 bit little endian integer    uint32_t read_uint32()    {        byte_t m[4];        read( m );        return (m[3] << 24) | (m[2] << 16) | (m[1] << 8) | m[0];    }    /// Writes number of elements from a buffer    template < typename T >    std::size_t write( const T*    buf                     , std::size_t count                     )    {        std::size_t num_elements = fwrite( buf                                         , buff_item<T>::size                                         , count                                         , get()                                         );        //return value indicates how much was actually written        //returning less than "count" is not an error        return num_elements;    }    /// Writes array    template < typename    T             , std::size_t N             >    void write( const T (&buf)[N] )    {        io_error_if( write( buf, N ) < N                   , "file_stream_device: file write error"                   );        return ;    }    /// Writes byte    void write_uint8( uint8_t x )    {        byte_t m[1] = { x };        write(m);    }    /// Writes 16 bit little endian integer    void write_uint16( uint16_t x )    {        byte_t m[2];        m[0] = byte_t( x >> 0 );        m[1] = byte_t( x >> 8 );        write( m );    }    /// Writes 32 bit little endian integer    void write_uint32( uint32_t x )    {        byte_t m[4];        m[0] = byte_t( x >>  0 );        m[1] = byte_t( x >>  8 );        m[2] = byte_t( x >> 16 );        m[3] = byte_t( x >> 24 );        write( m );    }    void seek( long count, int whence = SEEK_SET )    {        io_error_if( fseek( get()                          , count                          , whence                          ) != 0                   , "file_stream_device: file seek error"                   );    }    long int tell()    {        long int pos = ftell( get() );        io_error_if( pos == -1L                   , "file_stream_device: file position error"                   );        return pos;    }    void flush()    {        fflush( get() );    }    /// Prints formatted ASCII text    void print_line( const std::string& line )    {        std::size_t num_elements = fwrite( line.c_str()                                         , sizeof( char )                                         , line.size()                                         , get()                                         );        io_error_if( num_elements < line.size()                   , "file_stream_device: line print error"                   );    }    int error()    {        return ferror( get() );    }private:    static void file_deleter( FILE* file )    {        if( file )        {            fclose( file );        }    }private:    using file_ptr_t = std::shared_ptr<FILE> ;    file_ptr_t _file;};/** * Input stream device */template< typename FormatTag >class istream_device{public:   istream_device( std::istream& in )   : _in( in )   {       // does the file exists?       io_error_if( !in                  , "istream_device: Stream is not valid."                  );   }    int getc_unchecked()    {        return _in.get();    }    char getc()    {        int ch;        io_error_if( ( ch = _in.get() ) == EOF                   , "istream_device: unexpected EOF"                   );        return ( char ) ch;    }    std::size_t read( byte_t*     data                    , std::size_t count )    {        std::streamsize cr = 0;        do        {            _in.peek();            std::streamsize c = _in.readsome( reinterpret_cast< char* >( data )                                            , static_cast< std::streamsize >( count ));            count -= static_cast< std::size_t >( c );            data += c;            cr += c;        } while( count && _in );        return static_cast< std::size_t >( cr );    }    /// Reads array    template<typename T, int N>    void read(T (&buf)[N])    {        read(buf, N);    }    /// Reads byte    uint8_t read_uint8()    {        byte_t m[1];        read( m );        return m[0];    }    /// Reads 16 bit little endian integer    uint16_t read_uint16()    {        byte_t m[2];        read( m );        return (m[1] << 8) | m[0];    }    /// Reads 32 bit little endian integer    uint32_t read_uint32()    {        byte_t m[4];        read( m );        return (m[3] << 24) | (m[2] << 16) | (m[1] << 8) | m[0];    }    void seek( long count, int whence = SEEK_SET )    {        _in.seekg( count                 , whence == SEEK_SET ? std::ios::beg                                      :( whence == SEEK_CUR ? std::ios::cur                                                            : std::ios::end )                 );    }    void write(const byte_t*, std::size_t)    {        io_error( "istream_device: Bad io error." );    }    void flush() {}private:    std::istream& _in;};/** * Output stream device */template< typename FormatTag >class ostream_device{public:    ostream_device( std::ostream & out )        : _out( out )    {    }    std::size_t read(byte_t *, std::size_t)    {        io_error( "ostream_device: Bad io error." );        return 0;    }    void seek( long count, int whence )    {        _out.seekp( count                  , whence == SEEK_SET                    ? std::ios::beg                    : ( whence == SEEK_CUR                        ?std::ios::cur                        :std::ios::end )                  );    }    void write( const byte_t* data              , std::size_t   count )    {        _out.write( reinterpret_cast<char const*>( data )                 , static_cast<std::streamsize>( count )                 );    }    /// Writes array    template < typename    T             , std::size_t N             >    void write( const T (&buf)[N] )    {        write( buf, N );    }    /// Writes byte    void write_uint8( uint8_t x )    {        byte_t m[1] = { x };        write(m);    }    /// Writes 16 bit little endian integer    void write_uint16( uint16_t x )    {        byte_t m[2];        m[0] = byte_t( x >> 0 );        m[1] = byte_t( x >> 8 );        write( m );    }    /// Writes 32 bit little endian integer    void write_uint32( uint32_t x )    {        byte_t m[4];        m[0] = byte_t( x >>  0 );        m[1] = byte_t( x >>  8 );        m[2] = byte_t( x >> 16 );        m[3] = byte_t( x >> 24 );        write( m );    }    void flush()    {        _out << std::flush;    }    /// Prints formatted ASCII text    void print_line( const std::string& line )    {        _out << line;    }private:    std::ostream& _out;};/** * Metafunction to detect input devices. * Should be replaced by an external facility in the future. */template< typename IODevice  > struct is_input_device : std::false_type{};template< typename FormatTag > struct is_input_device< file_stream_device< FormatTag > > : std::true_type{};template< typename FormatTag > struct is_input_device<     istream_device< FormatTag > > : std::true_type{};template< typename FormatTag        , typename T        , typename D = void        >struct is_adaptable_input_device : std::false_type{};template <typename FormatTag, typename T>struct is_adaptable_input_device<    FormatTag,    T,    typename std::enable_if    <        mp11::mp_or        <            std::is_base_of<std::istream, T>,            std::is_same<std::istream, T>        >::value    >::type> : std::true_type{    using device_type = istream_device<FormatTag>;};template< typename FormatTag >struct is_adaptable_input_device< FormatTag                                , FILE*                                , void                                >    : std::true_type{    using device_type = file_stream_device<FormatTag>;};////// Metafunction to decide if a given type is an acceptable read device type.///template< typename FormatTag        , typename T        , typename D = void        >struct is_read_device : std::false_type{};template <typename FormatTag, typename T>struct is_read_device<    FormatTag,    T,    typename std::enable_if    <        mp11::mp_or        <            is_input_device<FormatTag>,            is_adaptable_input_device<FormatTag, T>        >::value    >::type> : std::true_type{};/** * Metafunction to detect output devices. * Should be replaced by an external facility in the future. */template<typename IODevice> struct is_output_device : std::false_type{};template< typename FormatTag > struct is_output_device< file_stream_device< FormatTag > > : std::true_type{};template< typename FormatTag > struct is_output_device< ostream_device    < FormatTag > > : std::true_type{};template< typename FormatTag        , typename IODevice        , typename D = void        >struct is_adaptable_output_device : std::false_type {};template <typename FormatTag, typename T>struct is_adaptable_output_device<    FormatTag,    T,    typename std::enable_if    <        mp11::mp_or        <            std::is_base_of<std::ostream, T>,            std::is_same<std::ostream, T>        >::value    >::type> : std::true_type{    using device_type = ostream_device<FormatTag>;};template<typename FormatTag> struct is_adaptable_output_device<FormatTag,FILE*,void>  : std::true_type{    using device_type = file_stream_device<FormatTag>;};////// Metafunction to decide if a given type is an acceptable read device type.///template< typename FormatTag        , typename T        , typename D = void        >struct is_write_device : std::false_type{};template <typename FormatTag, typename T>struct is_write_device<    FormatTag,    T,    typename std::enable_if    <        mp11::mp_or        <            is_output_device<FormatTag>,            is_adaptable_output_device<FormatTag, T>        >::value    >::type> : std::true_type{};} // namespace detailtemplate< typename Device, typename FormatTag > class scanline_reader;template< typename Device, typename FormatTag, typename ConversionPolicy > class reader;template< typename Device, typename FormatTag, typename Log = no_log > class writer;template< typename Device, typename FormatTag > class dynamic_image_reader;template< typename Device, typename FormatTag, typename Log = no_log > class dynamic_image_writer;namespace detail {template< typename T >struct is_reader : std::false_type{};template< typename Device        , typename FormatTag        , typename ConversionPolicy        >struct is_reader< reader< Device                        , FormatTag                        , ConversionPolicy                        >                > : std::true_type{};template< typename T >struct is_dynamic_image_reader : std::false_type{};template< typename Device        , typename FormatTag        >struct is_dynamic_image_reader< dynamic_image_reader< Device                                                    , FormatTag                                                    >                              > : std::true_type{};template< typename T >struct is_writer : std::false_type{};template< typename Device        , typename FormatTag        >struct is_writer< writer< Device                        , FormatTag                        >                > : std::true_type{};template< typename T >struct is_dynamic_image_writer : std::false_type{};template< typename Device        , typename FormatTag        >struct is_dynamic_image_writer< dynamic_image_writer< Device                                                    , FormatTag                                                    >                > : std::true_type{};} // namespace detail#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)#pragma warning(pop)#endif} // namespace gil} // namespace boost#endif
 |