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

Last change on this file since 18018 was 17140, checked in by tbretz, 11 years ago
The ClassDef is not needed. We are not going to write class instances to files.
File size: 4.8 KB
Line 
1#ifndef MARS_izstream
2#define MARS_izstream
3
4#include <string.h>
5
6#include <istream>
7#include <streambuf>
8
9#ifdef __CINT__
10typedef void *gzFile;
11#else
12#include <zlib.h>
13#endif
14
15class izstream : public std::streambuf, public std::istream
16{
17private:
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
51public:
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
Note: See TracBrowser for help on using the repository browser.