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