Sign in to follow this  
l0calh05t

boost iostreams question(s)

Recommended Posts

l0calh05t    1796
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]

Share this post


Link to post
Share on other sites
l0calh05t    1796
bump...

Well, after some testing I noticed that seekg *does* call my seek function after all, but only if the state flags are good. If the state flags are eof|fail, my seek function is not called, *but* the flags are reset...

Is this behavior normal??

Oh.. and readsome still doesn't work...

EDIT:

well, both behaviors seem to be normal...
seekg behaves the same with a standard filebuf (first call if any flags are set only resets flags)
readsome behaves the same with a standard filebuf (always returns 0)

still doesn't make much sense imo, but at least it doesn't seem to be my fault...

[Edited by - l0calh05t on January 29, 2008 7:34:12 AM]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this