diff options
| author | ruki <[email protected]> | 2025-12-11 22:46:20 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2025-12-12 09:00:43 +0800 |
| commit | 1c5e66f354ca526214845fa190f7d18a4960d89b (patch) | |
| tree | 43b00bfac18661aff797d9778d07c8240c81110e /core/src | |
| parent | af99153ccd7fbc82c7374eac23e6308e37fc061a (diff) | |
improve extractlib
Diffstat (limited to 'core/src')
| -rw-r--r-- | core/src/xmake/binutils/ar/extractlib.c | 73 | ||||
| -rw-r--r-- | core/src/xmake/binutils/ar/prefix.h | 22 |
2 files changed, 53 insertions, 42 deletions
diff --git a/core/src/xmake/binutils/ar/extractlib.c b/core/src/xmake/binutils/ar/extractlib.c index 53dd04cc5..7c5484e1d 100644 --- a/core/src/xmake/binutils/ar/extractlib.c +++ b/core/src/xmake/binutils/ar/extractlib.c @@ -47,7 +47,7 @@ static tb_bool_t xm_binutils_ar_get_member_name(tb_stream_ref_t istream, xm_ar_header_t const *header, tb_char_t *name, tb_size_t name_size, tb_size_t *name_len, tb_hize_t *bytes_read) { tb_assert_and_check_return_val(istream && header && name && name_size > 0 && name_len && bytes_read, tb_false); *bytes_read = 0; - + // check for extended name format (#N/L or #1/N) // In BSD AR format: // - #1/N means name is directly after header, N is total length (including name) @@ -63,31 +63,31 @@ static tb_bool_t xm_binutils_ar_get_member_name(tb_stream_ref_t istream, xm_ar_h break; } } - + if (slash_pos > 0 && slash_pos < 16) { // parse the number before '/' (could be name length or offset) tb_int64_t first_num = xm_binutils_ar_parse_decimal(header->name + 1, slash_pos - 1); // parse the number after '/' (total length) tb_int64_t total_length = xm_binutils_ar_parse_decimal(header->name + slash_pos + 1, 16 - slash_pos - 1); - + if (first_num <= 0 || total_length <= 0 || total_length >= (tb_int64_t)name_size) { return tb_false; } - + // In BSD AR format, extended name is directly after header // The name data starts immediately after the header, no newline // Read exactly total_length bytes for the name section tb_byte_t c; tb_size_t name_bytes = 0; tb_hize_t bytes_read_so_far = 0; - + // Read name characters until we hit null terminator or reach total_length while (bytes_read_so_far < (tb_hize_t)total_length && name_bytes < name_size - 1) { if (!tb_stream_bread(istream, &c, 1)) { return tb_false; } bytes_read_so_far++; - + if (c == '\0') { // Stop reading name at null terminator, but continue reading to reach total_length break; @@ -97,7 +97,7 @@ static tb_bool_t xm_binutils_ar_get_member_name(tb_stream_ref_t istream, xm_ar_h } name[name_bytes] = '\0'; *name_len = name_bytes; - + // Skip remaining bytes to reach total_length (there may be padding or null terminators) if (bytes_read_so_far < (tb_hize_t)total_length) { tb_hize_t remaining_to_read = (tb_hize_t)total_length - bytes_read_so_far; @@ -105,13 +105,13 @@ static tb_bool_t xm_binutils_ar_get_member_name(tb_stream_ref_t istream, xm_ar_h return tb_false; } } - + // Total bytes read = name + padding = total_length *bytes_read = (tb_hize_t)total_length; return tb_true; } } - + // regular name (null-terminated or space-padded) tb_size_t i = 0; for (i = 0; i < 16 && i < name_size - 1; i++) { @@ -132,7 +132,7 @@ static tb_bool_t xm_binutils_ar_get_member_name(tb_stream_ref_t istream, xm_ar_h * @return tb_true if it's a symbol table, tb_false otherwise */ static __tb_inline__ tb_bool_t xm_binutils_ar_is_symbol_table(tb_char_t const *name) { - if (!name) return tb_false; + tb_assert_and_check_return_val(name, tb_false); return (tb_strcmp(name, "__.SYMDEF") == 0 || tb_strcmp(name, "__.SYMDEF SORTED") == 0 || tb_strcmp(name, "/") == 0 || tb_strcmp(name, "//") == 0 || tb_strncmp(name, "__.SYMDEF", 9) == 0); @@ -144,14 +144,14 @@ static __tb_inline__ tb_bool_t xm_binutils_ar_is_symbol_table(tb_char_t const *n * @return tb_true if it's likely an object file, tb_false otherwise */ static __tb_inline__ tb_bool_t xm_binutils_ar_is_object_file(tb_char_t const *name) { - if (!name) return tb_false; + tb_assert_and_check_return_val(name, tb_false); tb_size_t len = tb_strlen(name); if (len == 0) return tb_false; - + // check common object file extensions if (len >= 2 && name[len - 2] == '.' && name[len - 1] == 'o') return tb_true; if (len >= 4 && tb_strcmp(name + len - 4, ".obj") == 0) return tb_true; - + // check if it's a COFF/ELF/Mach-O file by detecting format // For now, we'll extract all non-symbol-table members return tb_true; @@ -167,7 +167,7 @@ static __tb_inline__ tb_bool_t xm_binutils_ar_is_object_file(tb_char_t const *na */ static tb_bool_t xm_binutils_ar_generate_unique_name(tb_char_t const *base_name, tb_uint32_t id, tb_char_t *output, tb_size_t output_size) { tb_assert_and_check_return_val(base_name && output && output_size > 0, tb_false); - + // find the last dot for extension tb_char_t const *ext = tb_strrchr(base_name, '.'); if (ext) { @@ -195,21 +195,12 @@ static tb_bool_t xm_binutils_ar_generate_unique_name(tb_char_t const *base_name, */ tb_bool_t xm_binutils_ar_extract(tb_stream_ref_t istream, tb_char_t const *outputdir) { tb_assert_and_check_return_val(istream && outputdir, tb_false); - + // check AR magic (!<arch>\n) - tb_uint8_t magic[8]; - if (!tb_stream_seek(istream, 0)) { - return tb_false; - } - if (!tb_stream_bread(istream, magic, 8)) { - return tb_false; - } - if (magic[0] != '!' || magic[1] != '<' || magic[2] != 'a' || magic[3] != 'r' || - magic[4] != 'c' || magic[5] != 'h' || (magic[6] != '>' && magic[6] != '\n') || - (magic[7] != '\n' && magic[7] != '\r')) { + if (!xm_binutils_ar_check_magic(istream)) { return tb_false; } - + // ensure output directory exists // check if directory already exists if (!tb_file_info(outputdir, tb_null)) { @@ -218,10 +209,10 @@ tb_bool_t xm_binutils_ar_extract(tb_stream_ref_t istream, tb_char_t const *outpu return tb_false; } } - + tb_bool_t ok = tb_true; tb_byte_t* buffer = tb_null; - + // iterate through AR members while (ok) { // read AR header @@ -231,19 +222,19 @@ tb_bool_t xm_binutils_ar_extract(tb_stream_ref_t istream, tb_char_t const *outpu // end of file break; } - + // parse member size tb_int64_t member_size = xm_binutils_ar_parse_decimal(header.size, 10); if (member_size < 0) { ok = tb_false; break; } - + // get member name tb_char_t member_name[256] = {0}; tb_size_t name_len = 0; tb_hize_t name_bytes_read = 0; - + // get member name (handles both regular and extended name formats) tb_bool_t skip = tb_false; if (!xm_binutils_ar_get_member_name(istream, &header, member_name, sizeof(member_name), &name_len, &name_bytes_read)) { @@ -266,12 +257,12 @@ tb_bool_t xm_binutils_ar_extract(tb_stream_ref_t istream, tb_char_t const *outpu } continue; } - + // handle name conflicts by checking if file exists and renaming with ID tb_char_t output_name[512] = {0}; tb_char_t output_path_check[1024] = {0}; tb_snprintf(output_path_check, sizeof(output_path_check), "%s/%s", outputdir, member_name); - + // check if file already exists tb_uint32_t conflict_id = 1; if (tb_file_info(output_path_check, tb_null)) { @@ -296,24 +287,24 @@ tb_bool_t xm_binutils_ar_extract(tb_stream_ref_t istream, tb_char_t const *outpu // first occurrence, use original name tb_strlcpy(output_name, member_name, sizeof(output_name)); } - + // build output path tb_char_t output_path[1024] = {0}; tb_snprintf(output_path, sizeof(output_path), "%s/%s", outputdir, output_name); - + // create output file tb_stream_ref_t ostream = tb_stream_init_from_file(output_path, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC); if (!ostream) { ok = tb_false; break; } - + if (!tb_stream_open(ostream)) { tb_stream_exit(ostream); ok = tb_false; break; } - + // copy member data to output file // member_size includes the name if extended format was used, so subtract name_bytes_read if (!buffer) buffer = tb_malloc_bytes(TB_STREAM_BLOCK_MAXN); @@ -336,14 +327,14 @@ tb_bool_t xm_binutils_ar_extract(tb_stream_ref_t istream, tb_char_t const *outpu } remaining -= to_read; } - + tb_stream_clos(ostream); tb_stream_exit(ostream); - + if (!ok) { break; } - + // align to 2-byte boundary (AR format requirement) if (member_size % 2) { if (!tb_stream_skip(istream, 1)) { @@ -352,7 +343,7 @@ tb_bool_t xm_binutils_ar_extract(tb_stream_ref_t istream, tb_char_t const *outpu } } } - + if (buffer) tb_free(buffer); return ok; } diff --git a/core/src/xmake/binutils/ar/prefix.h b/core/src/xmake/binutils/ar/prefix.h index 406838d6f..392e0c37e 100644 --- a/core/src/xmake/binutils/ar/prefix.h +++ b/core/src/xmake/binutils/ar/prefix.h @@ -78,5 +78,25 @@ static __tb_inline__ tb_int64_t xm_binutils_ar_parse_decimal(tb_char_t const *st return result; } -#endif +/* check AR magic (!<arch>\n) + * + * @param istream the input stream + * @return tb_true on success, tb_false on failure + */ +static __tb_inline__ tb_bool_t xm_binutils_ar_check_magic(tb_stream_ref_t istream) { + tb_uint8_t magic[8]; + if (!tb_stream_seek(istream, 0)) { + return tb_false; + } + if (!tb_stream_bread(istream, magic, 8)) { + return tb_false; + } + if (magic[0] != '!' || magic[1] != '<' || magic[2] != 'a' || magic[3] != 'r' || + magic[4] != 'c' || magic[5] != 'h' || (magic[6] != '>' && magic[6] != '\n') || + (magic[7] != '\n' && magic[7] != '\r')) { + return tb_false; + } + return tb_true; +} +#endif |
