Skip to content

Commit

Permalink
extract program files
Browse files Browse the repository at this point in the history
  • Loading branch information
waruqi committed Aug 22, 2024
1 parent f279f50 commit 2f58a40
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 6 deletions.
161 changes: 156 additions & 5 deletions core/src/xmake/engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,17 @@
# include <image.h>
#endif

// for uid
#ifndef TB_CONFIG_OS_WINDOWS
# include <unistd.h>
# include <errno.h>
#endif

// for embed files
#ifdef XM_EMBED_ENABLE
# include "lz4/prefix.h"
#endif

/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
Expand Down Expand Up @@ -81,6 +92,11 @@ typedef struct __xm_engine_t
// the engine name
tb_char_t name[64];

#ifdef XM_EMBED_ENABLE
// the temporary directory
tb_char_t tmpdir[TB_PATH_MAXN];
#endif

}xm_engine_t;

/* //////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -744,16 +760,42 @@ static tb_size_t xm_engine_get_program_file(xm_engine_t* engine, tb_char_t* path
return ok;
}

#ifdef XM_EMBED_ENABLE
static tb_bool_t xm_engine_get_temporary_directory(tb_char_t* path, tb_size_t maxn, tb_char_t const* name, tb_char_t const* version_cstr)
{
tb_char_t data[TB_PATH_MAXN] = {0};
if (tb_directory_temporary(data, sizeof(data)))
{
// get euid
tb_int_t euid = 0;
#ifndef TB_CONFIG_OS_WINDOWS
euid = geteuid();
#endif

tb_snprintf(path, maxn, "%s/.%s%d/%s", data, name, euid, version_cstr);
return tb_true;
}
return tb_false;
}
#endif

static tb_bool_t xm_engine_get_program_directory(xm_engine_t* engine, tb_char_t* path, tb_size_t maxn, tb_char_t const* programfile)
{
// check
tb_assert_and_check_return_val(engine && path && maxn, tb_false);

tb_bool_t ok = tb_false;
tb_char_t data[TB_PATH_MAXN] = {0};
do
{
#ifdef XM_EMBED_ENABLE
// get it from the temporary directory
tb_strlcpy(path, engine->tmpdir, maxn);
ok = tb_true;
break;
#endif

// get it from the environment variable first
tb_char_t data[TB_PATH_MAXN] = {0};
if (tb_environment_first("XMAKE_PROGRAM_DIR", data, sizeof(data)) && tb_path_absolute(data, path, maxn))
{
ok = tb_true;
Expand Down Expand Up @@ -1097,6 +1139,109 @@ static tb_pointer_t xm_engine_lua_realloc(tb_pointer_t udata, tb_pointer_t data,
}
#endif

#ifdef XM_EMBED_ENABLE
static tb_bool_t xm_engine_extract_programfiles(xm_engine_t* engine, tb_char_t const* programdir)
{
tb_file_info_t info = {0};
if (tb_file_info(programdir, &info)) return tb_true;

tb_byte_t const* data = g_xmake_xmz_data;
tb_size_t size = sizeof(g_xmake_xmz_data);

// do decompress
tb_bool_t ok = tb_false;
LZ4F_errorCode_t code;
LZ4F_decompressionContext_t ctx = tb_null;
tb_buffer_t result;
do
{
tb_buffer_init(&result);

code = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION);
if (LZ4F_isError(code)) break;

tb_byte_t buffer[8192];
tb_bool_t failed = tb_false;
while (1)
{
size_t advance = (size_t)size;
size_t buffer_size = sizeof(buffer);
code = LZ4F_decompress(ctx, buffer, &buffer_size, data, &advance, tb_null);
if (LZ4F_isError(code))
{
failed = tb_true;
break;
}

if (buffer_size == 0) break;
data += advance;
size -= advance;

tb_buffer_memncat(&result, buffer, buffer_size);
}
tb_assert_and_check_break(!failed && tb_buffer_size(&result));

ok = tb_true;
} while (0);

// extract files to programdir
if (ok)
{
data = tb_buffer_data(&result);
size = tb_buffer_size(&result);
tb_byte_t const* p = data;
tb_byte_t const* e = data + size;
tb_size_t n = 0;
tb_char_t filepath[TB_PATH_MAXN];
tb_int_t pos = tb_snprintf(filepath, sizeof(filepath), "%s/", programdir);
while (p < e)
{
// get filepath
n = (tb_size_t)tb_bits_get_u16_be(p);
p += 2;
tb_assert_and_check_break(pos + n + 1 < sizeof(filepath));
tb_strncpy(filepath + pos, (tb_char_t const*)p, n);
filepath[pos + n] = '\0';
p += n;

// get filedata
n = (tb_size_t)tb_bits_get_u32_be(p);
p += 4;

// write file
tb_trace_d("extracting %s, %lu bytes ..", filepath, n);
tb_stream_ref_t stream = tb_stream_init_from_file(filepath, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC);
tb_assert_and_check_break(stream);

if (tb_stream_open(stream))
{
tb_stream_bwrit(stream, p, n);
tb_stream_exit(stream);
}

p += n;
}
ok = (p == e);
if (!ok)
{
tb_trace_e("extract program files failed");
}
}
else
{
tb_trace_e("decompress program files failed, %s", LZ4F_getErrorName(code));
}

if (ctx)
{
LZ4F_freeDecompressionContext(ctx);
ctx = tb_null;
}
tb_buffer_exit(&result);
return ok;
}
#endif

/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
Expand Down Expand Up @@ -1215,6 +1360,12 @@ xm_engine_ref_t xm_engine_init(tb_char_t const* name, xm_engine_lni_initalizer_c
lua_pushstring(engine->lua, version_cstr);
lua_setglobal(engine->lua, "_VERSION");

#ifdef XM_EMBED_ENABLE
// init the temporary directory
if (!xm_engine_get_temporary_directory(engine->tmpdir, sizeof(engine->tmpdir), name, version_cstr))
break;
#endif

// init short version string
tb_snprintf(version_cstr, sizeof(version_cstr), "%u.%u.%u", version->major, version->minor, version->alter);
lua_pushstring(engine->lua, version_cstr);
Expand Down Expand Up @@ -1306,6 +1457,10 @@ tb_int_t xm_engine_main(xm_engine_ref_t self, tb_int_t argc, tb_char_t** argv, t
// get the program directory
if (!xm_engine_get_program_directory(engine, path, sizeof(path), path)) return -1;

#ifdef XM_EMBED_ENABLE
if (!xm_engine_extract_programfiles(engine, path)) return -1;
#endif

// append the main script path
tb_strcat(path, "/core/_xmake_main.lua");

Expand Down Expand Up @@ -1338,10 +1493,6 @@ tb_int_t xm_engine_main(xm_engine_ref_t self, tb_int_t argc, tb_char_t** argv, t
return -1;
}

#ifdef XM_EMBED_ENABLE
tb_trace_i("g_xmake_xmz_data: %p", g_xmake_xmz_data);
#endif

// get the error code
return (tb_int_t)lua_tonumber(engine->lua, -1);
}
Expand Down
2 changes: 1 addition & 1 deletion xmake/modules/utils/archive/archive_xmz.lua
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ function _archive_files(archivefile, inputfiles, opt)
filepath = path.relative(filepath, curdir)
end
outputfile:write(bytes(2):u16be_set(1, #filepath))
outputfile:write(inputfile)
outputfile:write(filepath)
local data = io.readfile(inputfile, {encoding = "binary"})
vprint("archiving %s, %d bytes", inputfile, data and #data or 0)
outputfile:write(bytes(4):u32be_set(1, #data))
Expand Down

0 comments on commit 2f58a40

Please sign in to comment.