/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #include "filesystem/io_buffer.h" #include "log/log.h" #include "ntypes.h" using namespace GS::IO; //------------------------------------------------------------------------------ uint Buffer::GetCaps() const { return io->GetCaps(); } Handle *Buffer::Open(const char *path, Mode mode) { AutoPtr io_h(io->Open(path, mode)); if (io_h.IsNull()) return NULL; AutoPtr b_h(new BufferHandle(this, io_h)); if (b_h.IsNull()) return NULL; if (!b_h->read_buffer.buffer.Allocate(read_buffer_size)) return NULL; b_h->size = io_h->GetSize(); io_h.Detach(); return b_h.Detach(); } void Buffer::Close(Handle *h) { if (BufferHandle *b_h = (BufferHandle *)h) b_h->handle = NULL; } bool Buffer::Delete(const char *path) { return io->Delete(path); } size_t Buffer::Tell(Handle *h) { return ((BufferHandle *)h)->pos; } size_t Buffer::Seek(Handle *h, ptrdiff_t offset, SeekRef seek) { if (BufferHandle *c_h = (BufferHandle *)h) { switch (seek) { case SeekStart: c_h->pos = Types::Clamp (offset, 0, c_h->size); break; case SeekCurrent: c_h->pos = Types::Clamp (c_h->pos + offset, 0, c_h->size); break; case SeekEnd: c_h->pos = Types::Clamp (c_h->size + offset, 0, c_h->size); break; } return 0; } return size_t(-1); } size_t Buffer::Read(Handle *h, void *data, size_t size) { // __LOG_V__ << "Buffer::Read: size = " << size << ".\n"; size_t read_size = 0; if (BufferHandle *b_h = (BufferHandle *)h) { while (read_size < size) { ptrdiff_t buffer_pos = (b_h->pos + read_size) - b_h->read_buffer.start_pos; if ((buffer_pos >= 0) && (buffer_pos < ptrdiff_t(b_h->read_buffer.usage))) { ptrdiff_t copy_size = Types::Min (b_h->read_buffer.usage - buffer_pos, size - read_size); Memory::Copy((char *)data + read_size, b_h->read_buffer.buffer.c_ptr() + buffer_pos, copy_size); // __LOG_V__ << "Buffer read: pos = " << buffer_pos << ", size = " << copy_size << ".\n"; read_size += copy_size; } else // refill cache { b_h->read_buffer.start_pos = b_h->pos + read_size; if (b_h->read_buffer.start_pos >= b_h->size) { b_h->read_buffer.usage = 0; break; // EJ 01/05: Improves EOF performance for the OGG streaming interface which makes many out of bound calls. } io->Seek(b_h->handle, b_h->read_buffer.start_pos, SeekStart); b_h->read_buffer.usage = io->Read(b_h->handle, b_h->read_buffer.buffer.c_ptr(), b_h->read_buffer.buffer.GetSize()); // __LOG_V__ << "Buffer fill: pos = " << b_h->read_buffer.start_pos << ", size = " << b_h->read_buffer.usage << ".\n"; if (b_h->read_buffer.usage == 0) break; // EOF } } b_h->pos += read_size; } return read_size; } size_t Buffer::Write(Handle *h, const void *data, size_t size) { if (BufferHandle *b_h = (BufferHandle *)h) { size_t write_size = io->Write(b_h->handle, data, size); b_h->pos += write_size; return write_size; } return 0; } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ GS::String Buffer::Hash(const char *path) { return io->Hash(path); } // [EJ] Do not perform a FileLoad here, IO::Buffer is typically sitting in front of a slow IO backend which potentially optimizes hash transfer. //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ bool Buffer::MkDir(const char *path) { return io->MkDir(path); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ Buffer::Buffer(Base *base, size_t read_size, size_t write_size) : io(base) { read_buffer_size = Types::Clamp (read_size, 0, Units::MB(16)); write_buffer_size = Types::Clamp (write_size, 0, Units::MB(16)); } //------------------------------------------------------------------------------