I did this (well, a little bit more complicated, with compression and
stuff…) and everything works great, except that MP3 musics had to be
extracted to a regular file before being read. Apparently the code in
SDL_Mixer that detects MP3 files if not working or I have some problems
with my MP3 files and they were not being loaded properly directly from
a SDL_RWops. OGG works fine though.
IIRC, there’s the same problem when trying to read TTF files using
SDL_ttf, too. The problem is that when creating a SDL_RWops structure from
an open file handle, you can’t limit the SDL_RWops to a subsection of the
file.
Any request to seek to the beginning/end of the SDL_RWops seeks to the
beginning/end of the containing file, not to the end of the logical file
within. This can be fixed by creating SDL_RWops manually.
struct rw_fp {
FILE *fp;
int begin, size, pos;
bool autoclose;
};
int rw_fp_seek(SDL_RWops *ctx, int offset, int whence) {
struct rw_fp data = (struct rw_fp) ctx->hidden.unknown.data1;
switch (whence) {
case SEEK_SET:
data->pos = offset;
break;
case SEEK_CUR:
data->pos += offset;
break;
case SEEK_END:
data->pos = data->size+offset;
break;
default:
return -1;
break;
}
if (data->pos<0) data->pos = 0;
if (data->pos>data->size) data->pos = data->size;
if (fseek(data->fp,data->begin+data->pos,SEEK_SET)==0)
return data->pos;
// SDL_Error(SDL_EFSEEK);
return -1;
}
int rw_fp_read(SDL_RWops *ctx, void ptr, int size, int maxnum) {
struct rw_fp data = (struct rw_fp) ctx->hidden.unknown.data1;
int n = maxnum;
int n2 = (data->size-data->pos)/size;
if (n2<n) n = n2;
// if (data->pos == data->size) return -1;
n = fread(ptr,size,n,data->fp);
data->pos += nsize;
// if (n==0 && ferror(data->fp))
// SDL_Error(SDL_EFREAD);
return n;
}
int rw_fp_write(SDL_RWops *ctx, const void ptr, int size, int num) {
struct rw_fp data = (struct rw_fp) ctx->hidden.unknown.data1;
int n = num;
int n2 = (data->size-data->pos)/size;
if (n2<n) n = n2;
// if (data->pos == data->size) return -1;
n = fwrite(ptr,size,n,data->fp);
data->pos += nsize;
// if (n==0 && ferror(data->fp))
// SDL_Error(SDL_EFWRITE);
return n;
}
int rw_fp_close(SDL_RWops *ctx) {
struct rw_fp data = (struct rw_fp) ctx->hidden.unknown.data1;
if (data->autoclose)
fclose(data->fp);
free(data);
free(ctx);
return 0;
}
SDL_RWops *rwFromFP(FILE *in, int size, bool autoclose = true) {
SDL_RWops rw = (SDL_RWops) malloc(sizeof(SDL_RWops));
if (rw==NULL) return NULL;
rw->hidden.unknown.data1 = malloc(sizeof(struct rw_fp));
if (rw->hidden.unknown.data1==NULL) {
free(rw);
return NULL;
}
struct rw_fp data = (struct rw_fp) rw->hidden.unknown.data1;
data->fp = in;
data->begin = ftell(in);
data->size = size;
data->pos = 0;
data->autoclose = autoclose;
rw->seek = rw_fp_seek;
rw->read = rw_fp_read;
rw->write = rw_fp_write;
rw->close = rw_fp_close;
return rw;
}
This allows you to create a SDL_RWops structure essentially containing
only a part of the file, which allows seeking back and forth. If others
see a need for this, I’d be glad to see this integrated into SDL.
// MartinOn Tue, 3 Apr 2007, Andre de Leiradella wrote: