
static JSValue fileio_constructor(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv)
{
	JSValue anobj;
	JSFileIOCtx *ioctx;
	char *full_url;
	const char *parent;

	if (argc != 9) return GF_JS_EXCEPTION(ctx);
	if (!JS_IsString(argv[0])) return GF_JS_EXCEPTION(ctx);
	//open
	if (!JS_IsFunction(ctx, argv[1]) || JS_IsNull(argv[1])) return GF_JS_EXCEPTION(ctx);
	//close
	if (!JS_IsFunction(ctx, argv[2]) || JS_IsNull(argv[2])) return GF_JS_EXCEPTION(ctx);
	//write, can be null
	if (!JS_IsFunction(ctx, argv[3]) || JS_IsNull(argv[3])) {
		if (!JS_IsFunction(ctx, argv[4]) || JS_IsNull(argv[4])) return GF_JS_EXCEPTION(ctx);
	}
	//read, can be null
	if (!JS_IsFunction(ctx, argv[4]) || JS_IsNull(argv[4])) {
		if (!JS_IsFunction(ctx, argv[3]) || JS_IsNull(argv[3])) return GF_JS_EXCEPTION(ctx);
	}
	//seek
	if (!JS_IsFunction(ctx, argv[5]) || JS_IsNull(argv[5])) return GF_JS_EXCEPTION(ctx);
	//tell
	if (!JS_IsFunction(ctx, argv[6]) || JS_IsNull(argv[6])) return GF_JS_EXCEPTION(ctx);
	//eos
	if (!JS_IsFunction(ctx, argv[7]) || JS_IsNull(argv[7])) return GF_JS_EXCEPTION(ctx);
	//exists
	if (!JS_IsFunction(ctx, argv[8]) || JS_IsNull(argv[8])) return GF_JS_EXCEPTION(ctx);

	const char *url = JS_ToCString(ctx, argv[0]);
	if (!url) return GF_JS_EXCEPTION(ctx);

	GF_SAFEALLOC(ioctx, JSFileIOCtx);
	if (!ioctx) return js_throw_err(ctx, GF_OUT_OF_MEM);
	GF_SAFEALLOC(ioctx->factory, JSFileIOFactoryCtx);
	if (!ioctx->factory) {
		gf_free(ioctx);
		return js_throw_err(ctx, GF_OUT_OF_MEM);
	}
	ioctx->factory->url_pending = gf_list_new();
	if (!ioctx->factory->url_pending) {
		gf_free(ioctx->factory);
		gf_free(ioctx);
		return js_throw_err(ctx, GF_OUT_OF_MEM);
	}

	anobj = JS_NewObjectClass(ctx, fileio_class_id);
	if (JS_IsException(anobj)) {
		gf_free(ioctx);
		return anobj;
	}
	JS_SetOpaque(anobj, ioctx);
	ioctx->factory->open = JS_DupValue(ctx, argv[1]);
	ioctx->factory->close = JS_DupValue(ctx, argv[2]);
	ioctx->factory->write = JS_DupValue(ctx, argv[3]);
	ioctx->factory->read = JS_DupValue(ctx, argv[4]);
	ioctx->factory->seek = JS_DupValue(ctx, argv[5]);
	ioctx->factory->tell = JS_DupValue(ctx, argv[6]);
	ioctx->factory->eof = JS_DupValue(ctx, argv[7]);
	ioctx->factory->exists = JS_DupValue(ctx, argv[8]);
	ioctx->factory->factory_obj = JS_DupValue(ctx, anobj);
	ioctx->factory->ctx = ctx;
	ioctx->js_obj = JS_UNDEFINED;
	ioctx->factory->root = ioctx;

	parent = jsf_get_script_filename(ctx);
	full_url = gf_url_concatenate(parent, url);

	if (JS_IsUndefined(ioctx->factory->write)) {
		ioctx->gfio = gf_fileio_new((char *) full_url, ioctx, jsfio_open, jsfio_seek, jsfio_read, NULL, jsfio_tell, jsfio_eof, NULL);
	} else if (JS_IsUndefined(ioctx->factory->read)) {
		ioctx->gfio = gf_fileio_new((char *) full_url, ioctx, jsfio_open, jsfio_seek, NULL, jsfio_write, jsfio_tell, jsfio_eof, NULL);
	} else {
		ioctx->gfio = gf_fileio_new((char *) full_url, ioctx, jsfio_open, jsfio_seek, jsfio_read, jsfio_write, jsfio_tell, jsfio_eof, NULL);
	}
	JS_FreeCString(ctx, url);
	gf_free(full_url);
	return anobj;

static JSValue fileio_constructor(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv)
{
	JSValue anobj;
	JSFileIOCtx *ioctx;
	char *full_url;
	const char *parent;

	if (argc != 9) return GF_JS_EXCEPTION(ctx);
	if (!JS_IsString(argv[0])) return GF_JS_EXCEPTION(ctx);
	 
	if (!JS_IsFunction(ctx, argv[1]) || JS_IsNull(argv[1])) return GF_JS_EXCEPTION(ctx);
	 
	if (!JS_IsFunction(ctx, argv[2]) || JS_IsNull(argv[2])) return GF_JS_EXCEPTION(ctx);
	 
	if (!JS_IsFunction(ctx, argv[3]) || JS_IsNull(argv[3])) {
		if (!JS_IsFunction(ctx, argv[4]) || JS_IsNull(argv[4])) return GF_JS_EXCEPTION(ctx);
	}
	 
	if (!JS_IsFunction(ctx, argv[4]) || JS_IsNull(argv[4])) {
		if (!JS_IsFunction(ctx, argv[3]) || JS_IsNull(argv[3])) return GF_JS_EXCEPTION(ctx);
	}
	 
	if (!JS_IsFunction(ctx, argv[5]) || JS_IsNull(argv[5])) return GF_JS_EXCEPTION(ctx);
	 
	if (!JS_IsFunction(ctx, argv[6]) || JS_IsNull(argv[6])) return GF_JS_EXCEPTION(ctx);
	 
	if (!JS_IsFunction(ctx, argv[7]) || JS_IsNull(argv[7])) return GF_JS_EXCEPTION(ctx);
	 
	if (!JS_IsFunction(ctx, argv[8]) || JS_IsNull(argv[8])) return GF_JS_EXCEPTION(ctx);

	const char *url = JS_ToCString(ctx, argv[0]);
	if (!url) return GF_JS_EXCEPTION(ctx);

	GF_SAFEALLOC(ioctx, JSFileIOCtx);
	if (!ioctx) return js_throw_err(ctx, GF_OUT_OF_MEM);
	GF_SAFEALLOC(ioctx->factory, JSFileIOFactoryCtx);
	if (!ioctx->factory) {
		gf_free(ioctx);
		return js_throw_err(ctx, GF_OUT_OF_MEM);
	}
	ioctx->factory->url_pending = gf_list_new();
	if (!ioctx->factory->url_pending) {
		gf_free(ioctx->factory);
		gf_free(ioctx);
		return js_throw_err(ctx, GF_OUT_OF_MEM);
	}

	anobj = JS_NewObjectClass(ctx, fileio_class_id);
	if (JS_IsException(anobj)) {
		gf_free(ioctx);
		return anobj;
	}
	JS_SetOpaque(anobj, ioctx);
	ioctx->factory->open = JS_DupValue(ctx, argv[1]);
	ioctx->factory->close = JS_DupValue(ctx, argv[2]);
	ioctx->factory->write = JS_DupValue(ctx, argv[3]);
	ioctx->factory->read = JS_DupValue(ctx, argv[4]);
	ioctx->factory->seek = JS_DupValue(ctx, argv[5]);
	ioctx->factory->tell = JS_DupValue(ctx, argv[6]);
	ioctx->factory->eof = JS_DupValue(ctx, argv[7]);
	ioctx->factory->exists = JS_DupValue(ctx, argv[8]);
	ioctx->factory->factory_obj = JS_DupValue(ctx, anobj);
	ioctx->factory->ctx = ctx;
	ioctx->js_obj = JS_UNDEFINED;
	ioctx->factory->root = ioctx;

	parent = jsf_get_script_filename(ctx);
	full_url = gf_url_concatenate(parent, url);

	if (JS_IsUndefined(ioctx->factory->write)) {
		ioctx->gfio = gf_fileio_new((char *) full_url, ioctx, jsfio_open, jsfio_seek, jsfio_read, NULL, jsfio_tell, jsfio_eof, NULL);
	} else if (JS_IsUndefined(ioctx->factory->read)) {
		ioctx->gfio = gf_fileio_new((char *) full_url, ioctx, jsfio_open, jsfio_seek, NULL, jsfio_write, jsfio_tell, jsfio_eof, NULL);
	} else {
		ioctx->gfio = gf_fileio_new((char *) full_url, ioctx, jsfio_open, jsfio_seek, jsfio_read, jsfio_write, jsfio_tell, jsfio_eof, NULL);
	}
	JS_FreeCString(ctx, url);
	gf_free(full_url);
	return anobj;