FACT++  1.0
izstream.h
Go to the documentation of this file.
1 #ifndef MARS_izstream
2 #define MARS_izstream
3 
4 #include <string.h>
5 
6 #include <istream>
7 #include <streambuf>
8 
9 #ifdef __CINT__
10 typedef void *gzFile;
11 #else
12 #include <zlib.h>
13 #endif
14 
15 class izstream : public std::streambuf, public std::istream
16 {
17 private:
18  static const int fgBufferSize = 2048*1024*2;
19 
20  gzFile fFile; // file handle for compressed file
21  char *fBuffer; // data buffer
22 
23  int underflow()
24  {
25  if (gptr() && gptr()<egptr())
26  return * reinterpret_cast<unsigned char *>(gptr());
27 
28  if (!is_open())
29  return EOF;
30 
31  // gptr()-eback(): if more than four bytes are already flushed
32  const int iputback = gptr()-eback()>4 ? 4 : gptr()-eback();
33 
34  // Copy the last four bytes flushed into the putback area
35  memcpy(fBuffer+(4-iputback), gptr()-iputback, iputback);
36 
37  // Fill the buffer starting at the current file position and reset buffer
38  // pointers by calling setg
39  const int num = gzread(fFile, fBuffer+4, fgBufferSize-4);
40  if (num <= 0) // ERROR or EOF
41  return EOF;
42 
43  // reset buffer pointers
44  setg(fBuffer+(4-iputback), fBuffer+4, fBuffer+4+num);
45 
46  // return next character
47  return *reinterpret_cast<unsigned char *>(gptr());
48  }
49 
50 
51 public:
52  izstream() : std::istream(this), fFile(0)
53  {
54  fBuffer = new char[fgBufferSize];
55  setg(fBuffer+4, fBuffer+4, fBuffer+4);
56  }
57  izstream(const char *name) : std::istream(this), fFile(0)
58  {
59  fBuffer = new char[fgBufferSize];
60  setg(fBuffer+4, fBuffer+4, fBuffer+4);
61  open(name);
62  }
63  ~izstream() { izstream::close(); delete [] fBuffer; }
64 
65  int is_open() { return fFile!=0; }
66 
67  // --------------------------------------------------------------------------
68  //
69  // Open a file by name. Test if it is open like for an ifstream
70  // It doesn't matter whether the file is gzip compressed or not.
71  //
72  void open(const char* name)
73  {
74  if (is_open())
75  {
76  clear(rdstate()|std::ios::failbit);
77  return;
78  }
79 
80  fFile = gzopen(name, "rb");
81  if (fFile == 0)
82  {
83  clear(rdstate()|std::ios::failbit);
84  return;
85  }
86  }
87  // --------------------------------------------------------------------------
88  //
89  // Close an open file.
90  //
91  void close()
92  {
93  if (!is_open())
94  return;
95 
96  if (gzclose(fFile) != Z_OK)
97  clear(rdstate()|std::ios::failbit);
98 
99  fFile = 0;
100  }
101 
102  std::streambuf::pos_type seekoff(std::streambuf::off_type offset, std::ios_base::seekdir dir,
103  std::ios_base::openmode = std::ios_base::in)
104  {
105  // Using a switch instead results in:
106  // In member function `virtual std::streampos izstream::seekoff(long int, std::_Ios_Seekdir, std::_Ios_Openmode)':
107  // warning: enumeration value `_M_ios_seekdir_end' not handled in switch
108  // warning: case value `0' not in enumerated type `_Ios_Seekdir'
109  // warning: case value `1' not in enumerated type `_Ios_Seekdir'
110  // warning: case value `2' not in enumerated type `_Ios_Seekdir'
111 
112  if (dir==std::ios::end)
113  {
114  clear(rdstate()|std::ios::failbit);
115  return EOF;
116  }
117 
118  // We only do relative seeking to avoid unnecessary decompression
119  // of the whole file
120  if (dir==std::ios::beg)
121  offset -= tellg();
122 
123  // Calculate future position in streambuffer
124  const char *ptr = gptr()+offset;
125 
126  // This is the number of bytes still available in the buffer
127  const size_t sbuf = egptr()-gptr();
128 
129  // Check if the new position will still be in the buffer
130  // In this case the target data was already decompressed.
131  if (ptr>=eback() && ptr<egptr())
132  {
133  // Absolute position in z-stream
134  const z_off_t zpos = gztell(fFile)-sbuf; //gzseek(fFile, 0, SEEK_CUR);
135 
136  gbump(offset);
137 
138  return zpos+offset;
139  }
140 
141  const streampos pos = gzseek(fFile, offset-sbuf, SEEK_CUR);
142 
143  // Buffer is empty - force refilling
144  setg(fBuffer+4, fBuffer+4, fBuffer+4);
145 
146  return pos<0 ? streampos(EOF) : pos;
147 
148  /*
149  // SEEK_END not supported by zlib
150  if (dir==ios::end)
151  {
152  // Position in z-stream
153  const z_off_t zpos = gzseek(fFile, offset, SEEK_END);
154  if (zpos<0)
155  return EOF;
156 
157  return fill_buffer()==EOF ? EOF : zpos;
158  }
159  */
160  return EOF;
161  }
162 
163  std::streambuf::pos_type seekpos(std::streambuf::pos_type pos,
164  std::ios_base::openmode = std::ios_base::in)
165  {
166  return seekoff(pos, std::ios::beg);
167  }
168 };
169 
170 #endif
int is_open()
Definition: izstream.h:65
static const int fgBufferSize
Definition: izstream.h:18
std::streambuf::pos_type seekoff(std::streambuf::off_type offset, std::ios_base::seekdir dir, std::ios_base::openmode=std::ios_base::in)
Definition: izstream.h:102
void close()
Definition: izstream.h:91
STL namespace.
int underflow()
Definition: izstream.h:23
izstream(const char *name)
Definition: izstream.h:57
~izstream()
Definition: izstream.h:63
izstream()
Definition: izstream.h:52
void open(const char *name)
Definition: izstream.h:72
double end
char * fBuffer
Definition: izstream.h:21
gzFile fFile
Definition: izstream.h:20
void clear()
Definition: HeadersFTM.h:216
std::streambuf::pos_type seekpos(std::streambuf::pos_type pos, std::ios_base::openmode=std::ios_base::in)
Definition: izstream.h:163