SDL_RWops to handle gzipped files and autoconf question

Hi all,

Don’t know if anyone else has felt the need for this, but I modified
SDL_rwops.c to allow transparent read/write of gzipped files (any use
of SDL_RWFromFile uses zlib instead of stdio functions if the file is
gzipped). I was impressed at how clean and easy it was to do this,
thanks Sam!

Since this uses zlib to handle the (de)compression, it adds a
dependency. Of course we can make this autoconf’able, so I added some
#ifdefs, and a new configure option. This was fairly clear to me,
even though I am a relative autoconf newbie.

But! Here’s the problem… and the reason that I’m not supplying a
patch (yet!). In my own project, I check for whether SDL is available
in configure.in, using AC_CHECK_LIB(SDL, SDL_Init). But since SDL now
depends on zlib, and presumably autoconf can’t know that, autoconf’s
test program bombs out with unresolved link errors, and autoconf tells
me that SDL is not available! Now of course I can work around this in
my own configure.in (although I will need to learn m4 to do so, I
guess), but I don’t want to make everyone else do so.

What is the proper way to fix this? I’m sure that statically linking
zlib into SDL is not the answer. I mean, other libraries have
dependencies… I’m fairly sure there must be a standard answer.

=wl
… If I had heart failure right now, I couldn’t be a more fortunate man!!–
Albert ``Willy’’ Lee, Emacs user, game programmer
"They call me CRAZY - just because I DARE to DREAM of a RACE of
SUPERHUMAN MONSTERS!"

Willy Lee wrote:

Hi all,

Don’t know if anyone else has felt the need for this, but I modified
SDL_rwops.c to allow transparent read/write of gzipped files (any use
of SDL_RWFromFile uses zlib instead of stdio functions if the file is
gzipped). I was impressed at how clean and easy it was to do this,
thanks Sam!

Since this uses zlib to handle the (de)compression, it adds a
dependency. Of course we can make this autoconf’able, so I added some
#ifdefs, and a new configure option. This was fairly clear to me,
even though I am a relative autoconf newbie.

But! Here’s the problem… and the reason that I’m not supplying a
patch (yet!). In my own project, I check for whether SDL is available
in configure.in, using AC_CHECK_LIB(SDL, SDL_Init). But since SDL now
depends on zlib, and presumably autoconf can’t know that, autoconf’s
test program bombs out with unresolved link errors, and autoconf tells
me that SDL is not available! Now of course I can work around this in
my own configure.in (although I will need to learn m4 to do so, I
guess), but I don’t want to make everyone else do so.

What is the proper way to fix this? I’m sure that statically linking
zlib into SDL is not the answer. I mean, other libraries have
dependencies… I’m fairly sure there must be a standard answer.

=wl
… If I had heart failure right now, I couldn’t be a more fortunate man!!

Albert ``Willy’’ Lee, Emacs user, game programmer
"They call me CRAZY - just because I DARE to DREAM of a RACE of
SUPERHUMAN MONSTERS!"

You need to link libSDL to libz.

This sounds like it would be better as an extension to SDL,
rather than built in though. the RWops stuff was designed to
be replacable without replacing the standard ops.

Don’t know if anyone else has felt the need for this, but I modified
SDL_rwops.c to allow transparent read/write of gzipped files (any use
of SDL_RWFromFile uses zlib instead of stdio functions if the file is
gzipped). I was impressed at how clean and easy it was to do this,
thanks Sam!

do you have the source for this somewhere? i’d like to make
an SDL extension library that can do RW objects with .tar.gz
files.

“Pete” == Pete Shinners writes:

Don’t know if anyone else has felt the need for this, but I
modified > SDL_rwops.c to allow transparent read/write of gzipped
files (any use > of SDL_RWFromFile uses zlib instead of stdio
functions if the file is > gzipped). I was impressed at how clean
and easy it was to do this, > thanks Sam!

do you have the source for this somewhere? i’d like to make an SDL
extension library that can do RW objects with .tar.gz files.

Well, I followed Ray’s advice and took the code out of SDL_rwops.c to
try to make an extension library. I haven’t had much time to use it
(hitting beta at work this week), but it’s so simple — because I
just make zlib calls. This is of course no problem on Linux but it’s
yet another library that your end user has to install on Windows,
unfortunately.

The actual code is so small I will just quote it here, if I may. Note
that this particular code is untested — although very similar
to code that I once put in SDL_rwops.c, which worked quite well, at
least for reading. Please feel free to do with it what you will — I
will not have time to do anything with it — and in return I hope to
be able to use your extension library, so I can happily pack up my
game data files as .tar.gz files.

cheers,
=wl

#include “sdlzlib.h”
#include <zlib.h> /* gzopen, gzread /
#include <errno.h> /
perror /
#include <SDL/SDL_error.h> /
SDL_Error */

static int sdlzlib_seek(SDL_RWops *context, int offset, int whence)
{
int newpos;

if ( (newpos = gzseek(context->hidden.gzstdio.fp, offset, whence)) != -1) 
{
    return newpos;
} else {
    SDL_Error(SDL_EFSEEK);
    return(-1);
}

}

static int sdlzlib_read(SDL_RWops *context, void *ptr, int size, int maxnum)
{
int nread;

nread = gzread(context->hidden.gzstdio.fp, ptr, size * maxnum); 
if ( nread < 0 ) {
    SDL_Error(SDL_EFREAD);
}
/* return number of items read, not number of bytes */
return(nread / size);

}

static int sdlzlib_write(SDL_RWops *context, const void *ptr, int size,
int num)
{
size_t nwrote;

nwrote = gzwrite(context->hidden.gzstdio.fp, ptr, size * num);
if ( nwrote <= 0 ) {
    SDL_Error(SDL_EFWRITE);
}
return(nwrote);

}

static int sdlzlib_close(SDL_RWops context)
{
if ( context ) {
if ( context->hidden.gzstdio.autoclose ) {
/
TODO: Check the return value here */
gzclose(context->hidden.gzstdio.fp);
}
SDL_FreeRW(context);
}
return(0);
}

/*

  • This function is a wrapper for SDL_RWFromFile which checks to see

  • if the file is compressed with gzip and if so, uses zlib to operate

  • on the compressed contents. NOTE: mode must be either read-only or

  • write-only, otherwise zlib will silently fail.
    */
    SDL_RWops *SDLZlib_RWFromFile(const char *file, const char *mode)
    {
    SDL_RWops *ops;
    FILE *fp;
    unsigned char magic[2];
    int nread;

    fp = fopen(file, mode);
    if (!fp)
    {
    perror(“SDL-zlib”);
    return NULL;
    }

    nread = fread(magic, 1, 2, fp);
    if (nread != 2)
    {
    perror(“SDL-zlib”);
    return NULL;
    }

    if (magic[0] == 0x1f && magic[1] == 0x8b)
    {
    /* gzip /
    fclose(fp);
    ops = SDL_AllocRW();
    if (ops != NULL)
    {
    ops->seek = sdlzlib_seek;
    ops->read = sdlzlib_read;
    ops->write = sdlzlib_write;
    ops->close = sdlzlib_close;
    ops->hidden.unknown.data1 = gzopen(file, mode);
    if (ops->hidden.unknown.data1 == NULL)
    {
    /
    gzopen failed! */
    ops = NULL;
    }
    }
    return ops;
    }
    else
    return SDL_RWFromFP(fp, 1);
    }–
    Albert ``Willy’’ Lee, Emacs user, game programmer
    "They call me CRAZY - just because I DARE to DREAM of a RACE of
    SUPERHUMAN MONSTERS!"