Blame | Last modification | View Log | RSS feed
/*these classes define behaviour of bob_dom_o*filestream andbob_dom_i*filestream on windows filesystemI also wanted to write streams for x2 filesystem (x2fd library) but theydon't exist now*/#ifndef BOB_REALFILE_STREAM_INCLUDED#define BOB_REALFILE_STREAM_INCLUDED#include <io.h>#include <fcntl.h>#include <sys/stat.h>/*bob_dom_obinaryrealfile - output binary stream (real filesystem files)bob_dom_otextrealfile - output text stream (real filesystem files)*/template <class Ty>class owinfilestream : public Ty{private:static const size_t buffer_size = 4096;int m_fd;unsigned char *m_buffer;unsigned char *m_bufferPos;unsigned char *m_bufferEnd;size_t availBuffer() const { return m_bufferEnd - m_bufferPos; }public:typedef Ty base;typedef typename base::state state;typedef typename base::size_type size_type;typedef typename base::const_value_type_ptr const_value_type_ptr;typedef typename const base::value_type const_value_type;owinfilestream(){m_buffer = new unsigned char[buffer_size];m_fd = -1;m_bufferPos = m_buffer;m_bufferEnd = m_buffer + buffer_size;clear();}~owinfilestream(){close();delete[] m_buffer;}static size_type bufferSize() { return buffer_size; }void clear(state s = goodbit) { base::clear(s); setstate(m_fd != -1 ? goodbit : badbit); }virtual bool open(const char *fileName, filestream::mode m){int f = 0, cf = 0;name(fileName);if((m & filestream::rdonly && m & filestream::create) || (m & filestream::rdonly && m & filestream::rdwr)){clear(failbit);return false;}if(m & filestream::rdonly)f |= _O_RDONLY;else if(m & filestream::rdwr)f |= _O_RDWR;if(m & filestream::create)f |= _O_CREAT | _O_RDWR;m_fd = ::_open(fileName, _O_BINARY | f, _S_IREAD | _S_IWRITE);if(m & filestream::seekeof)_lseek(m_fd, 0, SEEK_END);clear();return m_fd != -1;}virtual void close(){if(m_fd == -1) return;flush();_chsize(m_fd, ::_tell(m_fd));::_close(m_fd);m_fd = -1;setstate(badbit);}void flush(){if(!good()) return;size_t s = m_bufferPos - m_buffer;if(s == 0) return;if(::_write(m_fd, m_buffer, (unsigned int)s) != (unsigned int)s)setstate(failbit);elsem_bufferPos = m_buffer;}virtual size_type write(const_value_type_ptr data, size_t size){if(!good()) return -1;size_type res = 0;if(size > availBuffer())flush();if(size > availBuffer()){res = ::_write(m_fd, data, (unsigned int)size);if(res != size)setstate(failbit);}else {memcpy(m_bufferPos, data, size);m_bufferPos += size;res = size;}return res;}virtual bool put(const_value_type& ch){return write(&ch, 1) > 0;}virtual size_t tell(){size_t pos = ::_tell(m_fd);if(pos >= 0) pos += m_bufferPos - m_buffer;return pos;}virtual size_t seek(int offset, mystream::stream_base::seek_type origin){int o;size_t res;flush();switch(origin){case mystream::stream_base::seek_begin:o = SEEK_SET;break;case mystream::stream_base::seek_end:o = SEEK_END;break;case mystream::stream_base::seek_current:o = SEEK_CUR;break;default:o = -1;}res = _lseek(m_fd, offset, o);return res;}};typedef owinfilestream<obinaryfilestream> obinaryrealfile;typedef owinfilestream<otextfilestream> otextrealfile;class iwinfilestream : public ibinaryfilestream{public:typedef ibinaryfilestream base;typedef base::value_type_ptr value_type_ptr;typedef base::value_type value_type;typedef base::size_type size_type;typedef base::state state;typedef base::offset_type offset_type;private:static const size_t m_bufferSize=5000;//static const size_t m_bufferSize=8;int m_fd;value_type_ptr m_buffer;const_value_type_ptr m_bufferEnd;const_value_type_ptr m_bufferPos;offset_type m_lineEnd;bool m_bBufferEOF;public:static size_type bufferSize() { return m_bufferSize; }private:size_type bufferAvail() const { return m_bufferEnd - m_bufferPos; }size_t fillBuffer(){size_t r=(size_t)::_read(m_fd, m_buffer, m_bufferSize);m_bufferEnd=m_buffer + r; // set buffer endm_bufferPos=m_buffer; // buffer pos to beginningm_bBufferEOF=::_eof(m_fd)!=0; // is this the last buffer?return r;}public:iwinfilestream(){m_fd=-1; clear(badbit);m_buffer=new value_type[m_bufferSize];}~iwinfilestream() { close(); delete m_buffer; }void clear(state s=goodbit) { base::clear(s); setstate(m_fd!=-1 ? goodbit : badbit); }bool open(const char *fileName, filestream::mode m){int f=0, cf=0;name(fileName);if((m & filestream::rdonly && m & filestream::create) || (m & filestream::rdonly && m & filestream::rdwr)){clear(failbit);return false;}if(m & filestream::rdonly)f|=_O_RDONLY;else if(m & filestream::rdwr)f|=_O_RDWR;if(m & filestream::create)f|=_O_CREAT | _O_RDWR;m_fd=::_open(fileName, _O_BINARY | f, _S_IREAD | _S_IWRITE);clear();if(m & filestream::seekeof)_lseek(m_fd, 0, SEEK_END);m_bufferPos = m_bufferEnd = m_buffer + m_bufferSize;m_bBufferEOF=false;m_lineEnd=0;return m_fd!=-1;}void close(){if(m_fd == -1) return;::_close(m_fd);m_fd=-1;setstate(badbit);}bool advance(offset_type off){// offset is in our buffer, just shift the buffer posif((m_bufferPos + off >= m_buffer) && (m_bufferPos + off <= m_bufferEnd)){m_bufferPos+=off;// our buffer is the last one, if we are at its end we are at eofif(m_bBufferEOF && m_bufferPos==m_bufferEnd)setstate(eofbit);elseclear((state)(rdstate() & ~eofbit));return true;}// offset is outside our buffer, do a file seekelse{// file offset is always at end of our buffer but buffer offset is different// we must adjust the offset to lseek by difference between end of buffer and buffer posint res=::_lseek(m_fd, off - (long)(m_bufferEnd - m_bufferPos), SEEK_CUR);if(res==-1)setstate(failbit);elsem_bufferPos=m_bufferEnd; // "erase" the bufferif(::_eof(m_fd))setstate(eofbit);elseclear((state)(rdstate() & ~eofbit));return res!=-1;}}size_t tell() const{return ::_tell(m_fd) - (m_bufferEnd - m_bufferPos);}size_type read(value_type_ptr buffer, size_type size){if(eof() && size > 0) setstate(failbit);if(!good()) return -1;// copy everything from our buffer to the out buffersize_t readed=0;size_t s=bufferAvail();if(size < s) s=size;memcpy(buffer, m_bufferPos, s);advance((offset_type)s);size-=s;readed=s;// our buffer doesn't have all the required data - we must read moreif(size){// our buffer is not large enough - read the data directlyif(size > m_bufferSize){readed+=(size_t)::_read(m_fd, buffer + s, (unsigned int)size);m_bufferPos=m_bufferEnd; // this means that our buffer is emptyif(::_eof(m_fd))setstate(eofbit);elseclear((state)(rdstate() & ~eofbit));}// read the data to our buffer and copy the required size to out bufferelse{size_t r=fillBuffer();if(size < r) r=size; // copy the missing data to out buffermemcpy(buffer + readed, m_bufferPos, r);readed+=r;advance((offset_type) r);}}return readed;}value_type_ptr readln(){value_type_ptr buff=0;value_type ch, old;int size;if(!good()) return 0;while(!mystream::stream_base::eof()){if(bufferAvail()==0)fillBuffer();// 0xD might be followed by 0xAch=old=*m_bufferPos++;if(ch==0xD || ch==0xA){size=(offset_type)tell() - m_lineEnd;advance(-size);buff=new value_type[size];read(buff, size);buff[size-1]=0; // to overwrite line end (0xD or 0xA)advance(1);m_lineEnd=(offset_type)tell();if(ch==0xD){// we are not at eofif(!eof()){if(bufferAvail()==0) fillBuffer();if(*m_bufferPos==0xA){advance(1);m_lineEnd++;}}}break;}}if(buff==0){size=(offset_type)tell() - m_lineEnd;advance(-size);buff=new value_type[size + 1];read(buff, size);buff[size]=0;}return buff;}value_type_ptr readln2(){if(!good()) return 0;if(bufferAvail()==0) fillBuffer();/*value_type *pos;for(pos=m_bufferPos; pos < m_bufferEnd; ++pos){if(*pos==0xD || 0xA){newLineEnd=tell() + pos;lseek(m_fd, m_lineEnd, SEEK_SET);::read}}*/}};typedef iwinfilestream ibinaryrealfile;#endif // !defined(BOB_REALFILE_STREAM_INCLUDED)