00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 #ifndef CGATOOLS_UTIL_STREAMS_HPP_
00016 #define CGATOOLS_UTIL_STREAMS_HPP_ 1
00017 
00021 
00022 #include "cgatools/core.hpp"
00023 #include "cgatools/util/Exception.hpp"
00024 
00025 #include <boost/shared_ptr.hpp>
00026 #include <boost/iostreams/stream.hpp>
00027 #include <boost/iostreams/filtering_stream.hpp>
00028 
00029 namespace cgatools { namespace util {
00030 
00031     
00032     
00033     
00034     class  FileDescriptorDevice {
00035     public:
00036 #ifdef CGA_USE_WIN_API
00037         typedef void*  handle_type;  
00038 #else
00039         typedef int    handle_type;
00040 #endif
00041         typedef char   char_type;
00042         struct category
00043             : boost::iostreams::seekable_device_tag,
00044               boost::iostreams::closable_tag
00045             { };
00046         FileDescriptorDevice();
00047         explicit FileDescriptorDevice(handle_type fd, bool close_on_exit = false);
00048 
00049         explicit FileDescriptorDevice( const std::string& path,
00050                                   BOOST_IOS::openmode mode =
00051                                       BOOST_IOS::in | BOOST_IOS::out,
00052                                   BOOST_IOS::openmode base_mode =
00053                                       BOOST_IOS::in | BOOST_IOS::out );
00054         explicit FileDescriptorDevice( const char* path,
00055                                   BOOST_IOS::openmode mode =
00056                                       BOOST_IOS::in | BOOST_IOS::out,
00057                                   BOOST_IOS::openmode base_mode =
00058                                       BOOST_IOS::in | BOOST_IOS::out );
00059         void open( const std::string& path,
00060                    BOOST_IOS::openmode =
00061                        BOOST_IOS::in | BOOST_IOS::out,
00062                    BOOST_IOS::openmode base_mode =
00063                        BOOST_IOS::in | BOOST_IOS::out );
00064         void open( const char* path,
00065                    BOOST_IOS::openmode =
00066                        BOOST_IOS::in | BOOST_IOS::out,
00067                    BOOST_IOS::openmode base_mode =
00068                        BOOST_IOS::in | BOOST_IOS::out );
00069         bool is_open() const { return pimpl_->flags_ != 0; }
00070         std::streamsize read(char_type* s, std::streamsize n);
00071         std::streamsize write(const char_type* s, std::streamsize n);
00072         std::streampos seek(boost::iostreams::stream_offset off, BOOST_IOS::seekdir way);
00073         bool fsync();
00074         void close();
00075         handle_type handle() const { return pimpl_->handle_; }
00076         const std::string& fn() const { return pimpl_->fn_; }
00077     private:
00078         struct impl {
00079             impl() :
00080 #ifdef CGA_USE_WIN_API
00081                     handle_(reinterpret_cast<handle_type>(-1)),
00082 #else
00083                     handle_(-1),
00084 #endif
00085                     flags_(0)
00086                 { }
00087 
00088             impl(handle_type fd, bool close_on_exit)
00089                 : fn_("<handle>"), handle_(fd), flags_(0)
00090             {
00091                 if (close_on_exit) flags_ |= impl::close_on_exit;
00092             }
00093 
00094             ~impl()
00095             {
00096                 if (flags_ & close_on_exit) close_impl(*this);
00097             }
00098             enum flags {
00099                 close_on_exit = 1,
00100                 append = 4,
00101                 flushable = 8
00102             };
00103             std::string  fn_;
00104             handle_type  handle_;
00105             int          flags_;
00106         };
00107         friend struct impl;
00108 
00109         static void close_impl(impl&);
00110         static void fsync_impl(impl&);
00111 
00112         boost::shared_ptr<impl> pimpl_;
00113     };
00114 
00115     struct FileSourceDevice : private FileDescriptorDevice {
00116         typedef FileDescriptorDevice::handle_type handle_type;
00117         typedef char   char_type;
00118         struct category
00119           : boost::iostreams::input_seekable,
00120             boost::iostreams::device_tag,
00121             boost::iostreams::closable_tag
00122           { };
00123         using FileDescriptorDevice::read;
00124         using FileDescriptorDevice::seek;
00125         using FileDescriptorDevice::open;
00126         using FileDescriptorDevice::is_open;
00127         using FileDescriptorDevice::close;
00128         using FileDescriptorDevice::handle;
00129         FileSourceDevice() { }
00130         explicit FileSourceDevice(handle_type fd, bool close_on_exit = false)
00131             : FileDescriptorDevice(fd, close_on_exit)
00132             { }
00133 
00134         explicit FileSourceDevice( const std::string& path,
00135                                          BOOST_IOS::openmode m = BOOST_IOS::in )
00136             : FileDescriptorDevice(path, m & ~BOOST_IOS::out, BOOST_IOS::in)
00137             { }
00138         explicit FileSourceDevice( const char* path,
00139                                          BOOST_IOS::openmode m = BOOST_IOS::in )
00140             : FileDescriptorDevice(path, m & ~BOOST_IOS::out, BOOST_IOS::in)
00141             { }
00142     };
00143 
00144     struct FileSinkDevice : private FileDescriptorDevice {
00145         typedef FileDescriptorDevice::handle_type handle_type;
00146         typedef char   char_type;
00147         struct category
00148           : boost::iostreams::output_seekable,
00149             boost::iostreams::device_tag,
00150             boost::iostreams::closable_tag
00151             
00152             
00153           { };
00154         using FileDescriptorDevice::write;
00155         using FileDescriptorDevice::seek;
00156         using FileDescriptorDevice::open;
00157         using FileDescriptorDevice::is_open;
00158         using FileDescriptorDevice::close;
00159         using FileDescriptorDevice::handle;
00160         using FileDescriptorDevice::fsync;
00161         FileSinkDevice() { }
00162         explicit FileSinkDevice(handle_type fd, bool close_on_exit = false)
00163             : FileDescriptorDevice(fd, close_on_exit)
00164             { }
00165         explicit FileSinkDevice( const std::string& path,
00166                                        BOOST_IOS::openmode m = BOOST_IOS::out )
00167             : FileDescriptorDevice(path, m & ~BOOST_IOS::in, BOOST_IOS::out)
00168             { }
00169         explicit FileSinkDevice( const char* path,
00170                                        BOOST_IOS::openmode m = BOOST_IOS::out )
00171             : FileDescriptorDevice(path, m & ~BOOST_IOS::in, BOOST_IOS::out)
00172             { }
00173     };
00174 
00176     class InputStream:
00177         public boost::iostreams::stream<FileSourceDevice>
00178     {
00179     public:
00180         InputStream() {}
00181         InputStream(const char* fn)
00182         {
00183             open(fn);
00184         }
00185 
00186         InputStream(const std::string& fn)
00187         {
00188             open(fn);
00189         }
00190 
00191         void open(const std::string& fn)
00192         {
00193             open(fn.c_str());
00194         }
00195         void open(const char* fn);
00196 
00197         void close()
00198         {
00199             if (is_open()) {
00200                 base_type::close();
00201             }
00202         }
00203 
00210         static boost::shared_ptr<std::istream>
00211         openCompressedInputStreamByExtension(const std::string& fn);
00212 
00215         static bool getline(std::istream& in, std::string& line);
00216 
00217     private:
00218         typedef boost::iostreams::stream<FileSourceDevice> base_type;
00219     };
00220 
00235     class OutputStream:
00236         public boost::iostreams::stream<FileSinkDevice>
00237     {
00238     public:
00239         OutputStream() {}
00240         OutputStream(const char* fn)
00241         {
00242             open(fn);
00243         }
00244         OutputStream(const std::string& fn)
00245         {
00246             open(fn);
00247         }
00248         ~OutputStream();
00249 
00250         void open(const std::string& fn)
00251         {
00252             open(fn.c_str());
00253         }
00254         void open(const char* fn);
00255 
00256         void close()
00257         {
00258             if (is_open()) {
00259                 base_type::close();
00260             }
00261         }
00262 
00269         static boost::shared_ptr<std::ostream>
00270         openCompressedOutputStreamByExtension(const std::string& fn);
00271     private:
00272         typedef boost::iostreams::stream<FileSinkDevice> base_type;
00273     };
00274 
00275     class CompressedInputStream:
00276         public boost::iostreams::filtering_istream
00277     {
00278     public:
00279         CompressedInputStream() {}
00280         CompressedInputStream(const char* fn)
00281         {
00282             open(fn);
00283         }
00284         CompressedInputStream(const std::string& fn)
00285         {
00286             open(fn);
00287         }
00288 
00290         void open(const std::string& fn)
00291         {
00292             open(fn.c_str());
00293         }
00295         void open(const char* fn);
00297         void openBZ2(const std::string& fn)
00298         {
00299             openBZ2(fn.c_str());
00300         }
00302         void openBZ2(const char* fn);
00303 
00304         void close()
00305         {
00306             reset();
00307         }
00308     private:
00309         typedef boost::iostreams::filtering_istream base_type;
00310     };
00311 
00312     class CompressedOutputStream:
00313         public boost::iostreams::filtering_ostream
00314     {
00315     public:
00316         static const int DEFAULT_COMPRESSION = 4;
00317 
00318         CompressedOutputStream() {}
00319         CompressedOutputStream(const char* fn, int clev = DEFAULT_COMPRESSION)
00320         {
00321             open(fn, clev);
00322         }
00323         CompressedOutputStream(const std::string& fn, int clev = DEFAULT_COMPRESSION)
00324         {
00325             open(fn, clev);
00326         }
00327 
00328         ~CompressedOutputStream();
00329 
00331         void open(const std::string& fn, int clev = DEFAULT_COMPRESSION)
00332         {
00333             open(fn.c_str(), clev);
00334         }
00336         void open(const char* fn, int clev = DEFAULT_COMPRESSION);
00338         void openBZ2(const std::string& fn)
00339         {
00340             openBZ2(fn.c_str());
00341         }
00343         void openBZ2(const char* fn);
00344 
00345         void close()
00346         {
00347             reset();
00348         }
00349     private:
00350         typedef boost::iostreams::filtering_ostream base_type;
00351     };
00352 
00354     void writeBinaryBool(std::ostream& out, bool val);
00355 
00357     template <class IntType>
00358     void writeBinaryInt(std::ostream& out, IntType val)
00359     {
00360         for(int ii=sizeof(val)*8-8; ii>=0; ii-=8)
00361         {
00362             char ch = (val >> ii) & 0xff;
00363             out.put(ch);
00364         }
00365     }
00366 
00370     template <class IntType>
00371     void writeBinaryUIntZC(std::ostream& out, IntType val)
00372     {
00373         char bytes[sizeof(val)*2];
00374         char* ptr = bytes + sizeof(bytes);
00375         char flag = 0;
00376         for(;;)
00377         {
00378             char ch = (val & 0x7f) | flag;
00379             val >>= 7;
00380             if (0 == val)
00381             {
00382                 *--ptr = ch;
00383                 break;
00384             }
00385             flag = char(0x80);
00386             *--ptr = ch;
00387         }
00388 
00389         out.write(ptr, bytes+sizeof(bytes)-ptr);
00390     }
00391 
00394     void writeBinaryString(std::ostream& out, const std::string& val);
00395 
00398     void readBinaryBool(std::istream& in, bool* val);
00399 
00401     template <class IntType>
00402     void readBinaryInt(std::istream& in, IntType* pVal)
00403     {
00404         IntType& val = *pVal;
00405         val = 0;
00406         for(size_t ii=0; ii<sizeof(val); ii++)
00407         {
00408             char ch;
00409             in.get(ch);
00410             if (!in.good())
00411                 throw Exception("failed to read binary int: unexpected eof");
00412 
00413             val <<= 8;
00414             val |= static_cast<uint8_t>(ch);
00415         }
00416     }
00417     
00422     template <class IntType>
00423     void readBinaryUIntZC(std::istream& in, IntType* pVal)
00424     {
00425         IntType& val = *pVal;
00426         IntType MAX_VAL = std::numeric_limits<IntType>::max() >> 7;
00427         val = 0;
00428         for(;;)
00429         {
00430             int ch = in.get();
00431             if (!in.good())
00432                 throw Exception("failed to read zero-compressed binary int: unexpected eof");
00433             val |= ch & 0x7f;
00434             if ( 0 == (ch & 0x80) )
00435                 break;
00436             if (val > MAX_VAL)
00437                 throw Exception("failed to read zero-compressed binary int: overflow");
00438             val <<= 7;
00439         }
00440     }
00441 
00443     void readBinaryString(std::istream& in, std::string* val);
00444 
00445 } } 
00446 
00447 #endif // CGATOOLS_UTIL_STREAMS_HPP_