Boost logo

Boost Users :

From: Sascha Ochsenknecht (s.ochsenknecht_at_[hidden])
Date: 2007-04-23 12:39:35


Hi,

I made a library which gets an std::ifstream and read a certain file
format. Now I would like to support also gzip compressed input files,
but it should also support not compressed files.
I used boost::iostreams to implement a new stream class which should
replace the std::ifstream in my library.

Following functions are called from std::ifstream:
- std::ifstream(const char*)
- read(...)
- seek(...)
- close(...)

My question is, is everything done correctly or is there a more elegant
way to implement this?

I'm not a stream expert, so I doubt if I do it in a good way :-).
Would be great if someone from the experts can have a look to it and
review it.

Thanks in advance,
Sascha

I derived my class from boost::iostreams::filtering_istream, here is my
implementation:

#ifndef PAT_INPUTSTREAM_H
#define PAT_INPUTSTREAM_H

#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/filtering_stream.hpp>

#include <string>

namespace my {

namespace io = boost::iostreams;

/*! Check if a given file is a (gzipped-)compressed format
      It is using functions from zlib
*/
bool isCompressed(const char* p_name);

/*! \class ifstream

      Special input stream to handle compressed files.

      After opening an my::ifstream, it should be checked with is_open()
      if it is openend correctly.
*/
class ifstream : public io::filtering_istream {

   private:
   std::string _name; // the filename is needed for re-opening in seek()

   public:

   ifstream(const char* p_name) : _name(p_name) {
      if (isCompressed(p_name)) {
         io::filtering_istream::push(io::gzip_decompressor());
         io::filtering_istream::push(io::file_source(p_name,
std::ios::binary));
      } else {
         io::filtering_istream::push(io::file_source(p_name));
      }
   }

   bool open(const char* p_name) {

      if (!is_open()) {
         _name = p_name;
         if (isCompressed(p_name)) {
            io::filtering_istream::push(io::gzip_decompressor());
            io::filtering_istream::push(io::file_source(p_name,
std::ios::binary));
         } else {
            io::filtering_istream::push(io::file_source(p_name));
         }
      }
      return is_open();
   }

   void close() {
      if (is_open()) {
         while (io::filtering_istream::size()) {
            io::filtering_istream::pop();
         }
      }
   }

   bool is_open() {
      if (io::filtering_istream::size()) {
         // the last components is the file device
         io::file_source* device =

io::filtering_istream::component<io::file_source>(io::filtering_istream::size()-1);
         if (device)
            return device->is_open();
      }
      return false;
   }

   ifstream& seekg(std::streampos p_pos) {
      // seek means close the stream
      // and read until position is reached were we
      // want to be

      if (is_open()) {
         close();

         if (open(_name.c_str())) {
            const std::streampos PAT_BLOCK_SIZE = 1024;

            char* buf = new char[PAT_BLOCK_SIZE];
            while (p_pos) {
               if (p_pos / PAT_BLOCK_SIZE) {
                  read(buf, PAT_BLOCK_SIZE);
                  p_pos -= PAT_BLOCK_SIZE;
               } else {
                  read(buf, p_pos % PAT_BLOCK_SIZE);
                  p_pos -= (p_pos % PAT_BLOCK_SIZE);
               }
            }

            delete [] buf;
         }
      }
      return *this;
   }
};

} // end of namespace pat

#endif


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net