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
00204 static bool isReadable(const std::string& fn);
00205
00212 static boost::shared_ptr<std::istream>
00213 openCompressedInputStreamByExtension(const std::string& fn);
00214
00217 static bool getline(std::istream& in, std::string& line);
00218
00219 private:
00220 typedef boost::iostreams::stream<FileSourceDevice> base_type;
00221 };
00222
00237 class OutputStream:
00238 public boost::iostreams::stream<FileSinkDevice>
00239 {
00240 public:
00241 OutputStream() {}
00242 OutputStream(const char* fn)
00243 {
00244 open(fn);
00245 }
00246 OutputStream(const std::string& fn)
00247 {
00248 open(fn);
00249 }
00250 ~OutputStream();
00251
00252 void open(const std::string& fn)
00253 {
00254 open(fn.c_str());
00255 }
00256 void open(const char* fn);
00257
00258 void close()
00259 {
00260 if (is_open()) {
00261 base_type::close();
00262 }
00263 }
00264
00271 static boost::shared_ptr<std::ostream>
00272 openCompressedOutputStreamByExtension(const std::string& fn);
00273 private:
00274 typedef boost::iostreams::stream<FileSinkDevice> base_type;
00275 };
00276
00277 class CompressedInputStream:
00278 public boost::iostreams::filtering_istream
00279 {
00280 public:
00281 CompressedInputStream() {}
00282 CompressedInputStream(const char* fn)
00283 {
00284 open(fn);
00285 }
00286 CompressedInputStream(const std::string& fn)
00287 {
00288 open(fn);
00289 }
00290
00292 void open(const std::string& fn)
00293 {
00294 open(fn.c_str());
00295 }
00297 void open(const char* fn);
00299 void openBZ2(const std::string& fn)
00300 {
00301 openBZ2(fn.c_str());
00302 }
00304 void openBZ2(const char* fn);
00305
00306 void close()
00307 {
00308 reset();
00309 }
00310 private:
00311 typedef boost::iostreams::filtering_istream base_type;
00312 };
00313
00314 class CompressedOutputStream:
00315 public boost::iostreams::filtering_ostream
00316 {
00317 public:
00318 static const int DEFAULT_COMPRESSION = 4;
00319
00320 CompressedOutputStream() {}
00321 CompressedOutputStream(const char* fn, int clev = DEFAULT_COMPRESSION)
00322 {
00323 open(fn, clev);
00324 }
00325 CompressedOutputStream(const std::string& fn, int clev = DEFAULT_COMPRESSION)
00326 {
00327 open(fn, clev);
00328 }
00329
00330 ~CompressedOutputStream();
00331
00333 void open(const std::string& fn, int clev = DEFAULT_COMPRESSION)
00334 {
00335 open(fn.c_str(), clev);
00336 }
00338 void open(const char* fn, int clev = DEFAULT_COMPRESSION);
00340 void openBZ2(const std::string& fn)
00341 {
00342 openBZ2(fn.c_str());
00343 }
00345 void openBZ2(const char* fn);
00346
00347 void close()
00348 {
00349 reset();
00350 }
00351 private:
00352 typedef boost::iostreams::filtering_ostream base_type;
00353 };
00354
00356 void writeBinaryBool(std::ostream& out, bool val);
00357
00359 template <class IntType>
00360 void writeBinaryInt(std::ostream& out, IntType val)
00361 {
00362 for(int ii=sizeof(val)*8-8; ii>=0; ii-=8)
00363 {
00364 char ch = (val >> ii) & 0xff;
00365 out.put(ch);
00366 }
00367 }
00368
00372 template <class IntType>
00373 void writeBinaryUIntZC(std::ostream& out, IntType val)
00374 {
00375 char bytes[sizeof(val)*2];
00376 char* ptr = bytes + sizeof(bytes);
00377 char flag = 0;
00378 for(;;)
00379 {
00380 char ch = (val & 0x7f) | flag;
00381 val >>= 7;
00382 if (0 == val)
00383 {
00384 *--ptr = ch;
00385 break;
00386 }
00387 flag = char(0x80);
00388 *--ptr = ch;
00389 }
00390
00391 out.write(ptr, bytes+sizeof(bytes)-ptr);
00392 }
00393
00396 void writeBinaryString(std::ostream& out, const std::string& val);
00397
00400 void readBinaryBool(std::istream& in, bool* val);
00401
00403 template <class IntType>
00404 void readBinaryInt(std::istream& in, IntType* pVal)
00405 {
00406 IntType& val = *pVal;
00407 val = 0;
00408 for(size_t ii=0; ii<sizeof(val); ii++)
00409 {
00410 char ch;
00411 in.get(ch);
00412 if (!in.good())
00413 throw Exception("failed to read binary int: unexpected eof");
00414
00415 val <<= 8;
00416 val |= static_cast<uint8_t>(ch);
00417 }
00418 }
00419
00424 template <class IntType>
00425 void readBinaryUIntZC(std::istream& in, IntType* pVal)
00426 {
00427 IntType& val = *pVal;
00428 IntType MAX_VAL = std::numeric_limits<IntType>::max() >> 7;
00429 val = 0;
00430 for(;;)
00431 {
00432 int ch = in.get();
00433 if (!in.good())
00434 throw Exception("failed to read zero-compressed binary int: unexpected eof");
00435 val |= ch & 0x7f;
00436 if ( 0 == (ch & 0x80) )
00437 break;
00438 if (val > MAX_VAL)
00439 throw Exception("failed to read zero-compressed binary int: overflow");
00440 val <<= 7;
00441 }
00442 }
00443
00445 void readBinaryString(std::istream& in, std::string* val);
00446
00447 } }
00448
00449 #endif // CGATOOLS_UTIL_STREAMS_HPP_