source: trunk/Mars/mbase/izstream.h@ 11559

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