Subversion Repositories spk

Rev

Details | Last modification | View Log | RSS feed

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