1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
| //paged file reader
template<class F, unsigned PS=4096u>
class file_reader: private F
{
public:
typedef typename F::traits traits;
typedef typename traits::byte byte;
typedef typename traits::size_type size_type;
typedef typename traits::offset_type offset_type;
private:
offset_type f_currentoffset, f_nextoffset;
byte *f_page; //local buffer for page
enum
{
e_pagesize=PS
};
unsigned f_loaded; //loaded page size
unsigned f_pos; //position inside page
//disable copy and assign
file_reader(file_reader const &);
file_reader & operator=(file_reader const &);
public:
file_reader():
f_currentoffset(0), f_nextoffset(0), f_page((byte *)0),
f_loaded(e_pagesize), f_pos(f_loaded)
{
f_page=new byte[e_pagesize];
}
~file_reader()
{
if (*this) { try { close(); } catch(...) {} }
delete[] f_page;
}
operator bool()
{ return F::operator bool(); }
bool fopen(_TCHAR const *path)
{ return F::open(path, traits::e_mdread, traits::e_shread, traits::e_open); }
bool close()
{ return F::close(); }
unsigned fread(void *buf, unsigned bufsize)
{
byte *bytedest=(byte *)buf;
unsigned bufread=0;
//check if file offset has been moved
if (f_currentoffset!=f_nextoffset)
{
f_pos=static_cast<unsigned>(f_nextoffset % e_pagesize);
f_nextoffset/=e_pagesize;
f_nextoffset*=e_pagesize;
if (f_nextoffset+e_pagesize!=f_currentoffset)
{
f_nextoffset=F::seek(f_nextoffset, traits::e_begin);
F::read(f_page, e_pagesize, &f_loaded);
f_currentoffset=(f_nextoffset+=f_loaded);
}
else
f_nextoffset=f_currentoffset;
}
//read page by page
while (bufsize)
{
if (f_pos<f_loaded)
{
unsigned copysize=f_loaded-f_pos;
if (bufsize<copysize)
copysize=bufsize;
::memcpy(bytedest, &f_page[f_pos], copysize);
bytedest+=copysize;
f_pos+=copysize;
bufread+=copysize;
bufsize-=copysize;
}
else if (f_loaded==e_pagesize)
{
F::read(f_page, e_pagesize, &f_loaded);
f_currentoffset=(f_nextoffset+=f_loaded);
f_pos=0;
}
else
break;//assume eof
}
return bufread;
}
offset_type fseek(offset_type offset)
{
//TODO check file is OK ?
//offset is the file pointer from the beginning of file
if (offset<0)
throw std::runtime_error(std::string(STRA_LEN("file_reader::fseek, offset can't be negative\n")));
//else if (F::size()<offset)
//?;ok, accept to move file pointer beyond eof
return (f_nextoffset=offset);
}
offset_type seek(offset_type offset, typename traits::seek_type sk)
{
//TODO check file is OK ?
//offset is the file pointer from the beginning of file
if (sk==traits::e_begin)
;
else if (sk==traits::e_current)
{
if (f_currentoffset!=f_nextoffset)
offset+=f_nextoffset;//assume this is a consecutive seek() call
else
offset+=f_currentoffset-f_loaded+f_pos;
}
else
throw std::runtime_error(std::string(STRA_LEN("file_reader::seek, unsupported seek_type\n")));
return fseek(offset);
}
size_type size()
{ return F::size(); }
}; |
Partager