Example #1
0
SDL_RWops *
SDL_RWFromFile(const char *file, const char *mode)
{
    SDL_RWops *rwops = NULL;
#ifdef HAVE_STDIO_H
    FILE *fp = NULL;
#endif
    if (!file || !*file || !mode || !*mode) {
        SDL_SetError("SDL_RWFromFile(): No file or no mode specified");
        return NULL;
    }
#if defined(ANDROID) && 0

    rwops = SDL_AllocRW();
    if (!rwops)
        return NULL;            /* SDL_SetError already setup by SDL_AllocRW() */
    if (Android_JNI_FileOpen(rwops, file, mode) < 0) {
        SDL_FreeRW(rwops);
        return NULL;
    }
    rwops->seek = Android_JNI_FileSeek;
    rwops->read = Android_JNI_FileRead;
    rwops->write = Android_JNI_FileWrite;
    rwops->close = Android_JNI_FileClose;

#elif defined(__WIN32__)
    rwops = SDL_AllocRW();
    if (!rwops)
        return NULL;            /* SDL_SetError already setup by SDL_AllocRW() */
    if (windows_file_open(rwops, file, mode) < 0) {
        SDL_FreeRW(rwops);
        return NULL;
    }
    rwops->seek = windows_file_seek;
    rwops->read = windows_file_read;
    rwops->write = windows_file_write;
    rwops->close = windows_file_close;

#elif HAVE_STDIO_H
	#ifdef __APPLE__
	fp = SDL_OpenFPFromBundleOrFallback(file, mode);
    #else
	fp = fopen(file, mode);
	#endif
	if (fp == NULL) {
        SDL_SetError("Couldn't open %s", file);
    } else {
        rwops = SDL_RWFromFP(fp, 1);
    }
#else
    SDL_SetError("SDL not compiled with stdio support");
#endif /* !HAVE_STDIO_H */

    return (rwops);
}
Example #2
0
static SDL_RWops* common_alloc(SDL_RWops *wrapped, size_t bufsize, bool autoclose) {
	SDL_RWops *rw = SDL_AllocRW();

	if(!rw) {
		return NULL;
	}

	if(bufsize < MIN_CHUNK_SIZE) {
		bufsize = MIN_CHUNK_SIZE;
	}

	memset(rw, 0, sizeof(SDL_RWops));

	rw->type = SDL_RWOPS_UNKNOWN;
	rw->size = common_size;
	rw->seek = common_seek;
	rw->close = common_close;

	ZData *z = calloc(1, sizeof(ZData));
	z->stream = calloc(1, sizeof(z_stream));
	z->buffer_size = bufsize;
	z->buffer = z->buffer_ptr = calloc(1, bufsize);

	z->wrapped = wrapped;
	z->autoclose = autoclose;

	rw->hidden.unknown.data1 = z;

	return rw;
}
static SDL_RWops* getFileForSDL(const char * filename)
{
    filesystem::ReadFile * file = new filesystem::ReadFile(filename);

    if ( ! file->isOpen() )
    {
        delete file;
        return 0;
    }

    SDL_RWops * rwops = SDL_AllocRW();
    if ( ! rwops )
    {
        delete file;
        return 0;
    }

    rwops->seek =RWOps_Seek;
    rwops->read =RWOps_Read;
    rwops->write=RWOps_Write;
    rwops->close=RWOps_Close;
    rwops->type =0xdeadbeef;
    rwops->hidden.unknown.data1 = file;

    return rwops;
}
Example #4
0
SDL_RWops *SDL_RWFromZZIP(const char* file, const char* mode)
{
    register SDL_RWops* rwops;
    register ZZIP_FILE* zzip_file;

    if (! strchr (mode, 'r'))
        return SDL_RWFromFile(file, mode);

    zzip_file = zzip_fopen (file, mode);
    if (! zzip_file) return 0;

    rwops = SDL_AllocRW ();
    if (! rwops) {
        errno=ENOMEM;
        zzip_close (zzip_file);
        return 0;
    }

    SDL_RWOPS_ZZIP_DATA(rwops) = zzip_file;
    rwops->read = _zzip_read;
    rwops->write = _zzip_write;
    rwops->seek = _zzip_seek;
    rwops->close = _zzip_close;
    return rwops;
}
Example #5
0
SDL_RWops* RWopsFromPythonThreaded(PyObject* obj)
{
	SDL_RWops* rw;
	RWHelper* helper;
        PyInterpreterState* interp;
        PyThreadState* thread;

	if(!obj)
		return (SDL_RWops*)RAISE(PyExc_TypeError, "Invalid filetype object");

        rw = get_standard_rwop(obj);
        if(rw)
                return rw;

#ifndef WITH_THREAD
        return (SDL_RWops*)RAISE(PyExc_NotImplementedError, "Python built without thread support");
#else
        helper = PyMem_New(RWHelper, 1);
        fetch_object_methods(helper, obj);

        rw = SDL_AllocRW();
        rw->hidden.unknown.data1 = (void*)helper;
        rw->seek = rw_seek_th;
        rw->read = rw_read_th;
        rw->write = rw_write_th;
        rw->close = rw_close_th;

        PyEval_InitThreads();
        thread = PyThreadState_Get();
        interp = thread->interp;
        helper->thread = PyThreadState_New(interp);

	return rw;
#endif
}
Example #6
0
	Music::Music(asset::istream stream) throw(Music_loading_failed) :
	    _handle(nullptr, Mix_FreeMusic), _stream(std::make_unique<asset::istream>(std::move(stream))){

		auto id = _stream->aid();

#ifndef EMSCRIPTEN
		SDL_RWops *rwops = SDL_AllocRW();
		INVARIANT(rwops, "SDL_AllocRW failed");

		rwops->seek = istream_seek;
		rwops->read = istream_read;
		rwops->write = NULL;
		rwops->close = istream_close;
		rwops->hidden.unknown.data1 = _stream.get();

		_handle.reset(Mix_LoadMUS_RW(rwops, 1));

#else
		auto location = _stream->physical_location();
		_stream.reset();

		if(location.is_nothing())
			return;

		_handle.reset(Mix_LoadMUS(location.get_or_throw().c_str()));
#endif

		if(!_handle){
			WARN("Mix_LoadMUS_RW ("<<id.str()<<") failed: " << Mix_GetError());
		}

	}
Example #7
0
SDL_RWops *
SDL_RWFromConstMem(const void *mem, int size)
{
    SDL_RWops *rwops = NULL;
    if (!mem) {
      SDL_InvalidParamError("mem");
      return rwops;
    }
    if (!size) {
      SDL_InvalidParamError("size");
      return rwops;
    }

    rwops = SDL_AllocRW();
    if (rwops != NULL) {
        rwops->size = mem_size;
        rwops->seek = mem_seek;
        rwops->read = mem_read;
        rwops->write = mem_writeconst;
        rwops->close = mem_close;
        rwops->hidden.mem.base = (Uint8 *) mem;
        rwops->hidden.mem.here = rwops->hidden.mem.base;
        rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
        rwops->type = SDL_RWOPS_MEMORY_RO;
    }
    return rwops;
}
Example #8
0
SDL_RWops *SDL_RWFromFP(FILE *fp, int autoclose)
{
	SDL_RWops *rwops;

#ifdef WIN32
	if ( ! in_sdl ) {
		SDL_SetError("You can't pass a FILE pointer to a DLL (??)");
		/*return(NULL);*/
	}
#endif
	rwops = SDL_AllocRW();
	if ( rwops != NULL ) {
		rwops->seek = stdio_seek;
		rwops->read = stdio_read;
		rwops->write = stdio_write;
		rwops->close = stdio_close;
		rwops->Getc = stdio_getc; //maks
		rwops->Putc = stdio_putc; //maks
		rwops->hidden.stdio.fp = fp;
		rwops->hidden.stdio.autoclose = autoclose;

		//maks
		rwops->filePosition = rwops->stdioFilePosition = ftell(rwops->hidden.stdio.fp);
	}
	return(rwops);
}
static VALUE
fileIntForPath(const char *path, bool rubyExc)
{
	SDL_RWops *ops = SDL_AllocRW();

	try
	{
		shState->fileSystem().openRead(*ops, path);
	}
	catch (const Exception &e)
	{
		SDL_FreeRW(ops);

		if (rubyExc)
			raiseRbExc(e);
		else
			throw e;
	}

	VALUE klass = rb_const_get(rb_cObject, rb_intern("FileInt"));

	VALUE obj = rb_obj_alloc(klass);

	setPrivateData(obj, ops);

	return obj;
}
Example #10
0
_TTF_Font *SharedFontState::getFont(std::string family,
                                    int size)
{
	/* Check for substitutions */
	if (p->subs.contains(family))
		family = p->subs[family];

	/* Find out if the font asset exists */
	const FontSet &req = p->sets[family];

	if (req.regular.empty() && req.other.empty())
	{
		/* Doesn't exist; use built-in font */
		family = "";
	}

	FontKey key(family, size);

	TTF_Font *font = p->pool.value(key);

	if (font)
		return font;

	/* Not in pool; open new handle */
	SDL_RWops *ops;

	if (family.empty())
	{
		/* Built-in font */
		ops = openBundledFont();
	}
	else
	{
		/* Use 'other' path as alternative in case
		 * we have no 'regular' styled font asset */
		const char *path = !req.regular.empty()
		                 ? req.regular.c_str() : req.other.c_str();

		ops = SDL_AllocRW();
		shState->fileSystem().openReadRaw(*ops, path, true);
	}

	// FIXME 0.9 is guesswork at this point
//	float gamma = (96.0/45.0)*(5.0/14.0)*(size-5);
//	font = TTF_OpenFontRW(ops, 1, gamma /** .90*/);
	font = TTF_OpenFontRW(ops, 1, size* .90);

	if (!font)
		throw Exception(Exception::SDLError, "%s", SDL_GetError());

	p->pool.insert(key, font);

	return font;
}
Example #11
0
SDL_RWops *stream::rwops()
{
    SDL_RWops *rw = SDL_AllocRW();
    if(!rw) return NULL;
    rw->hidden.unknown.data1 = this;
    rw->seek = rwopsseek;
    rw->read = rwopsread;
    rw->write = rwopswrite;
    rw->close = rwopsclose;
    return rw;
}
Example #12
0
static SDL_RWops*
PyRWops_NewRW (PyObject *obj, int *canautoclose)
{
    _RWWrapper *wrapper;
    SDL_RWops *ops;
    
    if (!obj || !canautoclose)
    {
        PyErr_SetString (PyExc_TypeError, "argument is NULL");
        return NULL;
    }
    
    /* If we have a text object, assume it is a file, which is automatically
     * closed. */
    if (IsTextObj (obj))
    {
        PyObject *tmp;
        char *filename;
        if (!UTF8FromObj (obj, &filename, &tmp))
            return NULL;
        Py_XDECREF (tmp);
        *canautoclose = 1;
        ops = SDL_RWFromFile ((const char *)filename, "wb");
        if (!ops)
            PyErr_SetString (PyExc_PyGameError, SDL_GetError ());
        return ops;

    }

    /* No text object, so its a buffer or something like that. Try to get the
     * necessary information. */
    ops = SDL_AllocRW ();
    if (!ops)
    {
        PyErr_SetString (PyExc_PyGameError, SDL_GetError ());
        return NULL;
    }
    wrapper = PyMem_New (_RWWrapper, 1);
    if (!wrapper)
    {
        SDL_FreeRW (ops);
        return NULL;
    }
    _bind_python_methods (wrapper, obj);
    ops->read = _pyobj_read;
    ops->write = _pyobj_write;
    ops->seek = _pyobj_seek;
    ops->close = _pyobj_close;
    ops->hidden.unknown.data1 = (void*) wrapper;
    *canautoclose = 0;
    return ops;
}
Example #13
0
	SDL_RWops* UUT_API Stream::CreatReadRWops(Stream* source)
	{
		SDL_RWops* ops = SDL_AllocRW();

		ops->hidden.unknown.data1 = source;
		ops->size = &funcRWopsSize;
		ops->seek = &funcRWopsSeek;
		ops->read = &funcRWopsRead;
		ops->write = &funcRWopsWrite;
		ops->close = &funcRWopsClose;

		return ops;
	}
Example #14
0
static VALUE
fileIntForPath(const char *path)
{
    SDL_RWops *ops = SDL_AllocRW();
    shState->fileSystem().openRead(*ops, path);

    VALUE klass = rb_const_get(rb_cObject, rb_intern("FileInt"));

    VALUE obj = rb_obj_alloc(klass);

    setPrivateData(obj, ops);

    return obj;
}
Example #15
0
SDL_RWops *SDL_RWFromFP(FILE *fp, int autoclose)
{
    SDL_RWops *rwops = NULL;

    rwops = SDL_AllocRW();
    if ( rwops != NULL ) {
        rwops->seek = stdio_seek;
        rwops->read = stdio_read;
        rwops->write = stdio_write;
        rwops->close = stdio_close;
        rwops->hidden.stdio.fp = fp;
        rwops->hidden.stdio.autoclose = autoclose;
    }
    return(rwops);
}
Example #16
0
SDL_RWops *SDL_RWFromFD(file_t fd, int autoclose)
{
	SDL_RWops *rwops = NULL;

	rwops = SDL_AllocRW();
	if ( rwops != NULL ) {
		rwops->seek = dc_seek;
		rwops->read = dc_read;
		rwops->write = dc_write;
		rwops->close = dc_close;
		rwops->hidden.dc.fd = fd;
		rwops->hidden.dc.autoclose = autoclose;
	}
	return(rwops);
}
/**
 * @brief Tests alloc and free RW context.
 *
 * \sa http://wiki.libsdl.org/moin.cgi/SDL_AllocRW
 * \sa http://wiki.libsdl.org/moin.cgi/SDL_FreeRW
 */
int
rwops_testAllocFree (void)
{
   /* Allocate context */
   SDL_RWops *rw = SDL_AllocRW();
   SDLTest_AssertPass("Call to SDL_AllocRW() succeeded");
   SDLTest_AssertCheck(rw != NULL, "Validate result from SDL_AllocRW() is not NULL");
   if (rw==NULL) return TEST_ABORTED;
          
   /* Free context again */
   SDL_FreeRW(rw);
   SDLTest_AssertPass("Call to SDL_FreeRW() succeeded");

   return TEST_COMPLETED;
}
Example #18
0
SDL_RWops *SDL_RWFromConstMem(const void *mem, int size)
{
    SDL_RWops *rwops;

    rwops = SDL_AllocRW();
    if ( rwops != NULL ) {
        rwops->seek = mem_seek;
        rwops->read = mem_read;
        rwops->write = mem_writeconst;
        rwops->close = mem_close;
        rwops->hidden.mem.base = (Uint8 *)mem;
        rwops->hidden.mem.here = rwops->hidden.mem.base;
        rwops->hidden.mem.stop = rwops->hidden.mem.base+size;
    }
    return(rwops);
}
Example #19
0
SDL_RWops *SDL_RWFromRW(SDL_RWops *src, Sint64 off, Sint64 size) {
    SDL_RWops *c = SDL_AllocRW();
    if (c == NULL) return NULL;

    c->seek = rw_seekfunc;
    c->size = rw_sizefunc;
    c->read = rw_readfunc;
    c->write = rw_writefunc;
    c->close = rw_closefunc;
    c->type = SDL_RW_TAG_CURRENT;
    c->hidden.rwops.baseRW = src;
    c->hidden.rwops.current = off;
    c->hidden.rwops.begin = off;
    c->hidden.rwops.end = off + size;
    return c;
}
Example #20
0
SDL_RWops *SDL_RWFromMem(void *mem, int size)
{
        SDL_RWops *rwops;

        rwops = SDL_AllocRW();
        if ( rwops != NULL ) {
                rwops->seek = mem_seek;
                rwops->read = mem_read;
                rwops->write = mem_write;
                rwops->close = mem_close;
                rwops->hidden.mem.base = (unsigned char *)mem;
                rwops->hidden.mem.here = rwops->hidden.mem.base;
                rwops->hidden.mem.stop = rwops->hidden.mem.base+size;
        }
        return(rwops);
}
Example #21
0
SDL_RWops *SDL_RWFromFile(const char *file, const char *mode)
{
    SDL_RWops *rwops = NULL;
#ifdef HAVE_STDIO_H
    FILE *fp = NULL;
#endif
    if ( !file || !*file || !mode || !*mode ) {
        SDL_SetError("SDL_RWFromFile(): No file or no mode specified");
        return NULL;
    }

#if defined(__WIN32__) && !defined(__SYMBIAN32__)
    rwops = SDL_AllocRW();
    if (!rwops)
        return NULL; /* SDL_SetError already setup by SDL_AllocRW() */
    if (win32_file_open(rwops,file,mode) < 0) {
        SDL_FreeRW(rwops);
        return NULL;
    }
    rwops->seek  = win32_file_seek;
    rwops->read  = win32_file_read;
    rwops->write = win32_file_write;
    rwops->close = win32_file_close;

#elif HAVE_STDIO_H

#ifdef __MACOS__
    {
        char *mpath = unix_to_mac(file);
        fp = fopen(mpath, mode);
        SDL_free(mpath);
    }
#else
    fp = fopen(file, mode);
#endif
    if ( fp == NULL ) {
        SDL_SetError("Couldn't open %s", file);
    } else {
        rwops = SDL_RWFromFP(fp, 1);
    }
#else
    SDL_SetError("SDL not compiled with stdio support");
#endif /* !HAVE_STDIO_H */

    return(rwops);
}
Example #22
0
SDL_RWops *SDL_RWFromMultipleArchive(const char *file, const char *mode)
{
	SDL_RWops *rwops;
	SDL_RWIndex *index = indexArchive;

	if(!multipleFile || !file || mode[0] != 'r' || mode[1] != 'b') //Read binary
		return NULL;

	
	//Search file in table index
	while(index)
	{
		if(dirStrcmp(index->fileName, file) == 0)
		{
			break;
		}

		index = index->next;
	}

	if(!index) return NULL;

	if(!multipleArchiveMutEx) 
	{
		multipleArchiveMutEx = SDL_CreateMutex();
	}


	rwops = SDL_AllocRW();

	if ( rwops != NULL ) 
	{
		rwops->seek = multiple_seek;
		rwops->read = multiple_read;
		rwops->write = multiple_write;
		rwops->close = multiple_close;
		rwops->Getc = multiple_getc;
		rwops->Putc = multiple_putc;
		rwops->hidden.multiple.base = index->offset;
		rwops->hidden.multiple.here = rwops->hidden.multiple.base;
		rwops->hidden.multiple.stop = rwops->hidden.multiple.base + index->size;
	}

	openFileCount++;
	return(rwops);
}
Example #23
0
SDL_RWops *
SDL_RWFromFP(FILE * fp, SDL_bool autoclose)
{
    SDL_RWops *rwops = NULL;

    rwops = SDL_AllocRW();
    if (rwops != NULL) {
        rwops->size = stdio_size;
        rwops->seek = stdio_seek;
        rwops->read = stdio_read;
        rwops->write = stdio_write;
        rwops->close = stdio_close;
        rwops->hidden.stdio.fp = fp;
        rwops->hidden.stdio.autoclose = autoclose;
        rwops->type = SDL_RWOPS_STDFILE;
    }
    return rwops;
}
Example #24
0
/**
 * @brief Tests alloc and free RW context.
 *
 * \sa http://wiki.libsdl.org/moin.cgi/SDL_AllocRW
 * \sa http://wiki.libsdl.org/moin.cgi/SDL_FreeRW
 */
int
rwops_testAllocFree (void)
{
   /* Allocate context */
   SDL_RWops *rw = SDL_AllocRW();
   SDLTest_AssertPass("Call to SDL_AllocRW() succeeded");
   SDLTest_AssertCheck(rw != NULL, "Validate result from SDL_AllocRW() is not NULL");
   if (rw==NULL) return TEST_ABORTED;

   /* Check type */
   SDLTest_AssertCheck(
      rw->type == SDL_RWOPS_UNKNOWN,
      "Verify RWops type is SDL_RWOPS_UNKNOWN; expected: %d, got: %d", SDL_RWOPS_UNKNOWN, rw->type);

   /* Free context again */
   SDL_FreeRW(rw);
   SDLTest_AssertPass("Call to SDL_FreeRW() succeeded");

   return TEST_COMPLETED;
}
Example #25
0
static SDL_RWops *create_rwops(PHYSFS_File *handle)
{
    SDL_RWops *retval = NULL;

    if (handle == NULL)
        SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
    else
    {
        retval = SDL_AllocRW();
        if (retval != NULL)
        {
            retval->seek  = physfsrwops_seek;
            retval->read  = physfsrwops_read;
            retval->write = physfsrwops_write;
            retval->close = physfsrwops_close;
            retval->hidden.unknown.data1 = handle;
        } /* if */
    } /* else */

    return retval;
} /* create_rwops */
Example #26
0
SDL_RWops *SDL_RWFromBundle(Bundle *bundle, const char *filename)
{
	SDL_RWops *rwops;
	RWOpsBundle * b = calloc(1, sizeof(RWOpsBundle));
	b->handle = bundle->handle;
	
	for (int i = 0 ; i < bundle->n_files ; ++i)
	{
		if (strcmp(bundle->file[i].name, filename) == 0)
		{
			b->file = &bundle->file[i];
			break;
		}
	}
	
	if (!b->file)
	{
		free(b);
		return NULL;
	}
		
	rwops = SDL_AllocRW();
	
	if (rwops != NULL) 
	{
		rwops->seek = bnd_seek;
		rwops->read = bnd_read;
		rwops->write = NULL;
		rwops->close = bnd_close;
		rwops->hidden.unknown.data1 = b;
		
		rwops->seek(rwops, 0, SEEK_SET);
	}
	else
	{
		free(b);
	}
	
	return rwops;
}
Example #27
0
SDL_RWops *SDL_RWFromConstMem(const void *mem, int size)
{
	SDL_RWops *rwops;

	rwops = SDL_AllocRW();
	if ( rwops != NULL ) {
		rwops->seek = mem_seek;
		rwops->read = mem_read;
		rwops->write = mem_writeconst;
		rwops->close = mem_close;
		rwops->hidden.mem.base = (Uint8 *)mem;
		rwops->hidden.mem.here = rwops->hidden.mem.base;
		rwops->hidden.mem.stop = rwops->hidden.mem.base+size;

		//Maks: memory map files
		rwops->hidden.mem.hFile = NULL;
		rwops->hidden.mem.hMapping = NULL;	
		
		rwops->hidden.mem.bAutoExpand = 0;
	}
	return(rwops);
}
Example #28
0
rwops_ptr make_write_RWops(const std::string &path) {
	rwops_ptr rw(SDL_AllocRW(), &SDL_FreeRW);

	rw->size = &ofs_size;
	rw->seek = &ofs_seek;
	rw->read = &ofs_read;
	rw->write = &ofs_write;
	rw->close = &ofs_close;

	rw->type = write_type;

	scoped_ostream ofs = ostream_file(path);
	if(!ofs) {
		ERR_FS << "make_write_RWops: ostream_file returned NULL on " << path << '\n';
		rw.reset();
		return rw;
	}

	rw->hidden.unknown.data1 = ofs.release();

	return rw;
}
Example #29
0
SDL_RWops *SDL_RWFromZip(struct zip *z,const char *fname) {
    zip_file_t* zf;
    struct zip_stat st;
    Sint64 idx = zip_name_locate(z, fname, 0);

    if ( idx < 0){
        SDL_SetError("Can't find file %s",fname);
        return NULL;
    }
    //printf("Found file %s with idx %ld\n",fname,idx);

    zf=zip_fopen_index(z,idx,ZIP_FL_UNCHANGED);
    if(zf == NULL ){
        zip_error_t *error = zip_get_error(z);
        SDL_SetError("PCK_RWFromZip failed for idx=%ld:%s", idx,zip_error_strerror(error));
        zip_error_fini(error);
        return NULL;
    }

    zip_stat_init(&st);
    if (zip_stat_index(z, idx, 0, &st) == 0) {
    }
    SDL_RWops *c = SDL_AllocRW();
    if (c == NULL) return NULL;

    c->seek = sdl_zip_seekfunc;
    c->size = sdl_zip_sizefunc;
    c->read = sdl_zip_readfunc;
    c->write = sdl_zip_writefunc;
    c->close = sdl_zip_closefunc;
    c->type = SDL_RW_TAG_CURRENT;
    ZipInfo* zi = SDL_malloc(sizeof(ZipInfo));
    zi->size = st.size;
    zi->zip = z;

    c->hidden.unknown.data1 = zf;
    c->hidden.unknown.data2 = zi;
    return c;
}
SDL_RWops *sdl_rw_from_rfork(const char *file, bool writable)
{
	SDL_RWops *rwops = NULL;

	int fd = open(file, writable ? O_RDWR : O_RDONLY);
	if (fd < 0) {
		SDL_SetError("Couldn't open %s", file);
		return NULL;
	} else {
		struct attr_info info;
		fs_stat_attr(fd, ATTR_NAME, &info);

		rwops = SDL_AllocRW();
		if (rwops == NULL) {
			close(fd);
			return NULL;
		}

		rfork_data *d = (rfork_data *)malloc(sizeof(struct rfork_data));
		if (d == NULL) {
			free(rwops);
			close(fd);
			return NULL;
		}

		d->fd = fd;
		d->current = 0;
		d->size = info.size;

		rwops->seek = rfork_seek;
		rwops->read = rfork_read;
		rwops->write = rfork_write;
		rwops->close = rfork_close;
		rwops->hidden.unknown.data1 = d;

		return rwops;
	}
}