diff options
| author | ruki <[email protected]> | 2025-12-11 23:35:23 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2025-12-12 09:00:44 +0800 |
| commit | 4ccb8514f37fdf7108b41dbcd8ca77143841e1cd (patch) | |
| tree | ff1b1ae7433fa16acb2bfccffcf4bebc4e9b8b98 /core/src | |
| parent | 409b21826872503ef479848321003d7ca4c1aad8 (diff) | |
set plain as default
Diffstat (limited to 'core/src')
| -rw-r--r-- | core/src/xmake/binutils/extractlib.c | 17 | ||||
| -rw-r--r-- | core/src/xmake/binutils/mslib/extractlib.c | 88 |
2 files changed, 97 insertions, 8 deletions
diff --git a/core/src/xmake/binutils/extractlib.c b/core/src/xmake/binutils/extractlib.c index d5e8b3759..ec588f213 100644 --- a/core/src/xmake/binutils/extractlib.c +++ b/core/src/xmake/binutils/extractlib.c @@ -36,7 +36,7 @@ * forward declarations */ extern tb_bool_t xm_binutils_ar_extract(tb_stream_ref_t istream, tb_char_t const *outputdir); -extern tb_bool_t xm_binutils_mslib_extract(tb_stream_ref_t istream, tb_char_t const *outputdir); +extern tb_bool_t xm_binutils_mslib_extract(tb_stream_ref_t istream, tb_char_t const *outputdir, tb_bool_t plain); /* ////////////////////////////////////////////////////////////////////////////////////// * implementation @@ -46,6 +46,11 @@ extern tb_bool_t xm_binutils_mslib_extract(tb_stream_ref_t istream, tb_char_t co * Supports AR format (.a) and MSVC lib format (.lib) * * @param lua the lua state + * + * libraryfile = lua[1] + * outputdir = lua[2] + * plain = lua[3] (optional, default: true) + * * @return 1 on success, 2 on failure (with error message) */ tb_int_t xm_binutils_extractlib(lua_State *lua) { @@ -59,6 +64,12 @@ tb_int_t xm_binutils_extractlib(lua_State *lua) { tb_char_t const *outputdir = luaL_checkstring(lua, 2); tb_check_return_val(outputdir, 0); + // get the plain mode (optional) + tb_bool_t plain = tb_true; + if (lua_gettop(lua) >= 3 && !lua_isnil(lua, 3)) { + plain = lua_toboolean(lua, 3); + } + // open library file tb_stream_ref_t istream = tb_stream_init_from_file(libraryfile, TB_FILE_MODE_RO); if (!istream) { @@ -88,7 +99,7 @@ tb_int_t xm_binutils_extractlib(lua_State *lua) { // if the file extension is .lib, we use the msvc lib extractor to support long paths and subdirectories tb_size_t n = tb_strlen(libraryfile); if (n > 4 && !tb_strnicmp(libraryfile + n - 4, ".lib", 4)) { - if (!xm_binutils_mslib_extract(istream, outputdir)) { + if (!xm_binutils_mslib_extract(istream, outputdir, plain)) { error_msg = "extract MSVC lib failed"; break; } @@ -105,7 +116,7 @@ tb_int_t xm_binutils_extractlib(lua_State *lua) { // MSVC lib files can be: // 1. Import libraries (different format) // 2. Static libraries (COFF archive format, similar to AR but different) - if (!xm_binutils_mslib_extract(istream, outputdir)) { + if (!xm_binutils_mslib_extract(istream, outputdir, plain)) { error_msg = "extract MSVC lib failed"; break; } diff --git a/core/src/xmake/binutils/mslib/extractlib.c b/core/src/xmake/binutils/mslib/extractlib.c index f56d3eb3e..5dec97f3e 100644 --- a/core/src/xmake/binutils/mslib/extractlib.c +++ b/core/src/xmake/binutils/mslib/extractlib.c @@ -34,13 +34,49 @@ * implementation */ +/* generate unique name for output file + * + * @param base_name the base name + * @param id the unique id + * @param output output buffer + * @param output_size output buffer size + * @param output_len output: actual output length + * @return tb_true on success, tb_false on failure + */ +static tb_bool_t xm_binutils_mslib_generate_unique_name(tb_char_t const *base_name, tb_uint32_t id, tb_char_t *output, tb_size_t output_size, tb_size_t* output_len) { + tb_assert_and_check_return_val(base_name && output && output_size > 0 && output_len, tb_false); + + // find the last dot for extension + tb_char_t const *ext = tb_strrchr(base_name, '.'); + tb_long_t n = -1; + if (ext) { + tb_size_t base_len = (tb_size_t)(ext - base_name); + tb_size_t ext_len = tb_strlen(ext); + if (base_len + ext_len + 16 < output_size) { + n = tb_snprintf(output, output_size, "%.*s_%u%s", (tb_int_t)base_len, base_name, id, ext); + } + } else { + // no extension + if (tb_strlen(base_name) + 16 < output_size) { + n = tb_snprintf(output, output_size, "%s_%u", base_name, id); + } + } + + if (n >= 0) { + *output_len = (tb_size_t)n; + return tb_true; + } + return tb_false; +} + /* extract MSVC lib archive to directory * * @param istream the input stream * @param outputdir the output directory + * @param plain extract all object files to the same directory * @return tb_true on success, tb_false on failure */ -tb_bool_t xm_binutils_mslib_extract(tb_stream_ref_t istream, tb_char_t const *outputdir) { +tb_bool_t xm_binutils_mslib_extract(tb_stream_ref_t istream, tb_char_t const *outputdir, tb_bool_t plain) { tb_assert_and_check_return_val(istream && outputdir, tb_false); // check magic (!<arch>\n) @@ -158,11 +194,53 @@ tb_bool_t xm_binutils_mslib_extract(tb_stream_ref_t istream, tb_char_t const *ou // check output path length tb_char_t output_path[1024]; - if (tb_strlen(outputdir) + 1 + name_len >= sizeof(output_path)) { - ok = tb_false; - break; + if (plain) { + // get filename only + tb_char_t const* name = tb_strrchr(member_name, '/'); + if (name) name++; + else name = member_name; + + // check conflicts + tb_char_t output_name[512]; + tb_size_t output_name_len = tb_strlen(name); + tb_size_t outputdir_len = tb_strlen(outputdir); + + if (outputdir_len + 1 + output_name_len >= sizeof(output_path)) { + ok = tb_false; + break; + } + tb_snprintf(output_path, sizeof(output_path), "%s/%s", outputdir, name); + + if (tb_file_info(output_path, tb_null)) { + // name conflict, try different IDs + tb_uint32_t conflict_id = 1; + while (conflict_id < 10000) { + if (!xm_binutils_mslib_generate_unique_name(name, conflict_id, output_name, sizeof(output_name), &output_name_len)) { + ok = tb_false; + break; + } + if (outputdir_len + 1 + output_name_len >= sizeof(output_path)) { + ok = tb_false; + break; + } + tb_snprintf(output_path, sizeof(output_path), "%s/%s", outputdir, output_name); + if (!tb_file_info(output_path, tb_null)) { + break; + } + conflict_id++; + } + if (!ok || conflict_id >= 10000) { + ok = tb_false; + break; + } + } + } else { + if (tb_strlen(outputdir) + 1 + name_len >= sizeof(output_path)) { + ok = tb_false; + break; + } + tb_snprintf(output_path, sizeof(output_path), "%s/%s", outputdir, member_name); } - tb_snprintf(output_path, sizeof(output_path), "%s/%s", outputdir, member_name); // ensure directory exists tb_char_t const* p = tb_strrchr(output_path, '/'); |
