00001 template<unsigned blocksize>
00002 class file_cached : public file {
00003 public:
00004 static void g_create(service_ptr_t<file> & p_out,service_ptr_t<file> p_base,abort_callback & p_abort) {
00005 service_ptr_t<file_cached<blocksize> > temp;
00006 temp = new service_impl_t<file_cached<blocksize> >();
00007 temp->initialize(p_base,p_abort);
00008 p_out = temp.get_ptr();
00009 }
00010 private:
00011 void initialize(service_ptr_t<file> p_base,abort_callback & p_abort) {
00012 m_base = p_base;
00013 m_position = 0;
00014 m_can_seek = m_base->can_seek();
00015 if (m_can_seek) {
00016 m_position_base = m_base->get_position(p_abort);
00017 } else {
00018 m_position_base = 0;
00019 }
00020
00021 m_size = m_base->get_size(p_abort);
00022
00023 flush_buffer();
00024 }
00025 public:
00026
00027 t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
00028 t_uint8 * outptr = (t_uint8*)p_buffer;
00029 t_size done = 0;
00030 while(done < p_bytes && m_position < m_size) {
00031 p_abort.check();
00032
00033 if (m_position >= m_buffer_position && m_position < m_buffer_position + m_buffer_status) {
00034 t_size delta = pfc::min_t<t_size>((t_size)(m_buffer_position + m_buffer_status - m_position),p_bytes - done);
00035 t_size bufptr = (t_size)(m_position - m_buffer_position);
00036 memcpy(outptr+done,m_buffer+bufptr,delta);
00037 done += delta;
00038 m_position += delta;
00039 if (m_buffer_status != sizeof(m_buffer) && done < p_bytes) break;
00040 } else {
00041 m_buffer_position = m_position - m_position % blocksize;
00042 adjust_position(m_buffer_position,p_abort);
00043
00044 m_buffer_status = m_base->read(m_buffer,sizeof(m_buffer),p_abort);
00045 m_position_base += m_buffer_status;
00046
00047 if (m_buffer_status <= (t_size)(m_position - m_buffer_position)) break;
00048 }
00049 }
00050
00051 return done;
00052 }
00053
00054 void write(const void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
00055 p_abort.check();
00056 adjust_position(m_position,p_abort);
00057 m_base->write(p_buffer,p_bytes,p_abort);
00058 m_position_base = m_position = m_position + p_bytes;
00059 if (m_size < m_position) m_size = m_position;
00060 flush_buffer();
00061 }
00062
00063 t_filesize get_size(abort_callback & p_abort) {
00064 p_abort.check();
00065 return m_size;
00066 }
00067 t_filesize get_position(abort_callback & p_abort) {
00068 p_abort.check();
00069 return m_position;
00070 }
00071 void set_eof(abort_callback & p_abort) {
00072 p_abort.check();
00073 adjust_position(m_position,p_abort);
00074 m_base->set_eof(p_abort);
00075 flush_buffer();
00076 }
00077 void seek(t_filesize p_position,abort_callback & p_abort) {
00078 p_abort.check();
00079 if (!m_can_seek) throw exception_io_object_not_seekable();
00080 if (p_position > m_size) throw exception_io_seek_out_of_range();
00081 m_position = p_position;
00082 }
00083 void reopen(abort_callback & p_abort) {seek(0,p_abort);}
00084 bool can_seek() {return m_can_seek;}
00085 bool get_content_type(pfc::string_base & out) {return m_base->get_content_type(out);}
00086 void on_idle(abort_callback & p_abort) {p_abort.check();m_base->on_idle(p_abort);}
00087 t_filetimestamp get_timestamp(abort_callback & p_abort) {p_abort.check(); return m_base->get_timestamp(p_abort);}
00088 bool is_remote() {return m_base->is_remote();}
00089 void resize(t_filesize p_size,abort_callback & p_abort) {
00090 flush_buffer();
00091 m_base->resize(p_size,p_abort);
00092 m_size = p_size;
00093 if (m_position > m_size) m_position = m_size;
00094 if (m_position_base > m_size) m_position_base = m_size;
00095 }
00096 private:
00097 void adjust_position(t_filesize p_target,abort_callback & p_abort) {
00098 if (p_target != m_position_base) {
00099 m_base->seek(p_target,p_abort);
00100 m_position_base = p_target;
00101 }
00102 }
00103
00104 void flush_buffer() {
00105 m_buffer_status = 0;
00106 m_buffer_position = 0;
00107 }
00108
00109 service_ptr_t<file> m_base;
00110 t_filesize m_position,m_position_base,m_size;
00111 bool m_can_seek;
00112 t_filesize m_buffer_position;
00113 t_size m_buffer_status;
00114 t_uint8 m_buffer[blocksize];
00115 };