2 // Copyright 2007-2012 Christian Henning, Andreas Pokorny
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
8 #ifndef BOOST_GIL_IO_DEVICE_HPP
9 #define BOOST_GIL_IO_DEVICE_HPP
11 #include <boost/gil/detail/mp11.hpp>
12 #include <boost/gil/io/base.hpp>
16 #include <type_traits>
18 namespace boost { namespace gil {
20 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
22 #pragma warning(disable:4512) //assignment operator could not be generated
27 template < typename T > struct buff_item
29 static const unsigned int size = sizeof( T );
32 template <> struct buff_item< void >
34 static const unsigned int size = 1;
38 * Implements the IODevice concept c.f. to \ref IODevice required by Image libraries like
41 * \todo switch to a sane interface as soon as there is
42 * something good in boost. I.E. the IOChains library
43 * would fit very well here.
45 * This implementation is based on FILE*.
47 template< typename FormatTag >
48 class file_stream_device
52 using format_tag_t = FormatTag;
56 /// Used to overload the constructor.
63 file_stream_device( const std::string& file_name
64 , read_tag tag = read_tag()
66 : file_stream_device(file_name.c_str(), tag)
72 file_stream_device( const char* file_name
73 , read_tag = read_tag()
78 io_error_if( ( file = fopen( file_name, "rb" )) == nullptr
79 , "file_stream_device: failed to open file for reading"
82 _file = file_ptr_t( file
90 file_stream_device( const std::string& file_name
93 : file_stream_device(file_name.c_str(), tag)
99 file_stream_device( const char* file_name
103 FILE* file = nullptr;
105 io_error_if( ( file = fopen( file_name, "wb" )) == nullptr
106 , "file_stream_device: failed to open file for writing"
109 _file = file_ptr_t( file
117 file_stream_device( FILE* file )
123 FILE* get() { return _file.get(); }
124 const FILE* get() const { return _file.get(); }
128 return std::getc( get() );
135 io_error_if( ( ch = std::getc( get() )) == EOF
136 , "file_stream_device: unexpected EOF"
142 ///@todo: change byte_t* to void*
143 std::size_t read( byte_t* data
147 std::size_t num_elements = fread( data
149 , static_cast<int>( count )
153 ///@todo: add compiler symbol to turn error checking on and off.
154 io_error_if( ferror( get() )
155 , "file_stream_device: file read error"
158 //libjpeg sometimes reads blocks in 4096 bytes even when the file is smaller than that.
159 //return value indicates how much was actually read
160 //returning less than "count" is not an error
168 void read( T (&buf)[N] )
170 io_error_if( read( buf, N ) < N
171 , "file_stream_device: file read error"
184 /// Reads 16 bit little endian integer
185 uint16_t read_uint16()
190 return (m[1] << 8) | m[0];
193 /// Reads 32 bit little endian integer
194 uint32_t read_uint32()
199 return (m[3] << 24) | (m[2] << 16) | (m[1] << 8) | m[0];
202 /// Writes number of elements from a buffer
203 template < typename T >
204 std::size_t write( const T* buf
208 std::size_t num_elements = fwrite( buf
214 //return value indicates how much was actually written
215 //returning less than "count" is not an error
220 template < typename T
223 void write( const T (&buf)[N] )
225 io_error_if( write( buf, N ) < N
226 , "file_stream_device: file write error"
232 void write_uint8( uint8_t x )
238 /// Writes 16 bit little endian integer
239 void write_uint16( uint16_t x )
243 m[0] = byte_t( x >> 0 );
244 m[1] = byte_t( x >> 8 );
249 /// Writes 32 bit little endian integer
250 void write_uint32( uint32_t x )
254 m[0] = byte_t( x >> 0 );
255 m[1] = byte_t( x >> 8 );
256 m[2] = byte_t( x >> 16 );
257 m[3] = byte_t( x >> 24 );
262 void seek( long count, int whence = SEEK_SET )
264 io_error_if( fseek( get()
268 , "file_stream_device: file seek error"
274 long int pos = ftell( get() );
276 io_error_if( pos == -1L
277 , "file_stream_device: file position error"
288 /// Prints formatted ASCII text
289 void print_line( const std::string& line )
291 std::size_t num_elements = fwrite( line.c_str()
297 io_error_if( num_elements < line.size()
298 , "file_stream_device: line print error"
304 return ferror( get() );
309 static void file_deleter( FILE* file )
319 using file_ptr_t = std::shared_ptr<FILE> ;
324 * Input stream device
326 template< typename FormatTag >
330 istream_device( std::istream& in )
333 // does the file exists?
335 , "istream_device: Stream is not valid."
348 io_error_if( ( ch = _in.get() ) == EOF
349 , "istream_device: unexpected EOF"
355 std::size_t read( byte_t* data
356 , std::size_t count )
358 std::streamsize cr = 0;
363 std::streamsize c = _in.readsome( reinterpret_cast< char* >( data )
364 , static_cast< std::streamsize >( count ));
366 count -= static_cast< std::size_t >( c );
370 } while( count && _in );
372 return static_cast< std::size_t >( cr );
376 template<typename T, int N>
377 void read(T (&buf)[N])
391 /// Reads 16 bit little endian integer
392 uint16_t read_uint16()
397 return (m[1] << 8) | m[0];
400 /// Reads 32 bit little endian integer
401 uint32_t read_uint32()
406 return (m[3] << 24) | (m[2] << 16) | (m[1] << 8) | m[0];
409 void seek( long count, int whence = SEEK_SET )
412 , whence == SEEK_SET ? std::ios::beg
413 :( whence == SEEK_CUR ? std::ios::cur
418 void write(const byte_t*, std::size_t)
420 io_error( "istream_device: Bad io error." );
431 * Output stream device
433 template< typename FormatTag >
437 ostream_device( std::ostream & out )
442 std::size_t read(byte_t *, std::size_t)
444 io_error( "ostream_device: Bad io error." );
448 void seek( long count, int whence )
453 : ( whence == SEEK_CUR
459 void write( const byte_t* data
460 , std::size_t count )
462 _out.write( reinterpret_cast<char const*>( data )
463 , static_cast<std::streamsize>( count )
468 template < typename T
471 void write( const T (&buf)[N] )
477 void write_uint8( uint8_t x )
483 /// Writes 16 bit little endian integer
484 void write_uint16( uint16_t x )
488 m[0] = byte_t( x >> 0 );
489 m[1] = byte_t( x >> 8 );
494 /// Writes 32 bit little endian integer
495 void write_uint32( uint32_t x )
499 m[0] = byte_t( x >> 0 );
500 m[1] = byte_t( x >> 8 );
501 m[2] = byte_t( x >> 16 );
502 m[3] = byte_t( x >> 24 );
512 /// Prints formatted ASCII text
513 void print_line( const std::string& line )
527 * Metafunction to detect input devices.
528 * Should be replaced by an external facility in the future.
530 template< typename IODevice > struct is_input_device : std::false_type{};
531 template< typename FormatTag > struct is_input_device< file_stream_device< FormatTag > > : std::true_type{};
532 template< typename FormatTag > struct is_input_device< istream_device< FormatTag > > : std::true_type{};
534 template< typename FormatTag
538 struct is_adaptable_input_device : std::false_type{};
540 template <typename FormatTag, typename T>
541 struct is_adaptable_input_device
545 typename std::enable_if
549 std::is_base_of<std::istream, T>,
550 std::is_same<std::istream, T>
555 using device_type = istream_device<FormatTag>;
558 template< typename FormatTag >
559 struct is_adaptable_input_device< FormatTag
565 using device_type = file_stream_device<FormatTag>;
569 /// Metafunction to decide if a given type is an acceptable read device type.
571 template< typename FormatTag
575 struct is_read_device : std::false_type
578 template <typename FormatTag, typename T>
579 struct is_read_device
583 typename std::enable_if
587 is_input_device<FormatTag>,
588 is_adaptable_input_device<FormatTag, T>
597 * Metafunction to detect output devices.
598 * Should be replaced by an external facility in the future.
600 template<typename IODevice> struct is_output_device : std::false_type{};
602 template< typename FormatTag > struct is_output_device< file_stream_device< FormatTag > > : std::true_type{};
603 template< typename FormatTag > struct is_output_device< ostream_device < FormatTag > > : std::true_type{};
605 template< typename FormatTag
609 struct is_adaptable_output_device : std::false_type {};
611 template <typename FormatTag, typename T>
612 struct is_adaptable_output_device
616 typename std::enable_if
620 std::is_base_of<std::ostream, T>,
621 std::is_same<std::ostream, T>
626 using device_type = ostream_device<FormatTag>;
629 template<typename FormatTag> struct is_adaptable_output_device<FormatTag,FILE*,void>
632 using device_type = file_stream_device<FormatTag>;
637 /// Metafunction to decide if a given type is an acceptable read device type.
639 template< typename FormatTag
643 struct is_write_device : std::false_type
646 template <typename FormatTag, typename T>
647 struct is_write_device
651 typename std::enable_if
655 is_output_device<FormatTag>,
656 is_adaptable_output_device<FormatTag, T>
663 } // namespace detail
665 template< typename Device, typename FormatTag > class scanline_reader;
666 template< typename Device, typename FormatTag, typename ConversionPolicy > class reader;
668 template< typename Device, typename FormatTag, typename Log = no_log > class writer;
670 template< typename Device, typename FormatTag > class dynamic_image_reader;
671 template< typename Device, typename FormatTag, typename Log = no_log > class dynamic_image_writer;
676 template< typename T >
677 struct is_reader : std::false_type
680 template< typename Device
682 , typename ConversionPolicy
684 struct is_reader< reader< Device
691 template< typename T >
692 struct is_dynamic_image_reader : std::false_type
695 template< typename Device
698 struct is_dynamic_image_reader< dynamic_image_reader< Device
704 template< typename T >
705 struct is_writer : std::false_type
708 template< typename Device
711 struct is_writer< writer< Device
717 template< typename T >
718 struct is_dynamic_image_writer : std::false_type
721 template< typename Device
724 struct is_dynamic_image_writer< dynamic_image_writer< Device
730 } // namespace detail
732 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)