Skip to content

Commit 57c175d

Browse files
authored
refactor(euicc): simplify bin2hex and hex2bin functions (estkme-group#323)
1 parent 50cd40b commit 57c175d

3 files changed

Lines changed: 97 additions & 115 deletions

File tree

euicc/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
option(LPAC_DYNAMIC_LIBEUICC "Build and install libeuicc as a dynamic library" OFF)
2+
option(LIBEUICC_REDUCED_STDLIB_CALL "Reduce standard library calling" OFF)
3+
24
if(LPAC_DYNAMIC_LIBEUICC)
35
add_library(euicc SHARED)
46
else()
@@ -79,3 +81,7 @@ if(LPAC_DYNAMIC_LIBEUICC)
7981
install(TARGETS euicc LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
8082
FILE_SET public_headers DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
8183
endif()
84+
85+
if (LIBEUICC_REDUCED_STDLIB_CALL)
86+
target_compile_definitions(euicc PRIVATE LIBEUICC_REDUCED_STDLIB_CALL)
87+
endif ()

euicc/hexutil.c

Lines changed: 79 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,142 +1,112 @@
11
#include "hexutil.h"
22

3-
#include <inttypes.h>
43
#include <stdlib.h>
54
#include <string.h>
65

7-
int euicc_hexutil_bin2hex(char *output, uint32_t output_len, const uint8_t *bin, uint32_t bin_len) {
8-
const char hexDigits[] = "0123456789abcdef";
9-
10-
if (!bin || !output) {
11-
return -1;
6+
#ifndef LIBEUICC_REDUCED_STDLIB_CALL
7+
# include <ctype.h>
8+
# include <stddef.h>
9+
#endif
10+
11+
#define SWAP(a, b) \
12+
do { \
13+
typeof(a) temp = (a); \
14+
(a) = (b); \
15+
(b) = temp; \
16+
} while (0)
17+
18+
static inline void gsmbcd_swap_chars(char *restrict input, const uint32_t input_len) {
19+
for (uint32_t i = 0; i < input_len; i += 2) {
20+
SWAP(input[i], input[i + 1]);
1221
}
22+
}
1323

14-
if (output_len < 2 * bin_len + 1) {
24+
int euicc_hexutil_bin2hex(char *restrict output, const uint32_t output_len, const uint8_t *bin,
25+
const uint32_t bin_len) {
26+
if (output == NULL || bin == NULL || output_len < ((2 * bin_len) + 1)) {
1527
return -1;
1628
}
17-
18-
for (uint32_t i = 0; i < bin_len; ++i) {
19-
char byte = bin[i];
20-
output[2 * i] = hexDigits[(byte >> 4) & 0x0F];
21-
output[2 * i + 1] = hexDigits[byte & 0x0F];
29+
static const char digits[] = "0123456789abcdef";
30+
uint32_t n = 0;
31+
for (uint32_t i = 0; i < bin_len; i++) {
32+
output[n++] = digits[bin[i] >> 4];
33+
output[n++] = digits[bin[i] & 0xf];
2234
}
23-
output[2 * bin_len] = '\0';
24-
25-
return 0;
35+
output[n] = '\0';
36+
return (int)n;
2637
}
2738

28-
int euicc_hexutil_hex2bin(uint8_t *output, uint32_t output_len, const char *str) {
29-
return euicc_hexutil_hex2bin_r(output, output_len, str, strlen(str));
39+
inline int euicc_hexutil_hex2bin(uint8_t *restrict output, const uint32_t output_len, const char *restrict input) {
40+
return euicc_hexutil_hex2bin_r(output, output_len, input, strlen(input));
3041
}
3142

32-
int euicc_hexutil_hex2bin_r(uint8_t *output, uint32_t output_len, const char *str, uint32_t str_len) {
33-
uint32_t length;
34-
35-
if (!str || !output || str_len % 2 != 0) {
43+
int euicc_hexutil_hex2bin_r(uint8_t *restrict output, const uint32_t output_len, const char *restrict input,
44+
const uint32_t input_len) {
45+
if (output == NULL || input == NULL || (input_len % 2) != 0 || output_len < (input_len / 2)) {
3646
return -1;
3747
}
38-
39-
length = str_len / 2;
40-
if (length > output_len) {
41-
return -1;
42-
}
43-
44-
for (uint32_t i = 0; i < length; ++i) {
45-
char high = str[2 * i];
46-
char low = str[2 * i + 1];
47-
48-
if (high >= '0' && high <= '9') {
49-
high -= '0';
50-
} else if (high >= 'a' && high <= 'f') {
51-
high = high - 'a' + 10;
52-
} else if (high >= 'A' && high <= 'F') {
53-
high = high - 'A' + 10;
54-
} else {
55-
return -1;
48+
uint32_t bytes = 0;
49+
#ifdef LIBEUICC_REDUCED_STDLIB_CALL
50+
uint8_t c, msb = 0;
51+
for (uint32_t i = 0; i < input_len; i++) {
52+
c = input[i] | ' ';
53+
if ((c < '0' || c > '9') && (c < 'a' || c > 'f')) {
54+
return -1; // invalid character
5655
}
57-
58-
if (low >= '0' && low <= '9') {
59-
low -= '0';
60-
} else if (low >= 'a' && low <= 'f') {
61-
low = low - 'a' + 10;
62-
} else if (low >= 'A' && low <= 'F') {
63-
low = low - 'A' + 10;
56+
c -= c > '9' ? 'a' - 10 : '0';
57+
if (i % 2 == 0) {
58+
msb = c;
6459
} else {
65-
return -1;
60+
output[bytes++] = msb << 4 | c;
6661
}
67-
68-
output[i] = (high << 4) + low;
6962
}
70-
71-
return length;
63+
#else
64+
char hex[3] = "\0\0";
65+
for (uint32_t i = 0; i < input_len; i += 2) {
66+
hex[0] = input[i + 0];
67+
hex[1] = input[i + 1];
68+
if (!(isxdigit(hex[0]) && isxdigit(hex[1]))) {
69+
return -1; // invalid character
70+
}
71+
output[bytes++] = (uint8_t)strtol(hex, NULL, 16);
72+
}
73+
#endif
74+
return (int)bytes;
7275
}
7376

74-
int euicc_hexutil_gsmbcd2bin(uint8_t *output, uint32_t output_len, const char *str, uint32_t padding_to) {
75-
uint32_t str_length;
76-
uint32_t idx = 0;
77-
78-
str_length = strlen(str);
79-
80-
if (output_len < (str_length + 1) / 2) {
77+
int euicc_hexutil_gsmbcd2bin(uint8_t *restrict output, const uint32_t output_len, const char *restrict input,
78+
const uint32_t padding_to) {
79+
if (output == NULL || input == NULL || output_len < padding_to) {
8180
return -1;
8281
}
83-
84-
if (output_len < padding_to) {
82+
const uint32_t n = strlen(input);
83+
char *bin = calloc(n + (n % 2), sizeof(char)); // +1 if odd
84+
if (bin == NULL) {
8585
return -1;
8686
}
87-
88-
for (uint32_t i = 0; i < str_length; i += 2) {
89-
char high_nibble = (i + 1 < str_length) ? str[i + 1] : 'F';
90-
char low_nibble = str[i];
91-
92-
uint8_t high_nibble_val = 0x0;
93-
uint8_t low_nibble_val = 0x0;
94-
95-
if (low_nibble >= '0' && low_nibble <= '9') {
96-
low_nibble_val = low_nibble - '0';
97-
} else if (low_nibble == 'F' || low_nibble == 'f') {
98-
low_nibble_val = 0x0F;
99-
} else {
100-
return -1;
101-
}
102-
103-
if (high_nibble >= '0' && high_nibble <= '9') {
104-
high_nibble_val = high_nibble - '0';
105-
} else if (high_nibble == 'F' || high_nibble == 'f') {
106-
high_nibble_val = 0xF;
107-
} else {
108-
return -1;
109-
}
110-
111-
output[idx] = (high_nibble_val << 4) | low_nibble_val;
112-
idx++;
113-
}
114-
115-
for (; idx < padding_to; idx++) {
116-
output[idx] = 0xFF;
87+
memcpy(bin, input, n);
88+
memset(bin + n, 'f', n % 2); // pad with 'f' if odd
89+
gsmbcd_swap_chars(bin, n + (n % 2));
90+
const int bytes = euicc_hexutil_hex2bin_r(output, output_len, bin, n + (n % 2));
91+
free(bin);
92+
if (bytes == -1) {
93+
return -1;
11794
}
118-
119-
return idx;
95+
memset(output + bytes, 0xff, padding_to - bytes);
96+
return bytes;
12097
}
12198

122-
int euicc_hexutil_bin2gsmbcd(char *output, uint32_t output_len, const uint8_t *binData, uint32_t length) {
123-
if (euicc_hexutil_bin2hex(output, output_len, binData, length)) {
99+
int euicc_hexutil_bin2gsmbcd(char *restrict output, const uint32_t output_len, const uint8_t *restrict bin,
100+
const uint32_t bin_len) {
101+
int n = euicc_hexutil_bin2hex(output, output_len, bin, bin_len);
102+
if (n < 0) {
124103
return -1;
125104
}
126-
127-
length = strlen(output);
128-
for (size_t i = 0; i < length - 1; i += 2) {
129-
char temp = output[i];
130-
output[i] = output[i + 1];
131-
output[i + 1] = temp;
105+
n -= 1; // ignore NUL terminator
106+
gsmbcd_swap_chars(output, n);
107+
// trim trailing 'f'
108+
while (n > 0 && output[n] == 'f') {
109+
output[n--] = '\0';
132110
}
133-
134-
for (uint32_t i = length - 1; i > 0; i--) {
135-
if (output[i] != 'f') {
136-
break;
137-
}
138-
output[i] = '\0';
139-
}
140-
141-
return 0;
111+
return n;
142112
}

euicc/hexutil.h

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
#pragma once
22

3-
#include <inttypes.h>
3+
#include <stdint.h>
44

5-
int euicc_hexutil_hex2bin_r(uint8_t *output, uint32_t output_len, const char *str, uint32_t str_len);
6-
int euicc_hexutil_hex2bin(uint8_t *output, uint32_t output_len, const char *str);
7-
int euicc_hexutil_bin2hex(char *output, uint32_t output_len, const uint8_t *bin, uint32_t bin_len);
8-
int euicc_hexutil_gsmbcd2bin(uint8_t *output, uint32_t output_len, const char *str, uint32_t padding_to);
9-
int euicc_hexutil_bin2gsmbcd(char *output, uint32_t output_len, const uint8_t *binData, uint32_t length);
5+
int euicc_hexutil_bin2hex(char *restrict output, uint32_t output_len, const uint8_t *restrict bin, uint32_t bin_len);
6+
7+
int euicc_hexutil_hex2bin(uint8_t *restrict output, uint32_t output_len, const char *restrict input);
8+
9+
int euicc_hexutil_hex2bin_r(uint8_t *restrict output, uint32_t output_len, const char *restrict input,
10+
uint32_t input_len);
11+
12+
int euicc_hexutil_gsmbcd2bin(uint8_t *restrict output, uint32_t output_len, const char *restrict input,
13+
uint32_t padding_to);
14+
15+
int euicc_hexutil_bin2gsmbcd(char *restrict output, uint32_t output_len, const uint8_t *restrict bin, uint32_t bin_len);

0 commit comments

Comments
 (0)