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

Last change on this file since 16743 was 15266, checked in by tbretz, 12 years ago
Allocation the buffer on the stack can give problems because it is pretty big. Allocate it on the heap instead.
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.