Boost GIL


device.hpp
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 
11 #include <boost/gil/detail/mp11.hpp>
12 #include <boost/gil/io/base.hpp>
13 
14 #include <cstdio>
15 #include <memory>
16 #include <type_traits>
17 
18 namespace boost { namespace gil {
19 
20 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
21 #pragma warning(push)
22 #pragma warning(disable:4512) //assignment operator could not be generated
23 #endif
24 
25 namespace detail {
26 
27 template < typename T > struct buff_item
28 {
29  static const unsigned int size = sizeof( T );
30 };
31 
32 template <> struct buff_item< void >
33 {
34  static const unsigned int size = 1;
35 };
36 
47 template< typename FormatTag >
49 {
50 public:
51 
52  using format_tag_t = FormatTag;
53 
54 public:
55 
57  struct read_tag {};
58  struct write_tag {};
59 
63  file_stream_device( const std::string& file_name
64  , read_tag tag = read_tag()
65  )
66  : file_stream_device(file_name.c_str(), tag)
67  {}
68 
72  file_stream_device( const char* file_name
73  , read_tag = read_tag()
74  )
75  {
76  FILE* file = nullptr;
77 
78  io_error_if( ( file = fopen( file_name, "rb" )) == nullptr
79  , "file_stream_device: failed to open file for reading"
80  );
81 
82  _file = file_ptr_t( file
83  , file_deleter
84  );
85  }
86 
90  file_stream_device( const std::string& file_name
91  , write_tag tag
92  )
93  : file_stream_device(file_name.c_str(), tag)
94  {}
95 
99  file_stream_device( const char* file_name
100  , write_tag
101  )
102  {
103  FILE* file = nullptr;
104 
105  io_error_if( ( file = fopen( file_name, "wb" )) == nullptr
106  , "file_stream_device: failed to open file for writing"
107  );
108 
109  _file = file_ptr_t( file
110  , file_deleter
111  );
112  }
113 
117  file_stream_device( FILE* file )
118  : _file( file
119  , file_deleter
120  )
121  {}
122 
123  FILE* get() { return _file.get(); }
124  const FILE* get() const { return _file.get(); }
125 
126  int getc_unchecked()
127  {
128  return std::getc( get() );
129  }
130 
131  char getc()
132  {
133  int ch;
134 
135  io_error_if( ( ch = std::getc( get() )) == EOF
136  , "file_stream_device: unexpected EOF"
137  );
138 
139  return ( char ) ch;
140  }
141 
143  std::size_t read( byte_t* data
144  , std::size_t count
145  )
146  {
147  std::size_t num_elements = fread( data
148  , 1
149  , static_cast<int>( count )
150  , get()
151  );
152 
154  io_error_if( ferror( get() )
155  , "file_stream_device: file read error"
156  );
157 
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
161  return num_elements;
162  }
163 
165  template< typename T
166  , int N
167  >
168  void read( T (&buf)[N] )
169  {
170  io_error_if( read( buf, N ) < N
171  , "file_stream_device: file read error"
172  );
173  }
174 
176  uint8_t read_uint8()
177  {
178  byte_t m[1];
179 
180  read( m );
181  return m[0];
182  }
183 
185  uint16_t read_uint16()
186  {
187  byte_t m[2];
188 
189  read( m );
190  return (m[1] << 8) | m[0];
191  }
192 
194  uint32_t read_uint32()
195  {
196  byte_t m[4];
197 
198  read( m );
199  return (m[3] << 24) | (m[2] << 16) | (m[1] << 8) | m[0];
200  }
201 
203  template < typename T >
204  std::size_t write( const T* buf
205  , std::size_t count
206  )
207  {
208  std::size_t num_elements = fwrite( buf
209  , buff_item<T>::size
210  , count
211  , get()
212  );
213 
214  //return value indicates how much was actually written
215  //returning less than "count" is not an error
216  return num_elements;
217  }
218 
220  template < typename T
221  , std::size_t N
222  >
223  void write( const T (&buf)[N] )
224  {
225  io_error_if( write( buf, N ) < N
226  , "file_stream_device: file write error"
227  );
228  return ;
229  }
230 
232  void write_uint8( uint8_t x )
233  {
234  byte_t m[1] = { x };
235  write(m);
236  }
237 
239  void write_uint16( uint16_t x )
240  {
241  byte_t m[2];
242 
243  m[0] = byte_t( x >> 0 );
244  m[1] = byte_t( x >> 8 );
245 
246  write( m );
247  }
248 
250  void write_uint32( uint32_t x )
251  {
252  byte_t m[4];
253 
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 );
258 
259  write( m );
260  }
261 
262  void seek( long count, int whence = SEEK_SET )
263  {
264  io_error_if( fseek( get()
265  , count
266  , whence
267  ) != 0
268  , "file_stream_device: file seek error"
269  );
270  }
271 
272  long int tell()
273  {
274  long int pos = ftell( get() );
275 
276  io_error_if( pos == -1L
277  , "file_stream_device: file position error"
278  );
279 
280  return pos;
281  }
282 
283  void flush()
284  {
285  fflush( get() );
286  }
287 
289  void print_line( const std::string& line )
290  {
291  std::size_t num_elements = fwrite( line.c_str()
292  , sizeof( char )
293  , line.size()
294  , get()
295  );
296 
297  io_error_if( num_elements < line.size()
298  , "file_stream_device: line print error"
299  );
300  }
301 
302  int error()
303  {
304  return ferror( get() );
305  }
306 
307 private:
308 
309  static void file_deleter( FILE* file )
310  {
311  if( file )
312  {
313  fclose( file );
314  }
315  }
316 
317 private:
318 
319  using file_ptr_t = std::shared_ptr<FILE> ;
320  file_ptr_t _file;
321 };
322 
326 template< typename FormatTag >
328 {
329 public:
330  istream_device( std::istream& in )
331  : _in( in )
332  {
333  // does the file exists?
334  io_error_if( !in
335  , "istream_device: Stream is not valid."
336  );
337  }
338 
339  int getc_unchecked()
340  {
341  return _in.get();
342  }
343 
344  char getc()
345  {
346  int ch;
347 
348  io_error_if( ( ch = _in.get() ) == EOF
349  , "istream_device: unexpected EOF"
350  );
351 
352  return ( char ) ch;
353  }
354 
355  std::size_t read( byte_t* data
356  , std::size_t count )
357  {
358  std::streamsize cr = 0;
359 
360  do
361  {
362  _in.peek();
363  std::streamsize c = _in.readsome( reinterpret_cast< char* >( data )
364  , static_cast< std::streamsize >( count ));
365 
366  count -= static_cast< std::size_t >( c );
367  data += c;
368  cr += c;
369 
370  } while( count && _in );
371 
372  return static_cast< std::size_t >( cr );
373  }
374 
376  template< typename T
377  , int N
378  >
379  void read( T (&buf)[N] )
380  {
381  return read( buf, N );
382  }
383 
385  uint8_t read_uint8()
386  {
387  byte_t m[1];
388 
389  read( m );
390  return m[0];
391  }
392 
394  uint16_t read_uint16()
395  {
396  byte_t m[2];
397 
398  read( m );
399  return (m[1] << 8) | m[0];
400  }
401 
403  uint32_t read_uint32()
404  {
405  byte_t m[4];
406 
407  read( m );
408  return (m[3] << 24) | (m[2] << 16) | (m[1] << 8) | m[0];
409  }
410 
411  void seek( long count, int whence = SEEK_SET )
412  {
413  _in.seekg( count
414  , whence == SEEK_SET ? std::ios::beg
415  :( whence == SEEK_CUR ? std::ios::cur
416  : std::ios::end )
417  );
418  }
419 
420  void write(const byte_t*, std::size_t)
421  {
422  io_error( "istream_device: Bad io error." );
423  }
424 
425  void flush() {}
426 
427 private:
428 
429  std::istream& _in;
430 };
431 
435 template< typename FormatTag >
437 {
438 public:
439  ostream_device( std::ostream & out )
440  : _out( out )
441  {
442  }
443 
444  std::size_t read(byte_t *, std::size_t)
445  {
446  io_error( "ostream_device: Bad io error." );
447  return 0;
448  }
449 
450  void seek( long count, int whence )
451  {
452  _out.seekp( count
453  , whence == SEEK_SET
454  ? std::ios::beg
455  : ( whence == SEEK_CUR
456  ?std::ios::cur
457  :std::ios::end )
458  );
459  }
460 
461  void write( const byte_t* data
462  , std::size_t count )
463  {
464  _out.write( reinterpret_cast<char const*>( data )
465  , static_cast<std::streamsize>( count )
466  );
467  }
468 
470  template < typename T
471  , std::size_t N
472  >
473  void write( const T (&buf)[N] )
474  {
475  write( buf, N );
476  }
477 
479  void write_uint8( uint8_t x )
480  {
481  byte_t m[1] = { x };
482  write(m);
483  }
484 
486  void write_uint16( uint16_t x )
487  {
488  byte_t m[2];
489 
490  m[0] = byte_t( x >> 0 );
491  m[1] = byte_t( x >> 8 );
492 
493  write( m );
494  }
495 
497  void write_uint32( uint32_t x )
498  {
499  byte_t m[4];
500 
501  m[0] = byte_t( x >> 0 );
502  m[1] = byte_t( x >> 8 );
503  m[2] = byte_t( x >> 16 );
504  m[3] = byte_t( x >> 24 );
505 
506  write( m );
507  }
508 
509  void flush()
510  {
511  _out << std::flush;
512  }
513 
515  void print_line( const std::string& line )
516  {
517  _out << line;
518  }
519 
520 
521 
522 private:
523 
524  std::ostream& _out;
525 };
526 
527 
532 template< typename IODevice > struct is_input_device : std::false_type{};
533 template< typename FormatTag > struct is_input_device< file_stream_device< FormatTag > > : std::true_type{};
534 template< typename FormatTag > struct is_input_device< istream_device< FormatTag > > : std::true_type{};
535 
536 template< typename FormatTag
537  , typename T
538  , typename D = void
539  >
540 struct is_adaptable_input_device : std::false_type{};
541 
542 template <typename FormatTag, typename T>
543 struct is_adaptable_input_device
544 <
545  FormatTag,
546  T,
547  typename std::enable_if
548  <
549  mp11::mp_or
550  <
551  std::is_base_of<std::istream, T>,
552  std::is_same<std::istream, T>
553  >::value
554  >::type
555 > : std::true_type
556 {
557  using device_type = istream_device<FormatTag>;
558 };
559 
560 template< typename FormatTag >
561 struct is_adaptable_input_device< FormatTag
562  , FILE*
563  , void
564  >
565  : std::true_type
566 {
567  using device_type = file_stream_device<FormatTag>;
568 };
569 
573 template< typename FormatTag
574  , typename T
575  , typename D = void
576  >
577 struct is_read_device : std::false_type
578 {};
579 
580 template <typename FormatTag, typename T>
581 struct is_read_device
582 <
583  FormatTag,
584  T,
585  typename std::enable_if
586  <
587  mp11::mp_or
588  <
589  is_input_device<FormatTag>,
590  is_adaptable_input_device<FormatTag, T>
591  >::value
592  >::type
593 > : std::true_type
594 {
595 };
596 
597 
602 template<typename IODevice> struct is_output_device : std::false_type{};
603 
604 template< typename FormatTag > struct is_output_device< file_stream_device< FormatTag > > : std::true_type{};
605 template< typename FormatTag > struct is_output_device< ostream_device < FormatTag > > : std::true_type{};
606 
607 template< typename FormatTag
608  , typename IODevice
609  , typename D = void
610  >
611 struct is_adaptable_output_device : std::false_type {};
612 
613 template <typename FormatTag, typename T>
614 struct is_adaptable_output_device
615 <
616  FormatTag,
617  T,
618  typename std::enable_if
619  <
620  mp11::mp_or
621  <
622  std::is_base_of<std::ostream, T>,
623  std::is_same<std::ostream, T>
624  >::value
625  >::type
626 > : std::true_type
627 {
628  using device_type = ostream_device<FormatTag>;
629 };
630 
631 template<typename FormatTag> struct is_adaptable_output_device<FormatTag,FILE*,void>
632  : std::true_type
633 {
634  using device_type = file_stream_device<FormatTag>;
635 };
636 
637 
641 template< typename FormatTag
642  , typename T
643  , typename D = void
644  >
645 struct is_write_device : std::false_type
646 {};
647 
648 template <typename FormatTag, typename T>
649 struct is_write_device
650 <
651  FormatTag,
652  T,
653  typename std::enable_if
654  <
655  mp11::mp_or
656  <
657  is_output_device<FormatTag>,
658  is_adaptable_output_device<FormatTag, T>
659  >::value
660  >::type
661 > : std::true_type
662 {
663 };
664 
665 } // namespace detail
666 
667 template< typename Device, typename FormatTag > class scanline_reader;
668 template< typename Device, typename FormatTag, typename ConversionPolicy > class reader;
669 
670 template< typename Device, typename FormatTag, typename Log = no_log > class writer;
671 
672 template< typename Device, typename FormatTag > class dynamic_image_reader;
673 template< typename Device, typename FormatTag, typename Log = no_log > class dynamic_image_writer;
674 
675 
676 namespace detail {
677 
678 template< typename T >
679 struct is_reader : std::false_type
680 {};
681 
682 template< typename Device
683  , typename FormatTag
684  , typename ConversionPolicy
685  >
686 struct is_reader< reader< Device
687  , FormatTag
688  , ConversionPolicy
689  >
690  > : std::true_type
691 {};
692 
693 template< typename T >
694 struct is_dynamic_image_reader : std::false_type
695 {};
696 
697 template< typename Device
698  , typename FormatTag
699  >
700 struct is_dynamic_image_reader< dynamic_image_reader< Device
701  , FormatTag
702  >
703  > : std::true_type
704 {};
705 
706 template< typename T >
707 struct is_writer : std::false_type
708 {};
709 
710 template< typename Device
711  , typename FormatTag
712  >
713 struct is_writer< writer< Device
714  , FormatTag
715  >
716  > : std::true_type
717 {};
718 
719 template< typename T >
720 struct is_dynamic_image_writer : std::false_type
721 {};
722 
723 template< typename Device
724  , typename FormatTag
725  >
726 struct is_dynamic_image_writer< dynamic_image_writer< Device
727  , FormatTag
728  >
729  > : std::true_type
730 {};
731 
732 } // namespace detail
733 
734 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
735 #pragma warning(pop)
736 #endif
737 
738 } // namespace gil
739 } // namespace boost
740 
741 #endif
Definition: device.hpp:532
void write_uint8(uint8_t x)
Writes byte.
Definition: device.hpp:479
file_stream_device(const std::string &file_name, write_tag tag)
Definition: device.hpp:90
Definition: algorithm.hpp:30
std::size_t read(byte_t *data, std::size_t count)
Definition: device.hpp:143
void print_line(const std::string &line)
Prints formatted ASCII text.
Definition: device.hpp:289
void read(T(&buf)[N])
Reads array.
Definition: device.hpp:379
uint16_t read_uint16()
Reads 16 bit little endian integer.
Definition: device.hpp:185
std::size_t write(const T *buf, std::size_t count)
Writes number of elements from a buffer.
Definition: device.hpp:204
uint16_t read_uint16()
Reads 16 bit little endian integer.
Definition: device.hpp:394
void write(const T(&buf)[N])
Writes array.
Definition: device.hpp:223
Definition: device.hpp:577
void write_uint32(uint32_t x)
Writes 32 bit little endian integer.
Definition: device.hpp:250
void write_uint8(uint8_t x)
Writes byte.
Definition: device.hpp:232
uint32_t read_uint32()
Reads 32 bit little endian integer.
Definition: device.hpp:194
void write_uint16(uint16_t x)
Writes 16 bit little endian integer.
Definition: device.hpp:239
uint8_t read_uint8()
Reads byte.
Definition: device.hpp:385
Used to overload the constructor.
Definition: device.hpp:57
uint8_t read_uint8()
Reads byte.
Definition: device.hpp:176
Definition: device.hpp:602
uint32_t read_uint32()
Reads 32 bit little endian integer.
Definition: device.hpp:403
file_stream_device(const char *file_name, read_tag=read_tag())
Definition: device.hpp:72
void write(const T(&buf)[N])
Writes array.
Definition: device.hpp:473
file_stream_device(const std::string &file_name, read_tag tag=read_tag())
Definition: device.hpp:63
Definition: device.hpp:645
void write_uint16(uint16_t x)
Writes 16 bit little endian integer.
Definition: device.hpp:486
Definition: device.hpp:436
Definition: device.hpp:327
file_stream_device(FILE *file)
Definition: device.hpp:117
void print_line(const std::string &line)
Prints formatted ASCII text.
Definition: device.hpp:515
void read(T(&buf)[N])
Reads array.
Definition: device.hpp:168
file_stream_device(const char *file_name, write_tag)
Definition: device.hpp:99
void write_uint32(uint32_t x)
Writes 32 bit little endian integer.
Definition: device.hpp:497