summaryrefslogtreecommitdiff
path: root/core/src
diff options
context:
space:
mode:
authorruki <[email protected]>2025-12-11 22:46:20 +0800
committerruki <[email protected]>2025-12-12 09:00:43 +0800
commit1c5e66f354ca526214845fa190f7d18a4960d89b (patch)
tree43b00bfac18661aff797d9778d07c8240c81110e /core/src
parentaf99153ccd7fbc82c7374eac23e6308e37fc061a (diff)
improve extractlib
Diffstat (limited to 'core/src')
-rw-r--r--core/src/xmake/binutils/ar/extractlib.c73
-rw-r--r--core/src/xmake/binutils/ar/prefix.h22
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