Rev 1 | Blame | Compare with Previous | 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)