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