Ok, I am trying to write a wrapper for PhysFS so that I can use it with C++ streams. To simplify this, I decided to try boost iostreams.
At the moment I have the following device:
struct input_seekable_device_tag :
boost::iostreams::device_tag,
boost::iostreams::input_seekable
{};
class PhysfsReadDevice
{
public:
typedef char char_type;
typedef input_seekable_device_tag category;
PhysfsReadDevice(const std::string& fname)
{
handle = PHYSFS_openRead(fname.c_str());
cout << "Opening file " << fname << endl;
if(!handle)
throw std::runtime_error(physfs::getLastError());
}
std::streamsize read(char* s, std::streamsize n)
{
// Read up to n characters from the input
// sequence into the buffer s, returning
// the number of characters read, or -1
// to indicate end-of-sequence.
PHYSFS_sint64 bytesread = PHYSFS_read(handle,s,1,static_cast<PHYSFS_uint32>(n));
if(bytesread < 0)
{
throw std::runtime_error(physfs::getLastError());
}
else if(bytesread == 0)
{
if(PHYSFS_eof(handle))
return -1;
}
return static_cast<std::streamsize>(bytesread);
}
std::streampos seek(boost::iostreams::stream_offset off, std::ios_base::seekdir way)
{
// Advances the read/write head by off characters,
// returning the new position, where the offset is
// calculated from:
// - the start of the sequence if way == ios_base::beg
// - the current position if way == ios_base::cur
// - the end of the sequence if way == ios_base::end
PHYSFS_uint64 seekAmt;
PHYSFS_sint64 currentPos;
cout << "Seeking... offset=" << off << endl;
if(way == ios_base::beg)
{
cout << "From beginning..." << endl;
seekAmt = (off > 0) ? static_cast<PHYSFS_uint64>(off) : 0;
}
else if(way == ios_base::cur)
{
cout << "From current..." << endl;
currentPos = PHYSFS_tell(handle);
if(currentPos < 0)
throw std::runtime_error(physfs::getLastError());
currentPos += static_cast<PHYSFS_sint64>(off);
seekAmt = (currentPos > 0) ? static_cast<PHYSFS_uint64>(currentPos) : 0;
}
else if(way == ios_base::end)
{
cout << "From end..." << endl;
currentPos = PHYSFS_fileLength(handle);
if(currentPos < 0) // file length could not be determined... what to do...
throw std::runtime_error("Could not determine file size, possibly streamed");
currentPos += static_cast<PHYSFS_sint64>(off);
seekAmt = (currentPos > 0) ? static_cast<PHYSFS_uint64>(currentPos) : 0;
}
else
throw std::runtime_error("Invalid seek direction");
if(!PHYSFS_seek(handle, static_cast<PHYSFS_uint64>(seekAmt)))
throw std::runtime_error(physfs::getLastError());
currentPos = PHYSFS_tell(handle);
if(currentPos < 0)
throw std::runtime_error(physfs::getLastError());
cout << "New position: " << currentPos << endl;
return std::streampos(static_cast<PHYSFS_uint32>(currentPos));
}
private:
PHYSFS_File* handle;
};
This seems to work fine for the most part... except for the seeking...
No matter if I create my final stream this way:
boost::iostreams::stream<PhysfsReadDevice> ifile("somefile.txt");
or this way
boost::iostreams::stream_buffer<PhysfsReadDevice> ifilebuf("somefile.txt");
std::istream ifile(&ifilebuf);
Doing ifile.seekg(123); does not actually call my seek function! Am I doing something wrong?
This otoh hand works: ifile.seekg(1234, ios_base::cur); (which, according to the PhysFS api description should report an error, as it seeks beyond the end of the file, but it doesn't. But here the iostreams part seems to work at least...)
EDIT: and readsome always returns 0...
[Edited by - l0calh05t on January 28, 2008 4:21:12 PM]