Subversion Repositories spk

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
114 cycrow 1
/*
2
  these classes define behaviour of bob_dom_o*filestream and
3
  bob_dom_i*filestream on windows filesystem
4
 
5
  I also wanted to write streams for x2 filesystem (x2fd library) but they
6
  don't exist now
7
*/
8
 
9
#ifndef BOB_REALFILE_STREAM_INCLUDED
10
#define BOB_REALFILE_STREAM_INCLUDED
11
 
12
#include <io.h>
13
#include <fcntl.h>
14
#include <sys/stat.h>
15
 
16
/*
17
	bob_dom_obinaryrealfile - output binary stream (real filesystem files)
18
	bob_dom_otextrealfile - output text stream (real filesystem files)
19
*/
20
 
21
template <class Ty>
22
class owinfilestream : public Ty
23
{
24
	private:
25
		static const size_t buffer_size = 4096;
26
 
27
		int m_fd;
28
		unsigned char *m_buffer;
29
		unsigned char *m_bufferPos;
30
		unsigned char *m_bufferEnd;
31
 
32
		size_t availBuffer() const { return m_bufferEnd - m_bufferPos; }
33
 
34
	public:
35
		typedef Ty base;
36
		typedef typename base::state state;
37
		typedef typename base::size_type size_type;
38
		typedef typename base::const_value_type_ptr const_value_type_ptr;
39
		typedef typename const base::value_type const_value_type;
40
 
41
		owinfilestream() 
42
		{ 
43
		  m_buffer = new unsigned char[buffer_size];
44
		  m_fd = -1; 
45
		  m_bufferPos = m_buffer; 
46
		  m_bufferEnd = m_buffer + buffer_size; 
47
		  clear();
48
		}
49
 
50
		~owinfilestream() 
51
		{ 
52
		  close();
53
		  delete[] m_buffer;
54
		}
55
 
56
		static size_type bufferSize() { return buffer_size; }
57
 
58
		void clear(state s = goodbit) { base::clear(s); setstate(m_fd != -1 ? goodbit : badbit); }
59
 
60
		virtual bool open(const char *fileName, filestream::mode m)
61
		{
62
			int f = 0, cf = 0;
63
 
64
			name(fileName);
65
 
66
			if((m & filestream::rdonly && m & filestream::create) || (m & filestream::rdonly && m & filestream::rdwr)){
67
				clear(failbit);
68
				return false;
69
			}
70
			if(m & filestream::rdonly)
71
				f |= _O_RDONLY;
72
			else if(m & filestream::rdwr)
73
				f |= _O_RDWR;
74
 
75
			if(m & filestream::create)
76
				f |= _O_CREAT | _O_RDWR;
77
 
78
			m_fd = ::_open(fileName, _O_BINARY | f, _S_IREAD | _S_IWRITE);
79
			if(m & filestream::seekeof)
80
				_lseek(m_fd, 0, SEEK_END);
81
 
82
			clear();
83
			return m_fd != -1;
84
		}
85
 
86
		virtual void close()
87
		{
88
		  if(m_fd == -1) return;
89
 
90
			flush();
91
			_chsize(m_fd, ::_tell(m_fd));
92
			::_close(m_fd);
93
			m_fd = -1;
94
			setstate(badbit);
95
		}
96
 
97
		void flush()
98
		{
99
			if(!good()) return;
100
			size_t s = m_bufferPos - m_buffer;
101
			if(s == 0) return;
102
			if(::_write(m_fd, m_buffer, (unsigned int)s) != (unsigned int)s)
103
				setstate(failbit);
104
			else
105
				m_bufferPos = m_buffer;
106
		}
107
 
108
		virtual size_type write(const_value_type_ptr data, size_t size)
109
		{
110
			if(!good()) return -1;
111
 
112
			size_type res = 0;
113
			if(size > availBuffer())
114
				flush();
115
 
116
			if(size > availBuffer()){
117
				res = ::_write(m_fd, data, (unsigned int)size);
118
				if(res != size)
119
					setstate(failbit);
120
			}
121
			else {
122
				memcpy(m_bufferPos, data, size);
123
				m_bufferPos += size;
124
				res = size;
125
			}
126
			return res;
127
		}
128
 
129
		virtual bool put(const_value_type& ch)
130
		{
131
			return write(&ch, 1) > 0;
132
		}
133
 
134
		virtual size_t tell()
135
		{
136
			size_t pos = ::_tell(m_fd);
137
			if(pos >= 0) pos += m_bufferPos - m_buffer;
138
			return pos;
139
		}
140
 
141
		virtual size_t seek(int offset, mystream::stream_base::seek_type origin)
142
		{
143
			int o;
144
			size_t res;
145
			flush();
146
 
147
			switch(origin){
148
				case mystream::stream_base::seek_begin:
149
					o = SEEK_SET;
150
					break;
151
				case mystream::stream_base::seek_end:
152
					o = SEEK_END;
153
					break;
154
				case mystream::stream_base::seek_current:
155
					o = SEEK_CUR;
156
					break;
157
				default:
158
					o = -1;
159
			}
160
			res = _lseek(m_fd, offset, o);
161
 
162
			return res;
163
		}
164
};
165
 
166
typedef owinfilestream<obinaryfilestream> obinaryrealfile;
167
typedef owinfilestream<otextfilestream> otextrealfile;
168
 
169
class iwinfilestream : public ibinaryfilestream
170
{
171
	public:
172
		typedef ibinaryfilestream base;
173
		typedef base::value_type_ptr value_type_ptr;
174
		typedef base::value_type value_type;
175
		typedef base::size_type size_type;
176
		typedef base::state state;
177
		typedef base::offset_type offset_type;
178
 
179
	private:
180
		static const size_t m_bufferSize=5000;
181
		//static const size_t m_bufferSize=8;
182
 
183
		int m_fd;
184
 
185
		value_type_ptr m_buffer;
186
		const_value_type_ptr m_bufferEnd;
187
		const_value_type_ptr m_bufferPos;
188
 
189
		offset_type m_lineEnd;
190
 
191
		bool m_bBufferEOF;
192
 
193
	public:
194
		static size_type bufferSize() { return m_bufferSize; }
195
 
196
	private:
197
		size_type bufferAvail() const { return m_bufferEnd - m_bufferPos; }
198
 
199
		size_t fillBuffer()
200
		{
201
			size_t r=(size_t)::_read(m_fd, m_buffer, m_bufferSize);
202
			m_bufferEnd=m_buffer + r; // set buffer end
203
			m_bufferPos=m_buffer; // buffer pos to beginning
204
			m_bBufferEOF=::_eof(m_fd)!=0; // is this the last buffer?
205
			return r;
206
		}
207
 
208
	public:
209
		iwinfilestream()
210
		{
211
			m_fd=-1; clear(badbit);
212
			m_buffer=new value_type[m_bufferSize];
213
		}
214
 
215
		~iwinfilestream() { close(); delete m_buffer; }
216
 
217
		void clear(state s=goodbit) { base::clear(s); setstate(m_fd!=-1 ? goodbit : badbit); }
218
 
219
		bool open(const char *fileName, filestream::mode m)
220
		{
221
			int f=0, cf=0;
222
 
223
			name(fileName);
224
 
225
			if((m & filestream::rdonly && m & filestream::create) || (m & filestream::rdonly && m & filestream::rdwr)){
226
				clear(failbit);
227
				return false;
228
			}
229
			if(m & filestream::rdonly)
230
				f|=_O_RDONLY;
231
			else if(m & filestream::rdwr)
232
				f|=_O_RDWR;
233
 
234
			if(m & filestream::create)
235
				f|=_O_CREAT | _O_RDWR;
236
 
237
			m_fd=::_open(fileName, _O_BINARY | f, _S_IREAD | _S_IWRITE);
238
			clear();
239
 
240
			if(m & filestream::seekeof)
241
				_lseek(m_fd, 0, SEEK_END);
242
 
243
			m_bufferPos = m_bufferEnd = m_buffer + m_bufferSize;
244
			m_bBufferEOF=false;
245
 
246
			m_lineEnd=0;
247
 
248
			return m_fd!=-1;
249
		}
250
 
251
		void close()
252
		{
253
		  if(m_fd == -1) return;
254
 
255
			::_close(m_fd);
256
			m_fd=-1;
257
			setstate(badbit);
258
		}
259
 
260
		bool advance(offset_type off)
261
		{
262
			// offset is in our buffer, just shift the buffer pos
263
			if((m_bufferPos + off >= m_buffer) && (m_bufferPos + off <= m_bufferEnd)){
264
				m_bufferPos+=off;
265
				// our buffer is the last one, if we are at its end we are at eof
266
				if(m_bBufferEOF && m_bufferPos==m_bufferEnd)
267
					setstate(eofbit);
268
				else
269
					clear((state)(rdstate() & ~eofbit));
270
				return true;
271
			}
272
			// offset is outside our buffer, do a file seek
273
			else{
274
				// file offset is always at end of our buffer but buffer offset is different
275
				// we must adjust the offset to lseek by difference between end of buffer and buffer pos
276
				int res=::_lseek(m_fd, off - (long)(m_bufferEnd - m_bufferPos), SEEK_CUR);
277
				if(res==-1)
278
					setstate(failbit);
279
				else
280
					m_bufferPos=m_bufferEnd; // "erase" the buffer
281
 
282
				if(::_eof(m_fd))
283
					setstate(eofbit);
284
				else
285
					clear((state)(rdstate() & ~eofbit));
286
 
287
				return res!=-1;
288
			}
289
		}
290
 
291
		size_t tell() const
292
		{
293
			return ::_tell(m_fd) - (m_bufferEnd - m_bufferPos);
294
		}
295
 
296
		size_type read(value_type_ptr buffer, size_type size)
297
		{
298
			if(eof() && size > 0) setstate(failbit);
299
			if(!good()) return -1;
300
 
301
			// copy everything from our buffer to the out buffer
302
			size_t readed=0;
303
			size_t s=bufferAvail();
304
			if(size < s) s=size;
305
 
306
			memcpy(buffer, m_bufferPos, s);
307
			advance((offset_type)s);
308
			size-=s;
309
			readed=s;
310
 
311
			// our buffer doesn't have all the required data - we must read more
312
			if(size){
313
				// our buffer is not large enough - read the data directly
314
				if(size > m_bufferSize){
315
					readed+=(size_t)::_read(m_fd, buffer + s, (unsigned int)size);
316
					m_bufferPos=m_bufferEnd; // this means that our buffer is empty
317
					if(::_eof(m_fd))
318
						setstate(eofbit);
319
					else
320
						clear((state)(rdstate() & ~eofbit));
321
				}
322
				// read the data to our buffer and copy the required size to out buffer
323
				else{
324
					size_t r=fillBuffer();
325
					if(size < r) r=size; // copy the missing data to out buffer
326
					memcpy(buffer + readed, m_bufferPos, r);
327
					readed+=r;
328
					advance((offset_type) r);
329
				}
330
			}
331
			return readed;
332
		}
333
 
334
		value_type_ptr readln()
335
		{
336
			value_type_ptr buff=0;
337
			value_type ch, old;
338
			int size;
339
 
340
			if(!good()) return 0;
341
 
342
			while(!mystream::stream_base::eof()){
343
				if(bufferAvail()==0)
344
					fillBuffer();
345
 
346
				// 0xD might be followed by 0xA
347
				ch=old=*m_bufferPos++;
348
				if(ch==0xD || ch==0xA){
349
					size=(offset_type)tell() - m_lineEnd;
350
					advance(-size);
351
					buff=new value_type[size];
352
					read(buff, size);
353
					buff[size-1]=0; // to overwrite line end (0xD or 0xA)
354
 
355
					advance(1);
356
					m_lineEnd=(offset_type)tell();
357
 
358
					if(ch==0xD){
359
						// we are not at eof
360
						if(!eof()){
361
							if(bufferAvail()==0) fillBuffer();
362
							if(*m_bufferPos==0xA){
363
								advance(1);
364
								m_lineEnd++;
365
							}
366
						}
367
					}
368
					break;
369
				}
370
			}
371
			if(buff==0){
372
				size=(offset_type)tell() - m_lineEnd;
373
				advance(-size);
374
				buff=new value_type[size + 1];
375
				read(buff, size);
376
				buff[size]=0;
377
			}
378
 
379
			return buff;
380
		}
381
 
382
		value_type_ptr readln2()
383
		{
384
			if(!good()) return 0;
385
 
386
			if(bufferAvail()==0) fillBuffer();
387
			/*
388
			value_type *pos;
389
			for(pos=m_bufferPos; pos < m_bufferEnd; ++pos){
390
				if(*pos==0xD || 0xA){
391
					newLineEnd=tell() + pos;
392
 
393
					lseek(m_fd, m_lineEnd, SEEK_SET);
394
					::read
395
				}
396
			}*/
397
		}
398
};
399
 
400
typedef iwinfilestream ibinaryrealfile;
401
 
402
#endif // !defined(BOB_REALFILE_STREAM_INCLUDED)