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  auto get() -> FILE* { return _file.get(); }
124  auto get() const -> FILE 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  auto read(byte_t* data, std::size_t count) -> std::size_t
144  {
145  std::size_t num_elements = fread( data
146  , 1
147  , static_cast<int>( count )
148  , get()
149  );
150 
152  io_error_if( ferror( get() )
153  , "file_stream_device: file read error"
154  );
155 
156  //libjpeg sometimes reads blocks in 4096 bytes even when the file is smaller than that.
157  //return value indicates how much was actually read
158  //returning less than "count" is not an error
159  return num_elements;
160  }
161 
163  template< typename T, int N>
164  void read( T (&buf)[N] )
165  {
166  io_error_if( read( buf, N ) < N
167  , "file_stream_device: file read error"
168  );
169  }
170 
172  uint8_t read_uint8()
173  {
174  byte_t m[1];
175 
176  read( m );
177  return m[0];
178  }
179 
181  uint16_t read_uint16()
182  {
183  byte_t m[2];
184 
185  read( m );
186  return (m[1] << 8) | m[0];
187  }
188 
190  uint32_t read_uint32()
191  {
192  byte_t m[4];
193 
194  read( m );
195  return (m[3] << 24) | (m[2] << 16) | (m[1] << 8) | m[0];
196  }
197 
199  template < typename T >
200  auto write(T const* buf, std::size_t count) -> std::size_t
201  {
202  std::size_t num_elements = fwrite( buf
203  , buff_item<T>::size
204  , count
205  , get()
206  );
207 
208  //return value indicates how much was actually written
209  //returning less than "count" is not an error
210  return num_elements;
211  }
212 
214  template < typename T
215  , std::size_t N
216  >
217  void write( const T (&buf)[N] )
218  {
219  io_error_if( write( buf, N ) < N
220  , "file_stream_device: file write error"
221  );
222  return ;
223  }
224 
226  void write_uint8( uint8_t x )
227  {
228  byte_t m[1] = { x };
229  write(m);
230  }
231 
233  void write_uint16( uint16_t x )
234  {
235  byte_t m[2];
236 
237  m[0] = byte_t( x >> 0 );
238  m[1] = byte_t( x >> 8 );
239 
240  write( m );
241  }
242 
244  void write_uint32( uint32_t x )
245  {
246  byte_t m[4];
247 
248  m[0] = byte_t( x >> 0 );
249  m[1] = byte_t( x >> 8 );
250  m[2] = byte_t( x >> 16 );
251  m[3] = byte_t( x >> 24 );
252 
253  write( m );
254  }
255 
256  void seek( long count, int whence = SEEK_SET )
257  {
258  io_error_if( fseek( get()
259  , count
260  , whence
261  ) != 0
262  , "file_stream_device: file seek error"
263  );
264  }
265 
266  long int tell()
267  {
268  long int pos = ftell( get() );
269 
270  io_error_if( pos == -1L
271  , "file_stream_device: file position error"
272  );
273 
274  return pos;
275  }
276 
277  void flush()
278  {
279  fflush( get() );
280  }
281 
283  void print_line( const std::string& line )
284  {
285  std::size_t num_elements = fwrite( line.c_str()
286  , sizeof( char )
287  , line.size()
288  , get()
289  );
290 
291  io_error_if( num_elements < line.size()
292  , "file_stream_device: line print error"
293  );
294  }
295 
296  int error()
297  {
298  return ferror( get() );
299  }
300 
301 private:
302 
303  static void file_deleter( FILE* file )
304  {
305  if( file )
306  {
307  fclose( file );
308  }
309  }
310 
311 private:
312 
313  using file_ptr_t = std::shared_ptr<FILE> ;
314  file_ptr_t _file;
315 };
316 
320 template< typename FormatTag >
322 {
323 public:
324  istream_device( std::istream& in )
325  : _in( in )
326  {
327  // does the file exists?
328  io_error_if( !in
329  , "istream_device: Stream is not valid."
330  );
331  }
332 
333  int getc_unchecked()
334  {
335  return _in.get();
336  }
337 
338  char getc()
339  {
340  int ch;
341 
342  io_error_if( ( ch = _in.get() ) == EOF
343  , "istream_device: unexpected EOF"
344  );
345 
346  return ( char ) ch;
347  }
348 
349  std::size_t read( byte_t* data
350  , std::size_t count )
351  {
352  std::streamsize cr = 0;
353 
354  do
355  {
356  _in.peek();
357  std::streamsize c = _in.readsome( reinterpret_cast< char* >( data )
358  , static_cast< std::streamsize >( count ));
359 
360  count -= static_cast< std::size_t >( c );
361  data += c;
362  cr += c;
363 
364  } while( count && _in );
365 
366  return static_cast< std::size_t >( cr );
367  }
368 
370  template<typename T, int N>
371  void read(T (&buf)[N])
372  {
373  read(buf, N);
374  }
375 
377  uint8_t read_uint8()
378  {
379  byte_t m[1];
380 
381  read( m );
382  return m[0];
383  }
384 
386  uint16_t read_uint16()
387  {
388  byte_t m[2];
389 
390  read( m );
391  return (m[1] << 8) | m[0];
392  }
393 
395  uint32_t read_uint32()
396  {
397  byte_t m[4];
398 
399  read( m );
400  return (m[3] << 24) | (m[2] << 16) | (m[1] << 8) | m[0];
401  }
402 
403  void seek( long count, int whence = SEEK_SET )
404  {
405  _in.seekg( count
406  , whence == SEEK_SET ? std::ios::beg
407  :( whence == SEEK_CUR ? std::ios::cur
408  : std::ios::end )
409  );
410  }
411 
412  void write(const byte_t*, std::size_t)
413  {
414  io_error( "istream_device: Bad io error." );
415  }
416 
417  void flush() {}
418 
419 private:
420 
421  std::istream& _in;
422 };
423 
427 template< typename FormatTag >
429 {
430 public:
431  ostream_device( std::ostream & out )
432  : _out( out )
433  {
434  }
435 
436  std::size_t read(byte_t *, std::size_t)
437  {
438  io_error( "ostream_device: Bad io error." );
439  return 0;
440  }
441 
442  void seek( long count, int whence )
443  {
444  _out.seekp( count
445  , whence == SEEK_SET
446  ? std::ios::beg
447  : ( whence == SEEK_CUR
448  ?std::ios::cur
449  :std::ios::end )
450  );
451  }
452 
453  void write( const byte_t* data
454  , std::size_t count )
455  {
456  _out.write( reinterpret_cast<char const*>( data )
457  , static_cast<std::streamsize>( count )
458  );
459  }
460 
462  template < typename T
463  , std::size_t N
464  >
465  void write( const T (&buf)[N] )
466  {
467  write( buf, N );
468  }
469 
471  void write_uint8( uint8_t x )
472  {
473  byte_t m[1] = { x };
474  write(m);
475  }
476 
478  void write_uint16( uint16_t x )
479  {
480  byte_t m[2];
481 
482  m[0] = byte_t( x >> 0 );
483  m[1] = byte_t( x >> 8 );
484 
485  write( m );
486  }
487 
489  void write_uint32( uint32_t x )
490  {
491  byte_t m[4];
492 
493  m[0] = byte_t( x >> 0 );
494  m[1] = byte_t( x >> 8 );
495  m[2] = byte_t( x >> 16 );
496  m[3] = byte_t( x >> 24 );
497 
498  write( m );
499  }
500 
501  void flush()
502  {
503  _out << std::flush;
504  }
505 
507  void print_line( const std::string& line )
508  {
509  _out << line;
510  }
511 
512 
513 
514 private:
515 
516  std::ostream& _out;
517 };
518 
519 
524 template< typename IODevice > struct is_input_device : std::false_type{};
525 template< typename FormatTag > struct is_input_device< file_stream_device< FormatTag > > : std::true_type{};
526 template< typename FormatTag > struct is_input_device< istream_device< FormatTag > > : std::true_type{};
527 
528 template< typename FormatTag
529  , typename T
530  , typename D = void
531  >
532 struct is_adaptable_input_device : std::false_type{};
533 
534 template <typename FormatTag, typename T>
535 struct is_adaptable_input_device
536 <
537  FormatTag,
538  T,
539  typename std::enable_if
540  <
541  mp11::mp_or
542  <
543  std::is_base_of<std::istream, T>,
544  std::is_same<std::istream, T>
545  >::value
546  >::type
547 > : std::true_type
548 {
549  using device_type = istream_device<FormatTag>;
550 };
551 
552 template< typename FormatTag >
553 struct is_adaptable_input_device< FormatTag
554  , FILE*
555  , void
556  >
557  : std::true_type
558 {
559  using device_type = file_stream_device<FormatTag>;
560 };
561 
565 template< typename FormatTag
566  , typename T
567  , typename D = void
568  >
569 struct is_read_device : std::false_type
570 {};
571 
572 template <typename FormatTag, typename T>
573 struct is_read_device
574 <
575  FormatTag,
576  T,
577  typename std::enable_if
578  <
579  mp11::mp_or
580  <
581  is_input_device<FormatTag>,
582  is_adaptable_input_device<FormatTag, T>
583  >::value
584  >::type
585 > : std::true_type
586 {
587 };
588 
589 
594 template<typename IODevice> struct is_output_device : std::false_type{};
595 
596 template< typename FormatTag > struct is_output_device< file_stream_device< FormatTag > > : std::true_type{};
597 template< typename FormatTag > struct is_output_device< ostream_device < FormatTag > > : std::true_type{};
598 
599 template< typename FormatTag
600  , typename IODevice
601  , typename D = void
602  >
603 struct is_adaptable_output_device : std::false_type {};
604 
605 template <typename FormatTag, typename T>
606 struct is_adaptable_output_device
607 <
608  FormatTag,
609  T,
610  typename std::enable_if
611  <
612  mp11::mp_or
613  <
614  std::is_base_of<std::ostream, T>,
615  std::is_same<std::ostream, T>
616  >::value
617  >::type
618 > : std::true_type
619 {
620  using device_type = ostream_device<FormatTag>;
621 };
622 
623 template<typename FormatTag> struct is_adaptable_output_device<FormatTag,FILE*,void>
624  : std::true_type
625 {
626  using device_type = file_stream_device<FormatTag>;
627 };
628 
629 
633 template< typename FormatTag
634  , typename T
635  , typename D = void
636  >
637 struct is_write_device : std::false_type
638 {};
639 
640 template <typename FormatTag, typename T>
641 struct is_write_device
642 <
643  FormatTag,
644  T,
645  typename std::enable_if
646  <
647  mp11::mp_or
648  <
649  is_output_device<FormatTag>,
650  is_adaptable_output_device<FormatTag, T>
651  >::value
652  >::type
653 > : std::true_type
654 {
655 };
656 
657 } // namespace detail
658 
659 template< typename Device, typename FormatTag > class scanline_reader;
660 template< typename Device, typename FormatTag, typename ConversionPolicy > class reader;
661 
662 template< typename Device, typename FormatTag, typename Log = no_log > class writer;
663 
664 template< typename Device, typename FormatTag > class dynamic_image_reader;
665 template< typename Device, typename FormatTag, typename Log = no_log > class dynamic_image_writer;
666 
667 
668 namespace detail {
669 
670 template< typename T >
671 struct is_reader : std::false_type
672 {};
673 
674 template< typename Device
675  , typename FormatTag
676  , typename ConversionPolicy
677  >
678 struct is_reader< reader< Device
679  , FormatTag
680  , ConversionPolicy
681  >
682  > : std::true_type
683 {};
684 
685 template< typename T >
686 struct is_dynamic_image_reader : std::false_type
687 {};
688 
689 template< typename Device
690  , typename FormatTag
691  >
692 struct is_dynamic_image_reader< dynamic_image_reader< Device
693  , FormatTag
694  >
695  > : std::true_type
696 {};
697 
698 template< typename T >
699 struct is_writer : std::false_type
700 {};
701 
702 template< typename Device
703  , typename FormatTag
704  >
705 struct is_writer< writer< Device
706  , FormatTag
707  >
708  > : std::true_type
709 {};
710 
711 template< typename T >
712 struct is_dynamic_image_writer : std::false_type
713 {};
714 
715 template< typename Device
716  , typename FormatTag
717  >
718 struct is_dynamic_image_writer< dynamic_image_writer< Device
719  , FormatTag
720  >
721  > : std::true_type
722 {};
723 
724 } // namespace detail
725 
726 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
727 #pragma warning(pop)
728 #endif
729 
730 } // namespace gil
731 } // namespace boost
732 
733 #endif
file_stream_device(const std::string &file_name, read_tag tag=read_tag())
Definition: device.hpp:63
void write_uint32(uint32_t x)
Writes 32 bit little endian integer.
Definition: device.hpp:244
void print_line(const std::string &line)
Prints formatted ASCII text.
Definition: device.hpp:283
void write_uint8(uint8_t x)
Writes byte.
Definition: device.hpp:226
void read(T(&buf)[N])
Reads array.
Definition: device.hpp:164
file_stream_device(FILE *file)
Definition: device.hpp:117
uint16_t read_uint16()
Reads 16 bit little endian integer.
Definition: device.hpp:181
uint8_t read_uint8()
Reads byte.
Definition: device.hpp:172
file_stream_device(const char *file_name, write_tag)
Definition: device.hpp:99
auto read(byte_t *data, std::size_t count) -> std::size_t
Definition: device.hpp:143
file_stream_device(const std::string &file_name, write_tag tag)
Definition: device.hpp:90
void write(const T(&buf)[N])
Writes array.
Definition: device.hpp:217
file_stream_device(const char *file_name, read_tag=read_tag())
Definition: device.hpp:72
uint32_t read_uint32()
Reads 32 bit little endian integer.
Definition: device.hpp:190
void write_uint16(uint16_t x)
Writes 16 bit little endian integer.
Definition: device.hpp:233
auto write(T const *buf, std::size_t count) -> std::size_t
Writes number of elements from a buffer.
Definition: device.hpp:200
Definition: device.hpp:322
void read(T(&buf)[N])
Reads array.
Definition: device.hpp:371
uint16_t read_uint16()
Reads 16 bit little endian integer.
Definition: device.hpp:386
uint8_t read_uint8()
Reads byte.
Definition: device.hpp:377
uint32_t read_uint32()
Reads 32 bit little endian integer.
Definition: device.hpp:395
Definition: device.hpp:429
void write_uint32(uint32_t x)
Writes 32 bit little endian integer.
Definition: device.hpp:489
void print_line(const std::string &line)
Prints formatted ASCII text.
Definition: device.hpp:507
void write_uint8(uint8_t x)
Writes byte.
Definition: device.hpp:471
void write(const T(&buf)[N])
Writes array.
Definition: device.hpp:465
void write_uint16(uint16_t x)
Writes 16 bit little endian integer.
Definition: device.hpp:478
defined(BOOST_NO_CXX17_HDR_MEMORY_RESOURCE)
Definition: algorithm.hpp:36
Used to overload the constructor.
Definition: device.hpp:57
Definition: device.hpp:524
Definition: device.hpp:594
Definition: device.hpp:570
Definition: device.hpp:638