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_