Skip to content

Commit 40d790c

Browse files
authored
Merge pull request #7102 from xmake-io/bin2c
improve bin2c
2 parents cd1323f + e17c4b0 commit 40d790c

File tree

1 file changed

+104
-39
lines changed

1 file changed

+104
-39
lines changed

core/src/xmake/utils/bin2c.c

Lines changed: 104 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -30,63 +30,126 @@
3030
*/
3131
#include "prefix.h"
3232

33+
/* //////////////////////////////////////////////////////////////////////////////////////
34+
* macros
35+
*/
36+
37+
#define XM_BIN2C_DATA_SIZE (8 * 1024)
38+
#define XM_BIN2C_LINE_SIZE (4 * 1024)
39+
#define XM_BIN2C_LINEWIDTH_MAX ((XM_BIN2C_LINE_SIZE - 2) / 6)
40+
3341
/* //////////////////////////////////////////////////////////////////////////////////////
3442
* private implementation
3543
*/
36-
static __tb_inline__ tb_size_t xm_utils_bin2c_hex2str(tb_char_t str[5], tb_byte_t value) {
37-
static tb_char_t const *digits_table = "0123456789ABCDEF";
38-
str[0] = ' ';
39-
str[1] = '0';
40-
str[2] = 'x';
41-
str[3] = digits_table[(value >> 4) & 15];
42-
str[4] = digits_table[value & 15];
43-
return 5;
44+
45+
// optimized hex conversion table
46+
static tb_char_t const *xm_utils_bin2c_digits = "0123456789ABCDEF";
47+
48+
// inline hex conversion for better performance
49+
static __tb_inline__ tb_void_t xm_utils_bin2c_write_hex(tb_char_t *str, tb_byte_t value) {
50+
str[0] = ' ';
51+
str[1] = '0';
52+
str[2] = 'x';
53+
str[3] = xm_utils_bin2c_digits[(value >> 4) & 15];
54+
str[4] = xm_utils_bin2c_digits[value & 15];
4455
}
4556

4657
static tb_bool_t xm_utils_bin2c_dump(tb_stream_ref_t istream,
4758
tb_stream_ref_t ostream,
4859
tb_int_t linewidth,
4960
tb_bool_t nozeroend) {
61+
5062
tb_bool_t first = tb_true;
51-
tb_hong_t i = 0;
52-
tb_hong_t left = 0;
53-
tb_char_t line[4096];
54-
tb_byte_t data[512];
63+
tb_bool_t zero_pending = tb_false;
64+
tb_byte_t data[XM_BIN2C_DATA_SIZE];
65+
tb_char_t line[XM_BIN2C_LINE_SIZE];
5566
tb_size_t linesize = 0;
56-
tb_size_t need = 0;
57-
tb_assert_and_check_return_val(linewidth < sizeof(data), tb_false);
58-
while (!tb_stream_beof(istream)) {
59-
linesize = 0;
60-
left = tb_stream_left(istream);
61-
need = (tb_size_t)tb_min(left, linewidth);
62-
if (need) {
63-
if (!tb_stream_bread(istream, data, need))
64-
break;
65-
66-
if (!nozeroend && tb_stream_beof(istream)) {
67-
tb_assert_and_check_break(need + 1 < sizeof(data));
68-
data[need++] = '\0';
67+
tb_size_t bytes_in_line = 0;
68+
tb_size_t data_pos = 0;
69+
tb_size_t data_size = 0;
70+
tb_assert_and_check_return_val(linewidth > 0 && linewidth <= XM_BIN2C_LINEWIDTH_MAX, tb_false);
71+
72+
while (!tb_stream_beof(istream) || data_pos < data_size || zero_pending) {
73+
// read a large chunk of data if buffer is empty
74+
if (data_pos >= data_size) {
75+
// handle pending zero terminator
76+
if (zero_pending) {
77+
data[0] = '\0';
78+
data_size = 1;
79+
data_pos = 0;
80+
zero_pending = tb_false;
81+
} else {
82+
tb_hong_t left = tb_stream_left(istream);
83+
tb_size_t to_read = (tb_size_t)tb_min(left, (tb_hong_t)XM_BIN2C_DATA_SIZE);
84+
if (!to_read) {
85+
break;
86+
}
87+
88+
if (!tb_stream_bread(istream, data, to_read)) {
89+
break;
90+
}
91+
data_size = to_read;
92+
data_pos = 0;
93+
94+
// check if we need to add zero terminator at the end
95+
if (!nozeroend && tb_stream_beof(istream)) {
96+
if (data_size < XM_BIN2C_DATA_SIZE) {
97+
// can add directly to current buffer
98+
data[data_size++] = '\0';
99+
} else {
100+
// buffer is full, need to add zero in next iteration
101+
zero_pending = tb_true;
102+
}
103+
}
104+
}
105+
}
106+
107+
// process bytes from buffer
108+
while (data_pos < data_size) {
109+
// check if we need a new line
110+
if (bytes_in_line >= (tb_size_t)linewidth) {
111+
// write line (tb_stream_bwrit_line will add newline automatically)
112+
if (tb_stream_bwrit_line(ostream, line, linesize) < 0) {
113+
return tb_false;
114+
}
115+
116+
linesize = 0;
117+
bytes_in_line = 0;
118+
first = tb_false;
69119
}
70120

71-
tb_assert_and_check_break(linesize + 6 * need < sizeof(line));
121+
// ensure we have enough space in line buffer (6 chars per byte: ", 0xXX")
122+
if (linesize + 6 > sizeof(line)) {
123+
// flush partial line if buffer is full
124+
if (linesize > 0) {
125+
if (!tb_stream_bwrit(ostream, (tb_byte_t *)line, linesize)) {
126+
return tb_false;
127+
}
128+
linesize = 0;
129+
}
130+
}
72131

73-
i = 0;
74-
if (first) {
75-
first = tb_false;
132+
// add separator
133+
if (bytes_in_line == 0 && first) {
76134
line[linesize++] = ' ';
135+
first = tb_false;
77136
} else {
78137
line[linesize++] = ',';
79138
}
80-
linesize += xm_utils_bin2c_hex2str(line + linesize, data[i]);
81139

82-
for (i = 1; i < need; i++) {
83-
line[linesize++] = ',';
84-
linesize += xm_utils_bin2c_hex2str(line + linesize, data[i]);
85-
}
86-
tb_assert_and_check_break(i == need && linesize && linesize < sizeof(line));
140+
// write hex value (inline for performance)
141+
xm_utils_bin2c_write_hex(line + linesize, data[data_pos]);
142+
linesize += 5;
143+
bytes_in_line++;
144+
data_pos++;
145+
}
146+
}
87147

88-
if (tb_stream_bwrit_line(ostream, line, linesize) < 0)
89-
break;
148+
// flush remaining line
149+
if (linesize > 0) {
150+
// write line (tb_stream_bwrit_line will add newline automatically)
151+
if (tb_stream_bwrit_line(ostream, line, linesize) < 0) {
152+
return tb_false;
90153
}
91154
}
92155

@@ -147,12 +210,14 @@ tb_int_t xm_utils_bin2c(lua_State *lua) {
147210

148211
} while (0);
149212

150-
if (istream)
213+
if (istream) {
151214
tb_stream_clos(istream);
215+
}
152216
istream = tb_null;
153217

154-
if (ostream)
218+
if (ostream) {
155219
tb_stream_clos(ostream);
220+
}
156221
ostream = tb_null;
157222

158223
return ok ? 1 : 2;

0 commit comments

Comments
 (0)