Boost GIL


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