tags:

views:

198

answers:

2

I'm quite surprised that Google didn't find a solution. I'm searching for a solution that allows SDL_RWops to be used with std::istream. SDL_RWops is the alternative mechanism for reading/writing data in SDL.

Any links to sites that tackle the problem?

An obvious solution would be to pre-read enough data to memory and then use SDL_RWFromMem. However, that has the downside that I'd need to know the filesize beforehand.

Seems like the problem could somehow be solved by "overriding" SDL_RWops functions...

A: 

I feel bad answering my own question, but it preocupied me for some time, and this is the solution I came up with:

int istream_seek( struct SDL_RWops *context, int offset, int whence)
{
    std::istream* stream = (std::istream*) context->hidden.unknown.data1;

         if ( whence == SEEK_SET )
        stream->seekg ( offset, std::ios::beg );
    else if ( whence == SEEK_CUR )
        stream->seekg ( offset, std::ios::cur );
    else if ( whence == SEEK_END )
         stream->seekg ( offset, std::ios::end );

    return stream->fail() ? -1 : stream->tellg();
}


int istream_read(SDL_RWops *context, void *ptr, int size, int maxnum)
{
    if ( size == 0 ) return -1;
    std::istream* stream = (std::istream*) context->hidden.unknown.data1;
    stream->read( (char*)ptr, size * maxnum );

    return stream->bad() ? -1 : stream->gcount() / size;
}

int istream_close( SDL_RWops *context )
{
    if ( context ) {
        SDL_FreeRW( context );
    }
    return 0;
}


SDL_RWops *SDL_RWFromIStream( std::istream& stream )
{
    SDL_RWops *rwops;
    rwops = SDL_AllocRW();

    if ( rwops != NULL ) 
    {
        rwops->seek = istream_seek;
        rwops->read = istream_read;
        rwops->write = NULL;
        rwops->close = istream_close;
        rwops->hidden.unknown.data1 = &stream;
    }
    return rwops;
}

Works under the assumptions that istream's are never freed by SDL (and that they live through the operation). Also only istream support is in, a separate function would be done for ostream -- I know I could pass iostream, but that would not allow passing an istream to the conversion function :/.

Any tips on errors or upgrades welcome.

Kornel Kisielewicz
using rwops->type you could allow either istream, ostream, or iostream.
caspin
using NULL as the write function seems scary. It might be better to create a function that uses SDL_SetError and returns -1.
caspin
@Caspin, thanks, very useful tip! Still, the code posted doesn't work.... I'm trying to debug it, but no clues :/
Kornel Kisielewicz
Okay, my bad, I wasn't passing ios::binary to the test case :)
Kornel Kisielewicz
+1  A: 

If you're trying to get an SDL_RWops struct from an istream, you could do it by reading the whole istream into memory and then using SDL_RWFromMem to get a struct to represent it.

Following is a quick example; note that it's unsafe, as no sanity checks are done. For example, if the file's size is 0, accessing buffer[0] may throw an exception or assert in debug builds.

// Open a bitmap
std::ifstream bitmap("bitmap.bmp");

// Find the bitmap file's size
bitmap.seekg(0, std::ios_base::end);
std::istream::pos_tye fileSize = bitmap.tellg();
bitmap.seekg(0);

// Allocate a buffer to store the file in
std::vector<unsigned char> buffer(fileSize);

// Copy the istream into the buffer
std::copy(std::istreambuf_iterator<unsigned char>(bitmap), std::istreambuf_iterator<unsigned char>(), buffer.begin());

// Get an SDL_RWops struct for the file
SDL_RWops* rw = SDL_RWFromMem(&buffer[0], buffer.size());

// Do stuff with the SDL_RWops struct
dauphic
I already wrote that I can't do that because I don't want to preload the whole file into memory. If I'd wanted to read from a file, I'd use IMG_Load :). I want to load from a custom container that is accessed via an istream.
Kornel Kisielewicz
You only mentioned that this is a problem because 'you don't know the size of the file beforehand'
dauphic
Well yes, this can work with any istream, I just used an ifstream for the example because it's the easiest way to make an istream.
dauphic
*sigh*... imagine -- I get a istream from a file-archive library. No sizes, just an istream. Moreover, in that zipfile, there are several files stored. Preloading the file would load us 1GB of images.
Kornel Kisielewicz