source: trunk/Mars/mcore/izstream.h@ 17135

Last change on this file since 17135 was 17135, checked in by tbretz, 11 years ago
Reverting to last revision.
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 = 2048*1024*2;
23
24 gzFile fFile; // file handle for compressed file
25 char *fBuffer; // 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 fBuffer = new char[fgBufferSize];
59 setg(fBuffer+4, fBuffer+4, fBuffer+4);
60 }
61 izstream(const char *name) : std::istream(this), fFile(0)
62 {
63 fBuffer = new char[fgBufferSize];
64 setg(fBuffer+4, fBuffer+4, fBuffer+4);
65 open(name);
66 }
67 ~izstream() { izstream::close(); delete [] fBuffer; }
68
69 int is_open() { return fFile!=0; }
70
71 // --------------------------------------------------------------------------
72 //
73 // Open a file by name. Test if it is open like for an ifstream
74 // It doesn't matter whether the file is gzip compressed or not.
75 //
76 void open(const char* name)
77 {
78 if (is_open())
79 {
80 clear(rdstate()|std::ios::failbit);
81 return;
82 }
83
84 fFile = gzopen(name, "rb");
85 if (fFile == 0)
86 {
87 clear(rdstate()|std::ios::failbit);
88 return;
89 }
90 }
91 // --------------------------------------------------------------------------
92 //
93 // Close an open file.
94 //
95 void close()
96 {
97 if (!is_open())
98 return;
99
100 if (gzclose(fFile) != Z_OK)
101 clear(rdstate()|std::ios::failbit);
102
103 fFile = 0;
104 }
105
106 std::streambuf::pos_type seekoff(std::streambuf::off_type offset, std::ios_base::seekdir dir,
107 std::ios_base::openmode = std::ios_base::in)
108 {
109 // Using a switch instead results in:
110 // In member function `virtual std::streampos izstream::seekoff(long int, std::_Ios_Seekdir, std::_Ios_Openmode)':
111 // warning: enumeration value `_M_ios_seekdir_end' not handled in switch
112 // warning: case value `0' not in enumerated type `_Ios_Seekdir'
113 // warning: case value `1' not in enumerated type `_Ios_Seekdir'
114 // warning: case value `2' not in enumerated type `_Ios_Seekdir'
115
116 if (dir==std::ios::end)
117 {
118 clear(rdstate()|std::ios::failbit);
119 return EOF;
120 }
121
122 // We only do relative seeking to avoid unnecessary decompression
123 // of the whole file
124 if (dir==std::ios::beg)
125 offset -= tellg();
126
127 // Calculate future position in streambuffer
128 const char *ptr = gptr()+offset;
129
130 // This is the number of bytes still available in the buffer
131 const size_t sbuf = egptr()-gptr();
132
133 // Check if the new position will still be in the buffer
134 // In this case the target data was already decompressed.
135 if (ptr>=eback() && ptr<egptr())
136 {
137 // Absolute position in z-stream
138 const z_off_t zpos = gztell(fFile)-sbuf; //gzseek(fFile, 0, SEEK_CUR);
139
140 gbump(offset);
141
142 return zpos+offset;
143 }
144
145 const streampos pos = gzseek(fFile, offset-sbuf, SEEK_CUR);
146
147 // Buffer is empty - force refilling
148 setg(fBuffer+4, fBuffer+4, fBuffer+4);
149
150 return pos<0 ? streampos(EOF) : pos;
151
152 /*
153 // SEEK_END not supported by zlib
154 if (dir==ios::end)
155 {
156 // Position in z-stream
157 const z_off_t zpos = gzseek(fFile, offset, SEEK_END);
158 if (zpos<0)
159 return EOF;
160
161 return fill_buffer()==EOF ? EOF : zpos;
162 }
163 */
164 return EOF;
165 }
166
167 std::streambuf::pos_type seekpos(std::streambuf::pos_type pos,
168 std::ios_base::openmode = std::ios_base::in)
169 {
170 return seekoff(pos, std::ios::beg);
171 }
172
173#ifdef __MARS__
174 ClassDef(izstream, 0) // A C++ wrapper to istream zlib files
175#endif
176};
177
178#endif
Note: See TracBrowser for help on using the repository browser.