Example #1
1
bool transferFunction(lua_State* toL, lua_State* fromL)
{
    bool result = false;
    if (!lua_iscfunction(fromL, -1) && lua_isfunction(fromL, -1))
    {
        try
        {
            TransferBuffer tb;
            if (lua_dump(fromL, functionWriter, &tb) == 0)
            {
                // sigh, was hoping to do this without any ifdefs... 
                // alas, i don't see how this one can be avoided
                #if LUA_VERSION_NUM > 501
                if (lua_load(toL, functionReader, &tb, "transferFunction", NULL) == 0)
                    result = true;
                #else
                if (lua_load(toL, functionReader, &tb, "transferFunction") == 0)
                    result = true;
                #endif
            }
        }
        catch (const std::exception& e)
        {
            (void) e;
            // catch a std::bad_alloc
            result = false;
        }
    }
    
    return result;
}
Example #2
0
static const char* luv_thread_dumped(lua_State* L, int idx, size_t* l) {
  if (lua_isstring(L, idx)) {
    return lua_tolstring(L, idx, l);
  } else {
    const char* buff = NULL;
    int top = lua_gettop(L);
    luaL_Buffer b;
    luaL_checktype(L, idx, LUA_TFUNCTION);
    lua_pushvalue(L, idx);
    luaL_buffinit(L, &b);
#if LUA_VERSION_NUM>=503
    int test_lua_dump = (lua_dump(L, thread_dump, &b, 1) == 0);
#else
    int test_lua_dump = (lua_dump(L, thread_dump, &b) == 0);
#endif
    if (test_lua_dump) {
      luaL_pushresult(&b);
      buff = lua_tolstring(L, -1, l);
    } else
      luaL_error(L, "Error: unable to dump given function");
    lua_settop(L, top);

    return buff;
  }
}
Example #3
0
static const char *tek_lib_exec_dump(lua_State *L, size_t *len)
{
	luaL_Buffer b;
	luaL_buffinit(L, &b);
#if LUA_VERSION_NUM < 503
	lua_dump(L, tek_lib_exec_write, &b);
#else
	lua_dump(L, tek_lib_exec_write, &b, 0);
#endif
	luaL_pushresult(&b);
	lua_remove(L, -2);
	return luaL_checklstring(L, -1, len);
}
Example #4
0
/**
* @brief	Attempts to compile a Lua script.
*
* @param	filename	Filename of the script.
* @param	buffer  	The buffer to store the script's compiled bytecode.
*
* @return	true if it succeeds, false if it fails.
*/
bool CLuaScript::CompileScript(const char * filename, BytecodeBuffer & buffer)
{
	// ensure that we wait until the last user's done executing their script.
	Guard lock(m_lock);

	/* Attempt to load the file */
	int err = luaL_loadfile(m_luaState, filename);

	// If something bad happened, try to find an error.
	if (err != LUA_OK)
	{
		RetrieveLoadError(err, filename);
		return false;
	}

	// Everything's OK so far, the script has been loaded, now we need to start dumping it to bytecode.
	err = lua_dump(m_luaState, (lua_Writer)LoadBytecodeChunk, &buffer);
	if (err
		|| buffer.empty())
	{
		printf("ERROR: Failed to dump the Lua script `%s` to bytecode.\n", filename);
		return false;
	}

	// Compiled!
	return true;
}
Example #5
0
static void serialize_function(lua_State *L, luaL_Buffer* b, int pos) {
    lua_pushvalue(L, pos);
    luaL_buffinit(L, b);
    if (lua_dump(L, f_writer, b) != 0)
        luaL_error(L, "cannot serialize: unable to dump function");
    luaL_pushresult(b);
    lua_remove(L, -2); // consume the function, leave the serialized string on the stack
}
int LuaScriptEngine::Compiler::dumper(lua_State* L)
{
    Options* opt = static_cast<Options*>(lua_touserdata(L, 1));

    int result = lua_dump(L, Compiler::writer, opt->s, !opt->stripDebug);

    return 0;
}
Example #7
0
	compiled_chunk* lua_context::compile_chunk(const std::string& name, const std::string& str)
	{
		compiled_chunk* chunk = new compiled_chunk();
		luaL_loadbuffer(context_ptr(), str.c_str(), str.size(), name.c_str());		// (-0,+1,-)
		lua_dump(context_ptr(), chunk_writer, reinterpret_cast<void*>(chunk));		// (-0,+0,-)
		lua_pop(context_ptr(), 1);													// (-n(1),+0,-)
		chunk->add_chunk(0, 0);
		return chunk;
	}
static int str_dump (lua_State *L) {
  luaL_Buffer b;
  luaL_checktype(L, 1, LUA_TFUNCTION);
  luaL_buffinit(L,&b);
  if (!lua_dump(L, writer, &b))
    luaL_error(L, "unable to dump given function");
  luaL_pushresult(&b);
  return 1;
}
Example #9
0
void lpi_broadcast_object(lua_State * L, int index, PI_BUNDLE * bundle)
{
    int n;


    if (luaL_getmetafield(L, index, "__recv"))
    {
        /* transmit __recv */
        lpi_broadcast_header(L, bundle, LUA_TUSERDATA, (lua_Number)0);
        lpi_broadcast_object(L, lua_gettop(L), bundle);
        lua_pop(L, 1);
    }
        
    
    if (luaL_getmetafield(L, index, "__send"))
    {
        lua_pushvalue(L, index);
        lua_call(L, 1, 1);
        lpi_broadcast_object(L, lua_gettop(L), bundle);
        lua_pop(L, 1);
        return;
    }
            
    
    switch(lua_type(L, index))
    {
        case LUA_TNIL:
            lpi_broadcast_header(L, bundle, LUA_TNIL, (lua_Number)0);
            break;
        case LUA_TNUMBER:
            lpi_broadcast_header(L, bundle, LUA_TNUMBER, lua_tonumber(L, index));
            break;
        case LUA_TBOOLEAN:
            lpi_broadcast_header(L, bundle, LUA_TBOOLEAN, (lua_Number)lua_toboolean(L, index));
            break;
        case LUA_TSTRING:
            lpi_broadcast_header(L, bundle, LUA_TSTRING, (lua_Number)lua_objlen(L, index));
            lpi_broadcast_data(L, bundle, lua_tostring(L, index), lua_objlen(L, index));
            break;
        case LUA_TFUNCTION:
            lua_pushvalue(L, index);
            n = lua_gettop(L);
            lua_dump(L, lpi_functionWriter, NULL);
            n = lua_gettop(L) - n;
            lua_concat(L, n);
            lpi_broadcast_header(L, bundle, LUA_TFUNCTION, (lua_Number)lua_objlen(L, -1));
            lpi_broadcast_data(L, bundle, lua_tostring(L, -1), lua_objlen(L, -1));
            lua_pop(L, 2);
            break;
        case LUA_TTABLE:
            lpi_broadcast_table(L, index, bundle);
            break;
        default:
            luaL_typerror(L, index, "nil, number, boolean, or string");
            break;
    }
}
Example #10
0
// Compile a script by name and dump it back to disk.
void LUA_DumpFile(const char *filename)
{
	FILE *handle;
	char filenamebuf[MAX_WADPATH];

	if (!gL) // Lua needs to be initialized
		LUA_ClearState(false);

	// find the file the SRB2 way
	strncpy(filenamebuf, filename, MAX_WADPATH);
	filenamebuf[MAX_WADPATH - 1] = '\0';
	filename = filenamebuf;
	if ((handle = fopen(filename, "rb")) == NULL)
	{
		// If we failed to load the file with the path as specified by
		// the user, strip the directories and search for the file.
		nameonly(filenamebuf);

		// If findfile finds the file, the full path will be returned
		// in filenamebuf == filename.
		if (findfile(filenamebuf, NULL, true))
		{
			if ((handle = fopen(filename, "rb")) == NULL)
			{
				CONS_Alert(CONS_ERROR, M_GetText("Can't open %s\n"), filename);
				return;
			}
		}
		else
		{
			CONS_Alert(CONS_ERROR, M_GetText("File %s not found.\n"), filename);
			return;
		}
	}
	fclose(handle);

	// pass the path we found to Lua
	// luaL_loadfile will open and read the file in as a Lua function
	if (luaL_loadfile(gL, filename)) {
		CONS_Alert(CONS_ERROR,"%s\n",lua_tostring(gL,-1));
		lua_pop(gL, 1);
		return;
	}

	// dump it back to disk
	if ((handle = fopen(filename, "wb")) == NULL)
		CONS_Alert(CONS_ERROR, M_GetText("Can't write to %s\n"), filename);
	if (lua_dump(gL, dumpWriter, handle))
		CONS_Printf("Failed while writing %s to disk... Sorry!\n", filename);
	else
		CONS_Printf("Successfully compiled %s into bytecode.\n", filename);
	fclose(handle);
	lua_pop(gL, 1); // function is still on stack after lua_dump
	lua_gc(gL, LUA_GCCOLLECT, 0);
	return;
}
Example #11
0
/**
 * @brief Copies the function on the top of src to the top of dst.
 *
 * It can be a Lua function or a C function.
 *
 * @param src source state
 * @param dst destination state
 */
static void sglua_copy_function(lua_State* src, lua_State* dst) {

  if (lua_iscfunction(src, -1)) {
    /* it's a C function */

    XBT_DEBUG("It's a C function");
    sglua_stack_dump("src before copying upvalues: ", src);

    /* get the function pointer */
    int function_index = lua_gettop(src);
    lua_CFunction f = lua_tocfunction(src, function_index);

    /* copy the upvalues */
    int i = 0;
    const char* upvalue_name = NULL;
    do {
      i++;
      upvalue_name = lua_getupvalue(src, function_index, i);

      if (upvalue_name != NULL) {
        XBT_DEBUG("Upvalue %s", upvalue_name);
        sglua_move_value(src, dst);
      }
    } while (upvalue_name != NULL);

    sglua_stack_dump("src before copying pointer: ", src);

    /* set the function */
    lua_pushcclosure(dst, f, i - 1);
    XBT_DEBUG("Function pointer copied");
  }
  else {
    /* it's a Lua function: dump it from src */

    s_sglua_buffer_t buffer;
    buffer.capacity = 128; /* an empty function uses 77 bytes */
    buffer.size = 0;
    buffer.data = xbt_new(char, buffer.capacity);

    /* copy the binary chunk from src into a buffer */
    _XBT_GNUC_UNUSED int error = lua_dump(src, sglua_memory_writer, &buffer);
    xbt_assert(!error, "Failed to dump the function from the source state: error %d",
        error);
    XBT_DEBUG("Fonction dumped: %zu bytes", buffer.size);

    /*
    fwrite(buffer.data, buffer.size, buffer.size, stderr);
    fprintf(stderr, "\n");
    */

    /* load the chunk into dst */
    error = luaL_loadbuffer(dst, buffer.data, buffer.size, "(dumped function)");
    xbt_assert(!error, "Failed to load the function into the destination state: %s",
        lua_tostring(dst, -1));
  }
}
Example #12
0
static int str_dump (lua_State *L) {
  luaL_Buffer b;
  int strip = lua_toboolean(L, 2);
  luaL_checktype(L, 1, LUA_TFUNCTION);
  lua_settop(L, 1);
  luaL_buffinit(L,&b);
  if (lua_dump(L, writer, &b, strip) != 0)
    return luaL_error(L, "unable to dump given function");
  luaL_pushresult(&b);
  return 1;
}
Example #13
0
static int set_bytecode(lua_State * L)
{
    int k, ltype;
    unsigned int i;
    k = (int) luaL_checkinteger(L, -2);
    i = (unsigned) k + 1;
    if ((int) (UINT_MAX32 / sizeof(bytecode) + 1) < i) {
        luaL_error(L, "value too large");
    }
    if (k < 0) {
        luaL_error(L, "negative values not allowed");
    }
    ltype = lua_type(L, -1);
    if (ltype != LUA_TFUNCTION && ltype != LUA_TNIL) {
        luaL_error(L, "unsupported type");
    }
    if (k > luabytecode_max) {
        i = (unsigned) (sizeof(bytecode) * ((unsigned) k + 1));
        lua_bytecode_registers = xrealloc(lua_bytecode_registers, i);
        if (luabytecode_max == -1) {
            luabytecode_bytes +=
                (unsigned) (sizeof(bytecode) * (unsigned) (k + 1));
        } else {
            luabytecode_bytes +=
                (unsigned) (sizeof(bytecode) *
                            (unsigned) (k + 1 - luabytecode_max));
        }
        for (i = (unsigned) (luabytecode_max + 1); i <= (unsigned) k; i++) {
            lua_bytecode_registers[i].buf = NULL;
            lua_bytecode_registers[i].size = 0;
            lua_bytecode_registers[i].done = 0;
        }
        luabytecode_max = k;
    }
    if (lua_bytecode_registers[k].buf != NULL) {
        xfree(lua_bytecode_registers[k].buf);
        luabytecode_bytes -= (unsigned) lua_bytecode_registers[k].size;
        lua_bytecode_registers[k].size = 0;
        lua_bytecode_registers[k].done = 0;
        lua_pushnil(L);
        bytecode_register_shadow_set(L, k);
    }
    if (ltype == LUA_TFUNCTION) {
        lua_bytecode_registers[k].buf = xmalloc(LOAD_BUF_SIZE);
        lua_bytecode_registers[k].alloc = LOAD_BUF_SIZE;
        memset(lua_bytecode_registers[k].buf, 0, LOAD_BUF_SIZE);
        lua_dump(L, writer, (void *) (lua_bytecode_registers + k));
    }
    lua_pop(L, 1);
    return 0;
}
Example #14
0
static int str_dump (lua_State *L) {
  luaL_Buffer *b = (luaL_Buffer *)kmalloc(sizeof(luaL_Buffer) + BUFSIZ, GFP_ATOMIC);
  if(!b) luaL_error(L, "str_dump: cannot allocate memory");
  luaL_checktype(L, 1, LUA_TFUNCTION);
  lua_settop(L, 1);
  luaL_buffinit(L,b);
  if (lua_dump(L, writer, b) != 0){
	  kfree(b);
	  luaL_error(L, "unable to dump given function");
  }

  luaL_pushresult(b);
  kfree(b);
  return 1;
}
Example #15
0
static void write_function( Transport *tpt, lua_State *L, int var_index )
{
  luaL_Buffer b;
  
  // push function onto stack, serialize to string 
  lua_pushvalue( L, var_index );
  luaL_buffinit( L, &b );
  lua_dump(L, writer, &b);
  
  // put string representation on stack and send it
  luaL_pushresult( &b );
  write_variable( tpt, L, lua_gettop( L ) );
  
  // Remove function & dumped string from stack
  lua_pop( L, 2 );
}
Example #16
0
static void pa_setcallback__(lua_State *L, int idx, pa_Stream *stream)
{
  luaL_Buffer b;
  size_t l;
  const char *str;
  lua_State *pa_L = stream->pa_L;

  if(!lua_isfunction(L, idx))
    luaL_error(L, "internal error: provided callback is not a function");

  lua_pushvalue(L, idx);
  luaL_buffinit(L, &b);
  if(lua_dump(L, pa_writer, &b) != 0)
  {
    lua_pop(L, 1);
    luaL_error(L, "invalid callback function -- cannot be dumped");
  }
  luaL_pushresult(&b);
  str = luaL_checklstring(L, -1, &l);

  lua_settop(pa_L, 0);
  if(luaL_loadbuffer(pa_L, str, l, NULL))
  {
    lua_pop(L, 2);
    luaL_error(L, "could not load the callback function properly");
  }
  
  if(lua_pcall(pa_L, 0, LUA_MULTRET, 0))
  {
    lua_pop(L, 2);
    luaL_error(L, "could not execute the callback function properly: %s", lua_tostring(pa_L, -1));
  }

  if(!((lua_gettop(pa_L) > 0) && lua_isfunction(pa_L, -1)))
  {
    lua_pop(L, 2);
    luaL_error(L, "the callback function did not return a function");
  }

  lua_pop(L, 2);
}
Example #17
0
	bool script::compile() {
		if (needs_recompilation) {
			int result = 0;
			bytecode.clear();

			if (is_associated_string_filename)
				result = luaL_loadstring(lua_state, get_file_contents(associated_string).c_str());
			else
				result = luaL_loadstring(lua_state, associated_string.c_str());

			if (result != 0)
				return false;
			else {
				lua_dump(lua_state, lua_writer, &bytecode, 0);
				lua_pop(lua_state, 1);
			}
		}

		needs_recompilation = false;
		return true;
	}
Example #18
0
/**
* @brief	Attempts to compile a Lua script.
*
* @param	filename	Filename of the script.
* @param	buffer  	The buffer to store the script's compiled bytecode.
*
* @return	true if it succeeds, false if it fails.
*/
bool CLuaScript::CompileScript(const char * filename, BytecodeBuffer & buffer)
{
	// ensure that we wait until the last user's done executing their script.
	FastGuard lock(m_lock);

	/* Attempt to load the file */
	int err = luaL_loadfile(m_luaState, filename);

	// If something bad happened, try to find an error.
	if (err != LUA_OK)
	{
		RetrieveLoadError(err, filename);
		return false;
	}

	// Everything's OK so far, the script has been loaded, now we need to start dumping it to bytecode.
	err = lua_dump(m_luaState, (lua_Writer)LoadBytecodeChunk, &buffer);
	if (err
		|| buffer.empty())
	{
		printf("ERROR: Failed to dump the Lua script `%s` to bytecode.\n", filename);
		return false;
	}

#if !defined(USE_ORIGINAL_QUESTS)
	// Load up the script & revert the stack.
	// This step's only here for cleanup purposes.
	err = lua_pcall(m_luaState, 0, LUA_MULTRET, 0);
	if (err != LUA_OK)
	{
		RetrieveLoadError(err, filename);
		return false;
	}
#endif

	// Compiled!
	return true;
}
Example #19
0
static int
lua_import_stream(stream_t* stream, const uuid_t uuid, luaimport_dump_t* dump) {
	lua_t* env;
	lua_State* state;
	int result = 0;
	lua_readstream_t read_stream = {
		.stream = stream,
	};

	env = lua_allocate();
	state = lua_state(env);

	if (lua_load(state, lua_read_stream, &read_stream, "import") != 0) {
		log_errorf(HASH_LUA, ERROR_INTERNAL_FAILURE, STRING_CONST("Lua load failed: %s"),
		           lua_tostring(state, -1));
		lua_pop(state, 1);
		result = -1;
		goto exit;
	}

	lua_dump(state, lua_import_dump_writer, dump);

	if (lua_pcall(state, 0, 0, 0) != 0) {
		log_errorf(HASH_LUA, ERROR_INTERNAL_FAILURE, STRING_CONST("Lua pcall failed: %s"),
		           lua_tostring(state, -1));
		lua_pop(state, 1);
		result = -1;
		goto exit;
	}

	log_debug(HASH_LUA, STRING_CONST("Lua bytecode dump successful"));

exit:

	lua_deallocate(env);

	return result;
}
Example #20
0
static int pmain(lua_State* L)
{
	struct Smain* s = (struct Smain*)lua_touserdata(L, 1);
	int argc=s->argc;
	char** argv=s->argv;
	int i;

	lua_pop(L,1);

	if (!lua_checkstack(L,argc)) fatal("too many input files");
	for (i=0; i<argc; i++)
	{
		const char* filename=IS("-") ? NULL : argv[i];
		if (luaL_loadfile(L,filename)!=0) fatal(lua_tostring(L,-1));

		if (dumping)
		{
			FILE* D= (output==NULL) ? stdout : fopen(output,(i > 0 ? "ab" : "wb"));
			if (D==NULL) cannot("open");

			char* bytecode = 0L;
			size_t len = 0;
			wdata wd = {&len, &bytecode};

			if(lua_dump(L, write_dump, &wd)) fatal("failed to dump bytecode");

			fwrite(bytecode,len,1,D);

			lua_pop(L,3);

			if (ferror(D)) cannot("write");
			if (fclose(D)) cannot("close");
		}

	}
	return 0;
}
Example #21
0
static int headerinfo (lua_State *L) {
  const char *dump;
  lua_settop(L, 1);
  if (lua_isnil(L, 1)) {
    if (luaL_loadstring(L, "return function () end") != LUA_OK)
      return Error(L, "unable to load dummy function");
    lua_replace(L, 1);
  }
  switch (lua_type(L, 1)) {
    case LUA_TSTRING: {
      size_t l;
      dump = lua_tolstring(L, 1, &l);
      if (l < HEADERSIZE || strncmp(LUA_SIGNATURE, dump, SIGSIZE) != 0)
        return Error(L, "not a valid Lua function dump");
      break;
    }
    case LUA_TFUNCTION: {
      luaL_Buffer b;
      luaL_buffinit(L, &b);
      if (lua_dump(L, Writer, &b) != LUA_OK)
        return Error(L, "unable to dump given function");
      luaL_pushresult(&b);
      lua_replace(L, 1);
      dump = lua_tostring(L, 1);
      break;
    }
    default: {
      return Error(L, "not a function or function dump");
    }
  }

  lua_createtable(L, 0, INFOSIZE);

  {
    int major = (GetInfo(dump, 0) >> 4);
    int minor = (GetInfo(dump, 0) & 0xf);
    lua_pushfstring(L, "%d.%d", major, minor);
    lua_setfield(L, 2, "version");
  }

  lua_pushinteger(L, GetInfo(dump, 1));
  lua_setfield(L, 2, "format");

  lua_pushstring(L, (GetInfo(dump, 2) ? "little-endian" : "big-endian"));
  lua_setfield(L, 2, "endianness");

  lua_pushinteger(L, GetInfo(dump, 3));
  lua_setfield(L, 2, "int_size");

  lua_pushinteger(L, GetInfo(dump, 4));
  lua_setfield(L, 2, "size_size");

  lua_pushinteger(L, GetInfo(dump, 5));
  lua_setfield(L, 2, "instruction_size");

  lua_pushinteger(L, GetInfo(dump, 6));
  lua_setfield(L, 2, "number_size");

  lua_pushboolean(L, GetInfo(dump, 7));
  lua_setfield(L, 2, "number_is_int");

  return 1;
}
Example #22
0
int CompileAspPage(lua_State *L, const char *asp_path,
        const struct AspEngineConfig *config, char **error_message)
{
    int requires_recompilation = 0;
    struct _stat asp_file_stat;
    struct _stat luac_file_stat;
    char cache_path[MAX_PATH];
    char lua_file[MAX_PATH];
    char luac_file[MAX_PATH];
    struct membuf *lua_content;
    lua_State *LL;
    int result;
    struct ReaderState reader_state;
    int use_cache;

    assert(((!config->cache_lua && !config->cache_luac) ||
            ((config->cache_lua || config->cache_luac)) &&
            config->root_path && config->cache_path));

    if (error_message != NULL)
        *error_message = NULL;

    if (config->cache_path && !RetargetPath(config->root_path, asp_path,
            config->cache_path, cache_path)) {
        use_cache = config->cache_lua || config->cache_luac;
    }
    else {
        use_cache = 0;
    }

    if (_stat(asp_path, &asp_file_stat) != 0) {
        if (error_message)
            *error_message = strdup(strerror(errno));
        return errno;
    }

    requires_recompilation = 1;

    if (use_cache) {
        CreateDirectories(cache_path);
        strcat(strcpy(lua_file, cache_path), ".lua");
        strcat(strcpy(luac_file, cache_path), ".luac");

        if (_stat(luac_file, &luac_file_stat) == 0) {
            if (asp_file_stat.st_mtime < luac_file_stat.st_mtime)
                requires_recompilation = 0;
        }
    }

    if (requires_recompilation) {
        lua_content = GenerateLuaFile(asp_path,
                (use_cache && config->cache_lua) ? lua_file : NULL,
                error_message);
        if (lua_content == NULL)
            return 1;
    }
    else {
        FILE *luac_fp = fopen(luac_file, "rb");
        if (luac_fp == NULL) {
            if (error_message)
                *error_message = strdup(strerror(errno));
            return 1;
        }

        lua_content = membuf_create(luac_file_stat.st_size,
                _dup(_fileno(luac_fp)), 1, 0);
        fclose(luac_fp);
    }

    reader_state.ptr = (char *)membuf_begin(lua_content);
    reader_state.end = (char *)membuf_end(lua_content);

    LL = L ? L : luaL_newstate();
    result = lua_load(LL, StringStreamReader, &reader_state, asp_path, NULL);
    if (result != LUA_OK) {
        membuf_close(lua_content);
        if (error_message)
            *error_message = strdup(lua_tostring(LL, -1));
        if (L == NULL)
            lua_close(LL);
        return 1;
    }

    membuf_close(lua_content);

    if (use_cache && requires_recompilation && config->cache_luac) {
        struct FileWriterState writer_state;

        writer_state.fp = fopen(luac_file, "wb");
        if (writer_state.fp != NULL) {
            lua_dump(LL, FileWriter, &writer_state);
            fclose(writer_state.fp);
        }
    }

    if (L != NULL) {
        result = lua_pcall(LL, 0, 0, 0);
        if (result && error_message)
            *error_message = strdup(lua_tostring(LL, -1));
    }
    else {
        lua_close(LL);
    }

    return result;
}
Example #23
0
void
·lua_dump(uintptr L, uintptr dumpinfo, uintptr ret) {
    ret = lua_dump((lua_State*)L, stubwriter, (void*)dumpinfo);
    FLUSH(&ret);
}
Example #24
0
static void mar_encode_value(lua_State *L, mar_Buffer *buf, int val, size_t *idx)
{
    size_t l;
    int val_type = lua_type(L, val);
    lua_pushvalue(L, val);

    buf_write(L, (void*)&val_type, MAR_CHR, buf);
    switch (val_type) {
    case LUA_TBOOLEAN: {
        int int_val = lua_toboolean(L, -1);
        buf_write(L, (void*)&int_val, MAR_CHR, buf);
        break;
    }
    case LUA_TSTRING: {
        const char *str_val = lua_tolstring(L, -1, &l);
        buf_write(L, (void*)&l, MAR_I32, buf);
        buf_write(L, str_val, l, buf);
        break;
    }
    case LUA_TNUMBER: {
        lua_Number num_val = lua_tonumber(L, -1);
        buf_write(L, (void*)&num_val, MAR_I64, buf);
        break;
    }
    case LUA_TTABLE: {
        int tag, ref;
        lua_pushvalue(L, -1);
        lua_rawget(L, SEEN_IDX);
        if (!lua_isnil(L, -1)) {
            ref = lua_tointeger(L, -1);
            tag = MAR_TREF;
            buf_write(L, (void*)&tag, MAR_CHR, buf);
            buf_write(L, (void*)&ref, MAR_I32, buf);
            lua_pop(L, 1);
        }
        else {
            mar_Buffer rec_buf;
            lua_pop(L, 1); /* pop nil */
            if (luaL_getmetafield(L, -1, "__persist")) {
                tag = MAR_TUSR;

                lua_pushvalue(L, -2); /* self */
                lua_call(L, 1, 1);
                if (!lua_isfunction(L, -1)) {
                    luaL_error(L, "__persist must return a function");
                }

                lua_remove(L, -2); /* __persist */

                lua_newtable(L);
                lua_pushvalue(L, -2); /* callback */
                lua_rawseti(L, -2, 1);

                buf_init(L, &rec_buf);
                mar_encode_table(L, &rec_buf, idx);

                buf_write(L, (void*)&tag, MAR_CHR, buf);
                buf_write(L, (void*)&rec_buf.head, MAR_I32, buf);
                buf_write(L, rec_buf.data, rec_buf.head, buf);
                buf_done(L, &rec_buf);
                lua_pop(L, 1);
            }
            else {
                tag = MAR_TVAL;

                lua_pushvalue(L, -1);
                lua_pushinteger(L, (*idx)++);
                lua_rawset(L, SEEN_IDX);

                lua_pushvalue(L, -1);
                buf_init(L, &rec_buf);
                mar_encode_table(L, &rec_buf, idx);
                lua_pop(L, 1);

                buf_write(L, (void*)&tag, MAR_CHR, buf);
                buf_write(L, (void*)&rec_buf.head, MAR_I32, buf);
                buf_write(L, rec_buf.data,rec_buf.head, buf);
                buf_done(L, &rec_buf);
            }
        }
        break;
    }
    case LUA_TFUNCTION: {
        int tag, ref;
        lua_pushvalue(L, -1);
        lua_rawget(L, SEEN_IDX);
        if (!lua_isnil(L, -1)) {
            ref = lua_tointeger(L, -1);
            tag = MAR_TREF;
            buf_write(L, (void*)&tag, MAR_CHR, buf);
            buf_write(L, (void*)&ref, MAR_I32, buf);
            lua_pop(L, 1);
        }
        else {
            mar_Buffer rec_buf;
            int i;
            lua_Debug ar;
            lua_pop(L, 1); /* pop nil */

            lua_pushvalue(L, -1);
            lua_getinfo(L, ">nuS", &ar);
            if (ar.what[0] != 'L') {
                luaL_error(L, "attempt to persist a C function '%s'", ar.name);
            }
            tag = MAR_TVAL;
            lua_pushvalue(L, -1);
            lua_pushinteger(L, (*idx)++);
            lua_rawset(L, SEEN_IDX);

            lua_pushvalue(L, -1);
            buf_init(L, &rec_buf);
            lua_dump(L, (lua_Writer)buf_write, &rec_buf);

            buf_write(L, (void*)&tag, MAR_CHR, buf);
            buf_write(L, (void*)&rec_buf.head, MAR_I32, buf);
            buf_write(L, rec_buf.data, rec_buf.head, buf);
            buf_done(L, &rec_buf);
            lua_pop(L, 1);

            lua_newtable(L);
            for (i=1; i <= ar.nups; i++) {
                lua_getupvalue(L, -2, i);
                lua_rawseti(L, -2, i);
            }

            buf_init(L, &rec_buf);
            mar_encode_table(L, &rec_buf, idx);

            buf_write(L, (void*)&rec_buf.head, MAR_I32, buf);
            buf_write(L, rec_buf.data, rec_buf.head, buf);
            buf_done(L, &rec_buf);
            lua_pop(L, 1);
        }

        break;
    }
    case LUA_TUSERDATA: {
        int tag, ref;
        lua_pushvalue(L, -1);
        lua_rawget(L, SEEN_IDX);
        if (!lua_isnil(L, -1)) {
            ref = lua_tointeger(L, -1);
            tag = MAR_TREF;
            buf_write(L, (void*)&tag, MAR_CHR, buf);
            buf_write(L, (void*)&ref, MAR_I32, buf);
            lua_pop(L, 1);
        }
        else {
            mar_Buffer rec_buf;
            lua_pop(L, 1); /* pop nil */
            if (luaL_getmetafield(L, -1, "__persist")) {
                tag = MAR_TUSR;

                lua_pushvalue(L, -2);
                lua_pushinteger(L, (*idx)++);
                lua_rawset(L, SEEN_IDX);

                lua_pushvalue(L, -2);
                lua_call(L, 1, 1);
                if (!lua_isfunction(L, -1)) {
                    luaL_error(L, "__persist must return a function");
                }
                lua_newtable(L);
                lua_pushvalue(L, -2);
                lua_rawseti(L, -2, 1);
                lua_remove(L, -2);

                buf_init(L, &rec_buf);
                mar_encode_table(L, &rec_buf, idx);

                buf_write(L, (void*)&tag, MAR_CHR, buf);
                buf_write(L, (void*)&rec_buf.head, MAR_I32, buf);
		buf_write(L, rec_buf.data, rec_buf.head, buf);
		buf_done(L, &rec_buf);
            }
            else {
                luaL_error(L, "attempt to encode userdata (no __persist hook)");
            }
            lua_pop(L, 1);
        }
        break;
    }
    case LUA_TNIL: break;
    default:
        luaL_error(L, "invalid value type (%s)", lua_typename(L, val_type));
    }
    lua_pop(L, 1);
}
Example #25
0
static void
dumpit ()
{
  lua_dump (lua_vm, writer, NULL);
}
Example #26
0
static void pack_value(lua_State *L, mar_Buffer *buf, int val, int *idx)
{
    size_t l;
    int val_type = lua_type(L, val);
    buf_write(L, (void*)&val_type, MAR_CHR, buf);
    switch (val_type) {
    case LUA_TBOOLEAN: {
        int int_val = lua_toboolean(L, val);
        buf_write(L, (void*)&int_val, MAR_CHR, buf);
        break;
    }
    case LUA_TSTRING: {
        const char *str_val = lua_tolstring(L, val, &l);
        buf_write(L, (void*)&l, MAR_I32, buf);
        buf_write(L, str_val, l, buf);
        break;
    }
    case LUA_TNUMBER: {
        lua_Number num_val = lua_tonumber(L, val);
        buf_write(L, (void*)&num_val, MAR_I64, buf);
        break;
    }
    case LUA_TTABLE: {
        int tag, ref;
        lua_pushvalue(L, val);
        lua_rawget(L, 2);
        if (!lua_isnil(L, -1)) {
            ref = lua_tointeger(L, -1);
            tag = MAR_TREF;
            buf_write(L, (void*)&tag, MAR_CHR, buf);
            buf_write(L, (void*)&ref, MAR_I32, buf);
            lua_pop(L, 1);
        }
        else {
            mar_Buffer rec_buf;
            lua_pop(L, 1);
            if (luaL_getmetafield(L, val, "__persist")) {
                tag = MAR_TUSR;

                lua_pushvalue(L, val-1);
                lua_pushinteger(L, (*idx)++);
                lua_rawset(L, 2);

                lua_pushvalue(L, val-1);
                lua_call(L, 1, 1);
                if (!lua_isfunction(L, -1)) {
                    luaL_error(L, "__persist must return a function");
                }
                lua_newtable(L);
                lua_pushvalue(L, -2);
                lua_rawseti(L, -2, 1);
                lua_remove(L, -2);

                buf_init(L, &rec_buf);
                mar_pack(L, &rec_buf, idx);


                buf_write(L, (void*)&tag, MAR_CHR, buf);
                buf_write(L, (void*)&rec_buf.head, MAR_I32, buf);
                buf_write(L, rec_buf.data, rec_buf.head, buf);
                buf_done(L, &rec_buf);
                lua_pop(L, 1);
            }
            else {
                tag = MAR_TVAL;

                lua_pushvalue(L, val);
                lua_pushinteger(L, (*idx)++);
                lua_rawset(L, 2);

                lua_pushvalue(L, val);
                buf_init(L, &rec_buf);
                mar_pack(L, &rec_buf, idx);

                buf_write(L, (void*)&tag, MAR_CHR, buf);
                buf_write(L, (void*)&rec_buf.head, MAR_I32, buf);
                buf_write(L, rec_buf.data,rec_buf.head, buf);
                buf_done(L, &rec_buf);
                lua_pop(L, 1);

            }
        }
        break;
    }
    case LUA_TFUNCTION: {
        int tag, ref;
        lua_pushvalue(L, val);
        lua_rawget(L, 2);
        if (!lua_isnil(L, -1)) {
            ref = lua_tointeger(L, -1);
            tag = MAR_TREF;
            buf_write(L, (void*)&tag, MAR_CHR, buf);
            buf_write(L, (void*)&ref, MAR_I32, buf);
            lua_pop(L, 1);
        }
        else {
            mar_Buffer rec_buf;
            int i;
            lua_Debug ar;
            lua_pop(L, 1);

            tag = MAR_TVAL;
            lua_pushvalue(L, val);
            lua_pushinteger(L, (*idx)++);
            lua_rawset(L, 2);

            lua_pushvalue(L, val);
            buf_init(L, &rec_buf);
            lua_dump(L, (lua_Writer)buf_write, &rec_buf);

            buf_write(L, (void*)&tag, MAR_CHR, buf);
            buf_write(L, (void*)&rec_buf.head, MAR_I32, buf);
	    buf_write(L, rec_buf.data, rec_buf.head, buf);
	    buf_done(L, &rec_buf);
	    lua_pop(L, 1);

            lua_pushvalue(L, val);
            lua_getinfo(L, ">uS", &ar);
            if (ar.what[0] != 'L') {
                luaL_error(L, "attempt to persist a C function");
            }

            lua_newtable(L);
            for (i=1; i <= ar.nups; i++) {
                lua_getupvalue(L, -2, i);
                lua_rawseti(L, -2, i);
            }

            buf_init(L, &rec_buf);
            mar_pack(L, &rec_buf, idx);

            buf_write(L, (void*)&rec_buf.head, MAR_I32, buf);
	    buf_write(L, rec_buf.data, rec_buf.head, buf);
	    buf_done(L, &rec_buf);
	    lua_pop(L, 1);
        }

        break;
    }
    case LUA_TUSERDATA: {
        int tag, ref;
        lua_pushvalue(L, val);
        lua_rawget(L, 2);
        if (!lua_isnil(L, -1)) {
            ref = lua_tointeger(L, -1);
            tag = MAR_TREF;
            buf_write(L, (void*)&tag, MAR_CHR, buf);
            buf_write(L, (void*)&ref, MAR_I32, buf);
            lua_pop(L, 1);
        }
        else {
            mar_Buffer rec_buf;
            lua_pop(L, 1);
            if (luaL_getmetafield(L, val, "__persist")) {
                tag = MAR_TUSR;

                lua_pushvalue(L, val-1);
                lua_pushinteger(L, (*idx)++);
                lua_rawset(L, 2);

                lua_pushvalue(L, val-1);
                lua_call(L, 1, 1);
                if (!lua_isfunction(L, -1)) {
                    luaL_error(L, "__persist must return a function");
                }
                lua_newtable(L);
                lua_pushvalue(L, -2);
                lua_rawseti(L, -2, 1);
                lua_remove(L, -2);

                buf_init(L, &rec_buf);
                mar_pack(L, &rec_buf, idx);

                buf_write(L, (void*)&tag, MAR_CHR, buf);
                buf_write(L, (void*)&rec_buf.head, MAR_I32, buf);
		buf_write(L, rec_buf.data, rec_buf.head, buf);
		buf_done(L, &rec_buf);
		lua_pop(L, 1);
            }
            else {
                tag = MAR_TVAL;
                buf_write(L, (void*)&tag, MAR_CHR, buf);
            }
        }
        break;
    }
    case LUA_TTHREAD: break; /* just give them a nil during unpack */
    default:
        luaL_error(L, "invalid value type");
    }
}
Example #27
0
static void mar_encode_value(lua_State *L, mar_Buffer *buf, int val, size_t *idx, int nowrap)
{
    size_t l;
    int val_type = lua_type(L, val);
    lua_pushvalue(L, val);

    buf_write(L, (void*)&val_type, MAR_CHR, buf);
    switch (val_type) {
    case LUA_TBOOLEAN: {
        int int_val = lua_toboolean(L, -1);
        buf_write(L, (void*)&int_val, MAR_CHR, buf);
        break;
    }
    case LUA_TSTRING: {
        const char *str_val = lua_tolstring(L, -1, &l);
        buf_write(L, (void*)&l, MAR_I32, buf);
        buf_write(L, str_val, l, buf);
        break;
    }
    case LUA_TNUMBER: {
        lua_Number num_val = lua_tonumber(L, -1);
        buf_write(L, (void*)&num_val, MAR_I64, buf);
        break;
    }
    case LUA_TLIGHTUSERDATA: {
        if(nowrap) 
           luaL_error(L, "light userdata not permitted");
        void * ptr_val = lua_touserdata(L, -1);
        long long v = (long long)ptr_val;
        buf_write(L, (char*)&v, MAR_I64, buf);
        break;
    }
    case LUA_TTABLE: {
        int tag, ref;
        lua_pushvalue(L, -1);
        lua_rawget(L, SEEN_IDX);
        if (!lua_isnil(L, -1)) {
            ref = lua_tointeger(L, -1);
            tag = MAR_TREF;
            buf_write(L, (void*)&tag, MAR_CHR, buf);
            buf_write(L, (void*)&ref, MAR_I32, buf);
            lua_pop(L, 1);
        }
        else {
            mar_Buffer rec_buf;
            lua_pop(L, 1); /* pop nil */
            if (luaL_getmetafield(L, -1, "__persist")) {
                tag = MAR_TUSR;

                lua_pushvalue(L, -2); /* self */
                lua_call(L, 1, 1);
                if (!lua_isfunction(L, -1)) {
                    luaL_error(L, "__persist must return a function");
                }

                lua_remove(L, -2); /* __persist */

                lua_newtable(L);
                lua_pushvalue(L, -2); /* callback */
                lua_rawseti(L, -2, 1);

                buf_init(L, &rec_buf);
                mar_encode_table(L, &rec_buf, idx, nowrap);

                buf_write(L, (void*)&tag, MAR_CHR, buf);
                buf_write(L, (void*)&rec_buf.head, MAR_I32, buf);
                buf_write(L, rec_buf.data, rec_buf.head, buf);
                buf_done(L, &rec_buf);
                lua_pop(L, 1);
            }
            else {
                tag = MAR_TVAL;

                lua_pushvalue(L, -1);
                lua_pushinteger(L, (*idx)++);
                lua_rawset(L, SEEN_IDX);

                lua_pushvalue(L, -1);
                buf_init(L, &rec_buf);
                mar_encode_table(L, &rec_buf, idx, nowrap);
                lua_pop(L, 1);

                buf_write(L, (void*)&tag, MAR_CHR, buf);
                buf_write(L, (void*)&rec_buf.head, MAR_I32, buf);
                buf_write(L, rec_buf.data,rec_buf.head, buf);
                buf_done(L, &rec_buf);
            }
        }
        break;
    }
    case LUA_TFUNCTION: {
        int tag, ref;
        lua_pushvalue(L, -1);
        lua_rawget(L, SEEN_IDX);
        if (!lua_isnil(L, -1)) {
            ref = lua_tointeger(L, -1);
            tag = MAR_TREF;
            buf_write(L, (void*)&tag, MAR_CHR, buf);
            buf_write(L, (void*)&ref, MAR_I32, buf);
            lua_pop(L, 1);
        }
        else {
            mar_Buffer rec_buf;
            int i;
            lua_Debug ar;
            lua_pop(L, 1); /* pop nil */

            lua_pushvalue(L, -1);
            lua_getinfo(L, ">nuS", &ar);
            //printf("Function name='%s' type='%s' nups=%d\n",ar.namewhat,ar.what,ar.nups);
            if (ar.what[0] != 'L') {
                luaL_error(L, "attempt to persist a C function '%s'", ar.name);
            }
            tag = MAR_TVAL;
            lua_pushvalue(L, -1);
            lua_pushinteger(L, (*idx)++);
            lua_rawset(L, SEEN_IDX);

            lua_pushvalue(L, -1);
            buf_init(L, &rec_buf);
            lua_dump(L, (lua_Writer)buf_write, &rec_buf);

            buf_write(L, (void*)&tag, MAR_CHR, buf);
            buf_write(L, (void*)&rec_buf.head, MAR_I32, buf);
            buf_write(L, rec_buf.data, rec_buf.head, buf);
            buf_done(L, &rec_buf);
            lua_pop(L, 1);

            lua_newtable(L);
            for (i=1; i <= ar.nups; i++) {            	
					 #if LUA_VERSION_NUM > 501
						const char * str=lua_getupvalue(L, -2, i);
					 	if(!strncmp(str,"_ENV",4)) {
		  					//printf("Stripping _ENV\n");
					 		lua_pop(L,1);
					 		lua_pushliteral(L,LEDA_ENV_MARKER);
					 	}
					#else
						lua_getupvalue(L, -2, i);
               #endif
               lua_rawseti(L, -2, i);
            }
            buf_init(L, &rec_buf);
            mar_encode_table(L, &rec_buf, idx, nowrap);

            buf_write(L, (void*)&rec_buf.head, MAR_I32, buf);
            buf_write(L, rec_buf.data, rec_buf.head, buf);
            buf_done(L, &rec_buf);
            lua_pop(L, 1);
        }

        break;
    }
    case LUA_TUSERDATA: {
        int tag, ref;
        lua_pushvalue(L, -1);
        lua_rawget(L, SEEN_IDX);
        if (!lua_isnil(L, -1)) {
            ref = lua_tointeger(L, -1);
            tag = MAR_TREF;
            buf_write(L, (void*)&tag, MAR_CHR, buf);
            buf_write(L, (void*)&ref, MAR_I32, buf);
            lua_pop(L, 1);
        }
        else {
            mar_Buffer rec_buf;
            lua_pop(L, 1); /* pop nil */
            if (!nowrap && luaL_getmetafield(L, -1, "__wrap")) {
                tag = MAR_TUSR;

                lua_pushvalue(L, -2);
                lua_pushinteger(L, (*idx)++);
                lua_rawset(L, SEEN_IDX);

                lua_pushvalue(L, -2);
                lua_call(L, 1, 1);
                if (!lua_isfunction(L, -1)) {
                    luaL_error(L, "__wrap must return a function");
                }
                lua_newtable(L);
                lua_pushvalue(L, -2);
                lua_rawseti(L, -2, 1);
                lua_remove(L, -2);

                buf_init(L, &rec_buf);
                mar_encode_table(L, &rec_buf, idx, nowrap);

                buf_write(L, (void*)&tag, MAR_CHR, buf);
                buf_write(L, (void*)&rec_buf.head, MAR_I32, buf);
		          buf_write(L, rec_buf.data, rec_buf.head, buf);
		          buf_done(L, &rec_buf);
            } else if (luaL_getmetafield(L, -1, "__persist")) {
                tag = MAR_TUSR;

                lua_pushvalue(L, -2);
                lua_pushinteger(L, (*idx)++);
                lua_rawset(L, SEEN_IDX);

                lua_pushvalue(L, -2);
                lua_call(L, 1, 1);
                if (!lua_isfunction(L, -1)) {
                    luaL_error(L, "__persist must return a function");
                }
                lua_newtable(L);
                lua_pushvalue(L, -2);
                lua_rawseti(L, -2, 1);
                lua_remove(L, -2);

                buf_init(L, &rec_buf);
                mar_encode_table(L, &rec_buf, idx, nowrap);

                buf_write(L, (void*)&tag, MAR_CHR, buf);
                buf_write(L, (void*)&rec_buf.head, MAR_I32, buf);
		          buf_write(L, rec_buf.data, rec_buf.head, buf);
		          buf_done(L, &rec_buf);
            }
            else {
                luaL_error(L, "attempt to encode userdata (no __wrap hook - or not permited - and no __persist hook)");
            }
            lua_pop(L, 1);
        }
        break;
    }
    case LUA_TNIL: break;
    default:
        luaL_error(L, "invalid value type (%s)", lua_typename(L, val_type));
    }
    lua_pop(L, 1);
}
Example #28
0
static void inter_copy_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ) {

    lua_CFunction cfunc= lua_tocfunction( L,i );
    unsigned n;

    ASSERT_L( L2_cache_i != 0 );

  STACK_GROW(L,2);

  STACK_CHECK(L)
    if (!cfunc) {   // Lua function
        luaL_Buffer b;
        const char *s;
        size_t sz;
        int tmp;
        const char *name= NULL;

#if 0
        // "To get information about a function you push it onto the 
        // stack and start the what string with the character '>'."
        //
        { lua_Debug ar;
        lua_pushvalue( L, i );
        lua_getinfo(L, ">n", &ar);      // fills 'name' and 'namewhat', pops function
        name= ar.namewhat;
        
        fprintf( stderr, "NAME: %s\n", name );  // just gives NULL
        }
#endif 
        // 'lua_dump()' needs the function at top of stack
        //
        if (i!=-1) lua_pushvalue( L, i );

        luaL_buffinit(L,&b);
        tmp= lua_dump(L, buf_writer, &b);
        ASSERT_L(tmp==0);
            //
            // "value returned is the error code returned by the last call 
            // to the writer" (and we only return 0)

        luaL_pushresult(&b);    // pushes dumped string on 'L'
        s= lua_tolstring(L,-1,&sz);
        ASSERT_L( s && sz );

        if (i!=-1) lua_remove( L, -2 );

        // Note: Line numbers seem to be taken precisely from the 
        //       original function. 'name' is not used since the chunk
        //       is precompiled (it seems...). 
        //
        // TBD: Can we get the function's original name through, as well?
        //
        if (luaL_loadbuffer(L2, s, sz, name) != 0) {
            // chunk is precompiled so only LUA_ERRMEM can happen
            // "Otherwise, it pushes an error message"
            //
            STACK_GROW( L,1 );
            luaL_error( L, "%s", lua_tostring(L2,-1) );
        }
        lua_pop(L,1);   // remove the dumped string
  STACK_MID(L,0)
    }
Example #29
0
bool Serializer::writeRoomData() {
  // Write the enable status for the spots of all nodes of all rooms
  if (!SDL_WriteBE16(_rw, Control::instance().numRooms()))
    return false;

  for (Room *room : Control::instance().rooms()) {
    if (!SDL_WriteBE16(_rw, room->numNodes()))
      return false;

    if (room->hasNodes()) {
      room->beginIteratingNodes();

      do {
        Node *node = room->iterator();

        if (!SDL_WriteBE16(_rw, node->numSpots()))
          return false;

        if (node->hasSpots()) {
          node->beginIteratingSpots();

          do {
            if (!SDL_WriteU8(_rw, node->currentSpot()->isEnabled()))
              return false;
          } while (node->iterateSpots());
        }
      } while (room->iterateNodes());
    }
  }

  Room *room = Control::instance().currentRoom();

  // Write node number
  uint16_t nodeIdx = 0;
  if (room->hasNodes()) {
    room->beginIteratingNodes();
    do {
      if (room->iterator() == room->currentNode())
        break;

      nodeIdx++;
    } while (room->iterateNodes());
  }

  if (!SDL_WriteBE16(_rw, nodeIdx))
    return false;

  // Write camera angles
  int hAngle = CameraManager::instance().angleHorizontal();
  const std::string hAngleStr = std::to_string(hAngle);
  if (!SDL_WriteU8(_rw, hAngleStr.length()))
    return false;
  if (!SDL_RWwrite(_rw, hAngleStr.c_str(), hAngleStr.length(), 1))
    return false;

  int vAngle = CameraManager::instance().angleVertical();
  const std::string vAngleStr = std::to_string(vAngle);
  if (!SDL_WriteU8(_rw, vAngleStr.length()))
    return false;
  if (!SDL_RWwrite(_rw, vAngleStr.c_str(), vAngleStr.length(), 1))
    return false;

  float fov = CameraManager::instance().fieldOfView();
  const std::string fovStr = std::to_string(fov);
  if (!SDL_WriteU8(_rw, fovStr.length()))
    return false;
  if (!SDL_RWwrite(_rw, fovStr.c_str(), fovStr.length(), 1))
    return false;

  // Write audio states
  if (!SDL_WriteBE16(_rw, room->arrayOfAudios().size()))
    return false;

  for (Audio *audio : room->arrayOfAudios()) {
    if (!SDL_WriteU8(_rw, audio->state()))
      return false;
  }

  // Write timers
  int64_t timersPtr = SDL_RWtell(_rw);
  if (timersPtr < 0)
    return false;
  if (!SDL_WriteBE16(_rw, 0)) // 2 placeholder bytes for the actual number of timers
    return false;

  uint16_t numTimers = 0;
  for (const auto &timer : TimerManager::instance().timers()) {
    if (timer.type != DGTimerNormal || !timer.isEnabled ||
        (!timer.isLoopable && timer.hasTriggered))
      continue;

    double elapsed = TimerManager::instance().timeElapsed(timer);
    if (timer.trigger - elapsed > 0) {
      const std::string triggerStr = std::to_string(timer.trigger);
      if (!SDL_WriteU8(_rw, timer.isLoopable))
        return false;
      if (!SDL_WriteU8(_rw, triggerStr.length()))
        return false;
      if (!SDL_RWwrite(_rw, triggerStr.c_str(), triggerStr.length(), 1))
        return false;

      const std::string elapsedStr = std::to_string(elapsed);
      if (!SDL_WriteU8(_rw, elapsedStr.length()))
        return false;
      if (!SDL_RWwrite(_rw, elapsedStr.c_str(), elapsedStr.length(), 1))
        return false;

      lua_rawgeti(_L, LUA_REGISTRYINDEX, timer.luaHandler); // Push timer function to top of stack

      int64_t funcSizePtr = SDL_RWtell(_rw);
      if (funcSizePtr < 0)
        return false;
      if (!SDL_WriteBE16(_rw, 0)) // 2 placeholder bytes for the actual function size
        return false;

      int64_t beforeFuncPtr = SDL_RWtell(_rw);
      if (beforeFuncPtr < 0)
        return false;
      int errCode = lua_dump(_L, writeFunction, _rw);
      if (errCode != 0)
        return false;
      int64_t afterFuncPtr = SDL_RWtell(_rw);
      if (afterFuncPtr < 0)
        return false;

      uint16_t numBytesWritten = afterFuncPtr - beforeFuncPtr;
      if (SDL_RWseek(_rw, funcSizePtr, RW_SEEK_SET) < 0)
        return false;
      if (!SDL_WriteBE16(_rw, numBytesWritten))
        return false;

      if (SDL_RWseek(_rw, 0, RW_SEEK_END) < 0) // Restore file pointer to end
        return false;

      numTimers++;
    }
  }

  if (SDL_RWseek(_rw, timersPtr, RW_SEEK_SET) < 0)
    return false;
  if (!SDL_WriteBE16(_rw, numTimers))
    return false;
  if (SDL_RWseek(_rw, 0, RW_SEEK_END) < 0) // Restore file pointer to end
    return false;

  // Write control mode
  if (!SDL_WriteU8(_rw, Config::instance().controlMode))
    return false;

  return true;
}
static inline int _cloneNoTable(lua_State *L, const int idx, 
	lua_State *L_, const int r_lv ) { 
	int ret_= 1; switch(lua_type(L, idx ) ) { 
		case LUA_TSTRING: { 
			size_t l; const char *s= lua_tolstring(L, idx, &l ); 
			lua_pushlstring(L_, s, l ); 
		} break; 
		case LUA_TNUMBER: 
		lua_pushnumber(L_, lua_tonumber(L, idx ) ); 
		break; 
		case LUA_TLIGHTUSERDATA: 
		lua_pushlightuserdata(L_, lua_touserdata(L, idx ) ); 
		break; 
		case LUA_TBOOLEAN: 
		lua_pushboolean(L_, lua_toboolean(L, idx ) ); 
		break; 
		case LUA_TUSERDATA: { // userdata 的 meta 暂时不能拷贝 
			const size_t l= lua_objlen(L, idx ); 
			memmove(lua_newuserdata(L_, l ), 
				lua_touserdata(L, idx ), l ); if(0) //屏蔽 meta 处理 
			if(lua_getmetatable(L, idx ) ) { 
				const int k= _cloneRecursion(L, lua_gettop(L ), L_, 
					((0<= r_lv )? r_lv: -1 ) ); lua_pop(L, 1 ); 
				if((0<= r_lv )&& lua_istable(L_, -1 )&& (0< k ) ) 
					printf("%*.s__{%3d}\n", (r_lv- 1 )* 2, "", k ); 
				lua_setmetatable(L_, -2 ); 
			} 
		} break; 
		case LUA_TFUNCTION: 
		if(lua_iscfunction(L, idx ) ) { 
			int j= 1; lua_CFunction f= lua_tocfunction(L, idx ); 
			for(j= 1; UPVALUE_MAX>= j; ++j ) { 
				//设置函数的 upvalue 
				if(!lua_getupvalue(L, idx, j ) ) break; 
				_cloneRecursion(L, lua_gettop(L ), L_, 
					((0<= r_lv )? (r_lv+ 1 ): -1 ) ); lua_pop(L, 1 ); 
			} lua_pushcclosure(L_, f, j- 1 ); 
		} else 
		{ int j= 1; DUMP_CB ud; memset(&ud, 0, sizeof(ud ) ); 
			lua_pushvalue(L, idx ); lua_dump(L, writer_CB, &ud ); 
			if(ud.p ) { //载入函数到新的栈 
				lua_load(L_, reader_CB, &ud, (char * )0 ); free(ud.p ); 
			} lua_pop(L, 1 ); 
			for(j= 1; UPVALUE_MAX>= j; ++j ) { 
				//设置函数的 upvalue 
				if(!lua_getupvalue(L, idx, j ) ) break; 
printf("upvalue %d\n", j ); 
				_cloneRecursion(L, lua_gettop(L ), L_, 
					((0<= r_lv )? (r_lv+ 1 ): -1 ) ); lua_pop(L, 1 ); 
				lua_setupvalue(L_, -2, j ); 
			} 
		} break; 
		case LUA_TNIL: 
		lua_pushnil(L_ ); 
		break; 
		case LUA_TNONE: 
		case LUA_TTHREAD: //?
		default: 
		ret_= 0; break; 
	} 
	return ret_; 
}