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