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