1 /** 2 * @file bzfstream.h 3 * @brief C++ I/O streams interface to the bzlib bz* functions 4 * @author Akiya Jouraku 5 * 6 * <!-------------------------------------------------------------------------- 7 * This file is part of libSBML. Please visit http://sbml.org for more 8 * information about SBML, and the latest version of libSBML. 9 * 10 * Copyright (C) 2020 jointly by the following organizations: 11 * 1. California Institute of Technology, Pasadena, CA, USA 12 * 2. University of Heidelberg, Heidelberg, Germany 13 * 3. University College London, London, UK 14 * 15 * Copyright (C) 2019 jointly by the following organizations: 16 * 1. California Institute of Technology, Pasadena, CA, USA 17 * 2. University of Heidelberg, Heidelberg, Germany 18 * 19 * Copyright (C) 2013-2018 jointly by the following organizations: 20 * 1. California Institute of Technology, Pasadena, CA, USA 21 * 2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK 22 * 3. University of Heidelberg, Heidelberg, Germany 23 * 24 * Copyright (C) 2009-2013 jointly by the following organizations: 25 * 1. California Institute of Technology, Pasadena, CA, USA 26 * 2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK 27 * 28 * Copyright (C) 2006-2008 by the California Institute of Technology, 29 * Pasadena, CA, USA 30 * 31 * Copyright (C) 2002-2005 jointly by the following organizations: 32 * 1. California Institute of Technology, Pasadena, CA, USA 33 * 2. Japan Science and Technology Agency, Japan 34 * 35 * This library is free software; you can redistribute it and/or modify it 36 * under the terms of the GNU Lesser General Public License as published by 37 * the Free Software Foundation. A copy of the license agreement is provided 38 * in the file named "LICENSE.txt" included with this software distribution 39 * and also available online as http://sbml.org/software/libsbml/license.html 40 * ------------------------------------------------------------------------- --> 41 * 42 * Most of the code (except for bzip2 specific code) is based on zfstream.h 43 * implemented by Ludwig Schwardt <schwardt@sun.ac.za> 44 * original version by Kevin Ruland <kevin@rodin.wustl.edu> 45 * zfstream.h is contained in the contributed samples in zlib version 1.2.3 46 * (http://www.zlib.net). 47 * 48 * ---------------------------------------------------------------------- -->*/ 49 50 51 #ifndef BZFSTREAM_H 52 #define BZFSTREAM_H 53 54 #include <istream> // not iostream, since we don't need cin/cout 55 #include <ostream> 56 #include "bzlib.h" 57 58 /*****************************************************************************/ 59 60 /** 61 * @brief bzip2 file stream buffer class. 62 * 63 * This class implements basic_filebuf for bzip2 files. It doesn't yet support 64 * seeking (allowed by zlib but slow/limited), putback and read/write access 65 * (tricky). Otherwise, it attempts to be a drop-in replacement for the standard 66 * file streambuf. 67 */ 68 class bzfilebuf : public std::streambuf 69 { 70 public: 71 // Default constructor. 72 bzfilebuf(); 73 74 // Destructor. 75 virtual 76 ~bzfilebuf(); 77 78 /** 79 * @brief Check if file is open. 80 * @return True if file is open. 81 */ 82 bool is_open()83 is_open() const { return (file != NULL); } 84 85 /** 86 * @brief Open bzip2 file. 87 * @param name File name. 88 * @param mode Open mode flags. 89 * @return @c this on success, NULL on failure. 90 */ 91 bzfilebuf* 92 open(const char* name, 93 std::ios_base::openmode mode); 94 95 /** 96 * @brief Attach to already open bzip2 file. 97 * @param fd File descriptor. 98 * @param mode Open mode flags. 99 * @return @c this on success, NULL on failure. 100 */ 101 bzfilebuf* 102 attach(int fd, 103 std::ios_base::openmode mode); 104 105 /** 106 * @brief Close bzip2 file. 107 * @return @c this on success, NULL on failure. 108 */ 109 bzfilebuf* 110 close(); 111 112 protected: 113 /** 114 * @brief Convert ios open mode int to mode string used by zlib. 115 * @return True if valid mode flag combination. 116 */ 117 bool 118 open_mode(std::ios_base::openmode mode, 119 char* c_mode) const; 120 121 /** 122 * @brief Number of characters available in stream buffer. 123 * @return Number of characters. 124 * 125 * This indicates number of characters in get area of stream buffer. 126 * These characters can be read without accessing the bzip2 file. 127 */ 128 virtual std::streamsize 129 showmanyc(); 130 131 /** 132 * @brief Fill get area from bzip2 file. 133 * @return First character in get area on success, EOF on error. 134 * 135 * This actually reads characters from bzip2 file to stream 136 * buffer. Always buffered. 137 */ 138 virtual int_type 139 underflow(); 140 141 /** 142 * @brief Write put area to bzip2 file. 143 * @param c Extra character to add to buffer contents. 144 * @return Non-EOF on success, EOF on error. 145 * 146 * This actually writes characters in stream buffer to 147 * bzip2 file. With unbuffered output this is done one 148 * character at a time. 149 */ 150 virtual int_type 151 overflow(int_type c = std::streambuf::traits_type::eof()); 152 153 /** 154 * @brief Installs external stream buffer. 155 * @param p Pointer to char buffer. 156 * @param n Size of external buffer. 157 * @return @c this on success, NULL on failure. 158 * 159 * Call setbuf(0,0) to enable unbuffered output. 160 */ 161 virtual std::streambuf* 162 setbuf(char_type* p, 163 std::streamsize n); 164 165 /** 166 * @brief Flush stream buffer to file. 167 * @return 0 on success, -1 on error. 168 * 169 * This calls underflow(EOF) to do the job. 170 */ 171 virtual int 172 sync(); 173 174 // 175 // Some future enhancements 176 // 177 // virtual int_type uflow(); 178 // virtual int_type pbackfail(int_type c = traits_type::eof()); 179 // virtual pos_type 180 // seekoff(off_type off, 181 // std::ios_base::seekdir way, 182 // std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out); 183 // virtual pos_type 184 // seekpos(pos_type sp, 185 // std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out); 186 187 private: 188 /** 189 * @brief Allocate internal buffer. 190 * 191 * This function is safe to call multiple times. It will ensure 192 * that a proper internal buffer exists if it is required. If the 193 * buffer already exists or is external, the buffer pointers will be 194 * reset to their original state. 195 */ 196 void 197 enable_buffer(); 198 199 /** 200 * @brief Destroy internal buffer. 201 * 202 * This function is safe to call multiple times. It will ensure 203 * that the internal buffer is deallocated if it exists. In any 204 * case, it will also reset the buffer pointers. 205 */ 206 void 207 disable_buffer(); 208 209 /** 210 * Underlying file pointer. 211 */ 212 BZFILE* file; 213 214 /** 215 * Mode in which file was opened. 216 */ 217 std::ios_base::openmode io_mode; 218 219 /** 220 * @brief True if this object owns file descriptor. 221 * 222 * This makes the class responsible for closing the file 223 * upon destruction. 224 */ 225 bool own_fd; 226 227 /** 228 * @brief Stream buffer. 229 * 230 * For simplicity this remains allocated on the free store for the 231 * entire life span of the bzfilebuf object, unless replaced by setbuf. 232 */ 233 char_type* buffer; 234 235 /** 236 * @brief Stream buffer size. 237 * 238 * Defaults to system default buffer size (typically 8192 bytes). 239 * Modified by setbuf. 240 */ 241 std::streamsize buffer_size; 242 243 /** 244 * @brief True if this object owns stream buffer. 245 * 246 * This makes the class responsible for deleting the buffer 247 * upon destruction. 248 */ 249 bool own_buffer; 250 }; 251 252 /*****************************************************************************/ 253 254 /** 255 * @brief bzip2 file input stream class. 256 * 257 * This class implements ifstream for bzip2 files. Seeking and putback 258 * is not supported yet. 259 */ 260 class bzifstream : public std::istream 261 { 262 public: 263 // Default constructor 264 bzifstream(); 265 266 /** 267 * @brief Construct stream on bzip2 file to be opened. 268 * @param name File name. 269 * @param mode Open mode flags (forced to contain ios::in). 270 */ 271 explicit 272 bzifstream(const char* name, 273 std::ios_base::openmode mode = std::ios_base::in); 274 275 /** 276 * @brief Construct stream on already open bzip2 file. 277 * @param fd File descriptor. 278 * @param mode Open mode flags (forced to contain ios::in). 279 */ 280 explicit 281 bzifstream(int fd, 282 std::ios_base::openmode mode = std::ios_base::in); 283 284 /** 285 * Obtain underlying stream buffer. 286 */ 287 bzfilebuf* rdbuf()288 rdbuf() const 289 { return const_cast<bzfilebuf*>(&sb); } 290 291 /** 292 * @brief Check if file is open. 293 * @return True if file is open. 294 */ 295 bool is_open()296 is_open() { return sb.is_open(); } 297 298 /** 299 * @brief Open bzip2 file. 300 * @param name File name. 301 * @param mode Open mode flags (forced to contain ios::in). 302 * 303 * Stream will be in state good() if file opens successfully; 304 * otherwise in state fail(). This differs from the behavior of 305 * ifstream, which never sets the state to good() and therefore 306 * won't allow you to reuse the stream for a second file unless 307 * you manually clear() the state. The choice is a matter of 308 * convenience. 309 */ 310 void 311 open(const char* name, 312 std::ios_base::openmode mode = std::ios_base::in); 313 314 /** 315 * @brief Attach to already open bzip2 file. 316 * @param fd File descriptor. 317 * @param mode Open mode flags (forced to contain ios::in). 318 * 319 * Stream will be in state good() if attach succeeded; otherwise 320 * in state fail(). 321 */ 322 void 323 attach(int fd, 324 std::ios_base::openmode mode = std::ios_base::in); 325 326 /** 327 * @brief Close bzip2 file. 328 * 329 * Stream will be in state fail() if close failed. 330 */ 331 void 332 close(); 333 334 private: 335 /** 336 * Underlying stream buffer. 337 */ 338 bzfilebuf sb; 339 }; 340 341 /*****************************************************************************/ 342 343 /** 344 * @brief Gzipped file output stream class. 345 * 346 * This class implements ofstream for bzip2 files. Seeking and putback 347 * is not supported yet. 348 */ 349 class bzofstream : public std::ostream 350 { 351 public: 352 // Default constructor 353 bzofstream(); 354 355 /** 356 * @brief Construct stream on bzip2 file to be opened. 357 * @param name File name. 358 * @param mode Open mode flags (forced to contain ios::out). 359 */ 360 explicit 361 bzofstream(const char* name, 362 std::ios_base::openmode mode = std::ios_base::out); 363 364 /** 365 * @brief Construct stream on already open bzip2 file. 366 * @param fd File descriptor. 367 * @param mode Open mode flags (forced to contain ios::out). 368 */ 369 explicit 370 bzofstream(int fd, 371 std::ios_base::openmode mode = std::ios_base::out); 372 373 /** 374 * Obtain underlying stream buffer. 375 */ 376 bzfilebuf* rdbuf()377 rdbuf() const 378 { return const_cast<bzfilebuf*>(&sb); } 379 380 /** 381 * @brief Check if file is open. 382 * @return True if file is open. 383 */ 384 bool is_open()385 is_open() { return sb.is_open(); } 386 387 /** 388 * @brief Open bzip2 file. 389 * @param name File name. 390 * @param mode Open mode flags (forced to contain ios::out). 391 * 392 * Stream will be in state good() if file opens successfully; 393 * otherwise in state fail(). This differs from the behavior of 394 * ofstream, which never sets the state to good() and therefore 395 * won't allow you to reuse the stream for a second file unless 396 * you manually clear() the state. The choice is a matter of 397 * convenience. 398 */ 399 void 400 open(const char* name, 401 std::ios_base::openmode mode = std::ios_base::out); 402 403 /** 404 * @brief Attach to already open bzip2 file. 405 * @param fd File descriptor. 406 * @param mode Open mode flags (forced to contain ios::out). 407 * 408 * Stream will be in state good() if attach succeeded; otherwise 409 * in state fail(). 410 */ 411 void 412 attach(int fd, 413 std::ios_base::openmode mode = std::ios_base::out); 414 415 /** 416 * @brief Close bzip2 file. 417 * 418 * Stream will be in state fail() if close failed. 419 */ 420 void 421 close(); 422 423 private: 424 /** 425 * Underlying stream buffer. 426 */ 427 bzfilebuf sb; 428 }; 429 430 /*****************************************************************************/ 431 432 /** 433 * @brief Gzipped file output stream manipulator class. 434 * 435 * This class defines a two-argument manipulator for bzofstream. It is used 436 * as base for the setcompression(int,int) manipulator. 437 */ 438 template<typename T1, typename T2> 439 class bzomanip2 440 { 441 public: 442 // Allows insertor to peek at internals 443 template <typename Ta, typename Tb> 444 friend bzofstream& 445 operator<<(bzofstream&, 446 const bzomanip2<Ta,Tb>&); 447 448 // Constructor 449 bzomanip2(bzofstream& (*f)(bzofstream&, T1, T2), 450 T1 v1, 451 T2 v2); 452 private: 453 // Underlying manipulator function 454 bzofstream& 455 (*func)(bzofstream&, T1, T2); 456 457 // Arguments for manipulator function 458 T1 val1; 459 T2 val2; 460 }; 461 462 /*****************************************************************************/ 463 464 465 // Manipulator constructor stores arguments 466 template<typename T1, typename T2> 467 inline bzomanip2(bzofstream & (* f)(bzofstream &,T1,T2),T1 v1,T2 v2)468 bzomanip2<T1,T2>::bzomanip2(bzofstream &(*f)(bzofstream &, T1, T2), 469 T1 v1, 470 T2 v2) 471 : func(f), val1(v1), val2(v2) 472 { } 473 474 // Insertor applies underlying manipulator function to stream 475 template<typename T1, typename T2> 476 inline bzofstream& 477 operator<<(bzofstream& s, const bzomanip2<T1,T2>& m) 478 { return (*m.func)(s, m.val1, m.val2); } 479 480 481 #endif // BZFSTREAM_H 482