Subversion Repositories spk

Rev

Blame | Last modification | View Log | RSS feed

/*
  these classes define behaviour of bob_dom_o*filestream and 
  bob_dom_i*filestream on windows filesystem
  
  I also wanted to write streams for x2 filesystem (x2fd library) but they
  don't exist know
*/

#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 bob_dom_owinfilestream : public Ty
{
        private:
                static const int buffer_size=5000;
                
                int m_fd;
                unsigned char m_buffer[buffer_size];
                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;
                
                bob_dom_owinfilestream() { m_fd=-1; m_bufferPos=m_buffer; m_bufferEnd=m_buffer + buffer_size; clear(); }
                ~bob_dom_owinfilestream() { close(); }
                
                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, bob_filestream::mode m)
                {
                        int f=0, cf=0;
                        
                        name(fileName);
                        
                        if((m & bob_filestream::rdonly && m & bob_filestream::create) || (m & bob_filestream::rdonly && m & bob_filestream::rdwr)){
                                clear(failbit);
                                return false;
                        }
                        if(m & bob_filestream::rdonly)
                                f|=_O_RDONLY;
                        else if(m & bob_filestream::rdwr)
                                f|=_O_RDWR;
                        
                        if(m & bob_filestream::create)
                                f|=_O_CREAT | _O_RDWR;
                        
                        m_fd=::_open(fileName, _O_BINARY | f, _S_IREAD | _S_IWRITE);
                        if(m & bob_filestream::seekeof) 
                                _lseek(m_fd, 0, SEEK_END);
                        
                        clear();
                        return m_fd!=-1;
                }
                
                virtual void close() 
                { 
                        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);
                        else
                                m_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, bob_filestream::seek_type origin) 
                { 
                        int o;
                        size_t res;
                        flush();
                        
                        switch(origin){
                                case bob_filestream::seek_begin:
                                        o=SEEK_SET;
                                        break;
                                case bob_filestream::seek_end:
                                        o=SEEK_END;
                                        break;
                                case bob_filestream::seek_current:
                                        o=SEEK_CUR;
                                        break;
                                default:        
                                        o=-1;
                        }
                        res=_lseek(m_fd, offset, o);
                        
                        return res;
                }
};

typedef bob_dom_owinfilestream<bob_dom_obinaryfilestream> bob_dom_obinaryrealfile;
typedef bob_dom_owinfilestream<bob_dom_otextfilestream> bob_dom_otextrealfile;

class bob_iwinfilestream : public bob_dom_ibinaryfilestream
{       
        public:
                typedef bob_dom_ibinaryfilestream base;
                typedef base::value_type_ptr value_type_ptr;
                typedef base::value_type value_type;
                typedef base::size_type size_type;
                typedef ext::stream_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 end
                        m_bufferPos=m_buffer; // buffer pos to beginning
                        m_bBufferEOF=::_eof(m_fd)!=0; // is this the last buffer?
                        return r;
                }
                
        public:
                bob_iwinfilestream() 
                { 
                        m_fd=-1; clear(badbit); 
                        m_buffer=new value_type[m_bufferSize]; 
                }
                
                ~bob_iwinfilestream() { close(); delete m_buffer; }
                
                void clear(state s=goodbit) { base::clear(s); setstate(m_fd!=-1 ? goodbit : badbit); }
                
                bool open(const char *fileName, bob_filestream::mode m)
                {
                        int f=0, cf=0;
                        
                        name(fileName);
                        
                        if((m & bob_filestream::rdonly && m & bob_filestream::create) || (m & bob_filestream::rdonly && m & bob_filestream::rdwr)){
                                clear(failbit);
                                return false;
                        }
                        if(m & bob_filestream::rdonly)
                                f|=_O_RDONLY;
                        else if(m & bob_filestream::rdwr)
                                f|=_O_RDWR;
                        
                        if(m & bob_filestream::create)
                                f|=_O_CREAT | _O_RDWR;
                        
                        m_fd=::_open(fileName, _O_BINARY | f, _S_IREAD | _S_IWRITE);
                        clear();
                        
                        if(m & bob_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() 
                { 
                        ::_close(m_fd);
                        m_fd=-1; 
                        setstate(badbit);
                }
                
                bool advance(offset_type off) 
                { 
                        // offset is in our buffer, just shift the buffer pos
                        if((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 eof
                                if(m_bBufferEOF && m_bufferPos==m_bufferEnd)
                                        setstate(eofbit);
                                else
                                        clear((state)(rdstate() & ~eofbit));
                                return true;
                        }
                        // offset is outside our buffer, do a file seek
                        else{
                                // 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 pos
                                int res=::_lseek(m_fd, off - (long)(m_bufferEnd - m_bufferPos), SEEK_CUR); 
                                if(res==-1) 
                                        setstate(failbit); 
                                else
                                        m_bufferPos=m_bufferEnd; // "erase" the buffer
                                
                                if(::_eof(m_fd)) 
                                        setstate(eofbit);
                                else
                                        clear((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 buffer
                        size_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 did't have all the required data - we must read more
                        if(size){
                                // our buffer is not large enough - read it directly
                                if(size > m_bufferSize){
                                        readed+=(size_t)::_read(m_fd, buffer + s, (unsigned int)size);
                                        m_bufferPos=m_bufferEnd; // this means that our buffer is empty
                                        if(::_eof(m_fd)) 
                                                setstate(eofbit);
                                        else
                                                clear((state)(rdstate() & ~eofbit));
                                }
                                // read the data to our buffer and copy the required size to out buffer
                                else{
                                        size_t r=fillBuffer();
                                        if(size < r) r=size; // copy the missing data to out buffer
                                        memcpy(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(!ext::stream_base::eof()){
                                if(bufferAvail()==0)
                                        fillBuffer();
                                        
                                // 0xD might be followed by 0xA
                                ch=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 eof
                                                if(!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 bob_iwinfilestream bob_dom_ibinaryrealfile;

#endif // !defined(BOB_REALFILE_STREAM_INCLUDED)