Generic Image Library: device.hpp Source File

###  | #  |

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
19namespace 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
26namespace detail {
27
28template < typename T > struct buff_item
29{
30 static const unsigned int size = sizeof( T );
31};
32
33template <> struct buff_item< void >
34{
35 static const unsigned int size = 1;
36};
37
48template< typename FormatTag >
49 class file_stream_device
50{
51public:
52
53 using format_tag_t = FormatTag;
54
55public:
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
302private:
303
304 static void file_deleter( FILE* file )
305 {
306 if( file )
307 {
308 fclose( file );
309 }
310 }
311
312private:
313
314 using file_ptr_t = std::shared_ptr<FILE> ;
315 file_ptr_t _file;
316};
317
321template< typename FormatTag >
322 class istream_device
323{
324public:
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
436private:
437
438 std::istream& _in;
439};
440
444template< typename FormatTag >
445 class ostream_device
446{
447public:
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
545private:
546
547 std::ostream& _out;
548};
549
550
555 template< typename IODevice > struct is_input_device : std::false_type{};
556template< typename FormatTag > struct is_input_device< file_stream_device< FormatTag > > : std::true_type{};
557template< typename FormatTag > struct is_input_device< istream_device< FormatTag > > : std::true_type{};
558
559template< typename FormatTag
560 , typename T
561 , typename D = void
562 >
563struct is_adaptable_input_device : std::false_type{};
564
565template <typename FormatTag, typename T>
566struct 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
583template< typename FormatTag >
584struct 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
596template< typename FormatTag
597 , typename T
598 , typename D = void
599 >
600 struct is_read_device : std::false_type
601{};
602
603template <typename FormatTag, typename T>
604struct 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
627template< typename FormatTag > struct is_output_device< file_stream_device< FormatTag > > : std::true_type{};
628template< typename FormatTag > struct is_output_device< ostream_device < FormatTag > > : std::true_type{};
629
630template< typename FormatTag
631 , typename IODevice
632 , typename D = void
633 >
634struct is_adaptable_output_device : std::false_type {};
635
636template <typename FormatTag, typename T>
637struct 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
654template<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
664template< typename FormatTag
665 , typename T
666 , typename D = void
667 >
668 struct is_write_device : std::false_type
669{};
670
671template <typename FormatTag, typename T>
672struct 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
690template< typename Device, typename FormatTag > class scanline_reader;
691template< typename Device, typename FormatTag, typename ConversionPolicy > class reader;
692
693template< typename Device, typename FormatTag, typename Log = no_log > class writer;
694
695template< typename Device, typename FormatTag > class dynamic_image_reader;
696template< typename Device, typename FormatTag, typename Log = no_log > class dynamic_image_writer;
697
698
699namespace detail {
700
701template< typename T >
702struct is_reader : std::false_type
703{};
704
705template< typename Device
706 , typename FormatTag
707 , typename ConversionPolicy
708 >
709struct is_reader< reader< Device
710 , FormatTag
711 , ConversionPolicy
712 >
713 > : std::true_type
714{};
715
716template< typename T >
717struct is_dynamic_image_reader : std::false_type
718{};
719
720template< typename Device
721 , typename FormatTag
722 >
723struct is_dynamic_image_reader< dynamic_image_reader< Device
724 , FormatTag
725 >
726 > : std::true_type
727{};
728
729template< typename T >
730struct is_writer : std::false_type
731{};
732
733template< typename Device
734 , typename FormatTag
735 >
736struct is_writer< writer< Device
737 , FormatTag
738 >
739 > : std::true_type
740{};
741
742template< typename T >
743struct is_dynamic_image_writer : std::false_type
744{};
745
746template< typename Device
747 , typename FormatTag
748 >
749struct 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
boost::gil::detail::file_stream_device
Definition device.hpp:50
boost::gil::detail::file_stream_device::file_stream_device
file_stream_device(const std::string &file_name, read_tag tag=read_tag())
Definition device.hpp:64
boost::gil::detail::file_stream_device::write_uint32
void write_uint32(uint32_t x)
Writes 32 bit little endian integer.
Definition device.hpp:245
boost::gil::detail::file_stream_device::print_line
void print_line(const std::string &line)
Prints formatted ASCII text.
Definition device.hpp:284
boost::gil::detail::file_stream_device::write_uint8
void write_uint8(uint8_t x)
Writes byte.
Definition device.hpp:227
boost::gil::detail::file_stream_device::read
void read(T(&buf)[N])
Reads array.
Definition device.hpp:165
boost::gil::detail::file_stream_device::file_stream_device
file_stream_device(FILE *file)
Definition device.hpp:118
boost::gil::detail::file_stream_device::read_uint16
uint16_t read_uint16()
Reads 16 bit little endian integer.
Definition device.hpp:182
boost::gil::detail::file_stream_device::read_uint8
uint8_t read_uint8()
Reads byte.
Definition device.hpp:173
boost::gil::detail::file_stream_device::file_stream_device
file_stream_device(const char *file_name, write_tag)
Definition device.hpp:100
boost::gil::detail::file_stream_device::read
auto read(byte_t *data, std::size_t count) -> std::size_t
Definition device.hpp:144
boost::gil::detail::file_stream_device::file_stream_device
file_stream_device(const std::string &file_name, write_tag tag)
Definition device.hpp:91
boost::gil::detail::file_stream_device::write
void write(const T(&buf)[N])
Writes array.
Definition device.hpp:218
boost::gil::detail::file_stream_device::file_stream_device
file_stream_device(const char *file_name, read_tag=read_tag())
Definition device.hpp:73
boost::gil::detail::file_stream_device::read_uint32
uint32_t read_uint32()
Reads 32 bit little endian integer.
Definition device.hpp:191
boost::gil::detail::file_stream_device::write_uint16
void write_uint16(uint16_t x)
Writes 16 bit little endian integer.
Definition device.hpp:234
boost::gil::detail::file_stream_device::write
auto write(T const *buf, std::size_t count) -> std::size_t
Writes number of elements from a buffer.
Definition device.hpp:201
boost::gil::detail::istream_device::read
void read(T(&buf)[N])
Reads array.
Definition device.hpp:372
boost::gil::detail::istream_device::read_uint16
uint16_t read_uint16()
Reads 16 bit little endian integer.
Definition device.hpp:387
boost::gil::detail::istream_device::read_uint8
uint8_t read_uint8()
Reads byte.
Definition device.hpp:378
boost::gil::detail::istream_device::read_uint32
uint32_t read_uint32()
Reads 32 bit little endian integer.
Definition device.hpp:396
boost::gil::detail::ostream_device::write_uint32
void write_uint32(uint32_t x)
Writes 32 bit little endian integer.
Definition device.hpp:517
boost::gil::detail::ostream_device::print_line
void print_line(const std::string &line)
Prints formatted ASCII text.
Definition device.hpp:535
boost::gil::detail::ostream_device::write_uint8
void write_uint8(uint8_t x)
Writes byte.
Definition device.hpp:499
boost::gil::detail::ostream_device::write
void write(const T(&buf)[N])
Writes array.
Definition device.hpp:493
boost::gil::detail::ostream_device::write_uint16
void write_uint16(uint16_t x)
Writes 16 bit little endian integer.
Definition device.hpp:506
boost
defined(BOOST_NO_CXX17_HDR_MEMORY_RESOURCE)
Definition algorithm.hpp:36
boost::gil::type
boost::gil::detail::file_stream_device::read_tag
Used to overload the constructor.
Definition device.hpp:58
boost::gil::detail::is_input_device
Definition device.hpp:555
boost::gil::detail::is_output_device
Definition device.hpp:625
boost::gil::detail::is_read_device
Definition device.hpp:601
boost::gil::detail::is_write_device
Definition device.hpp:669