Skip to content

Commit 3ad94d6

Browse files
dhylandsdpgeorge
authored andcommitted
extmod: Add ubinascii.unhexlify
This also pulls out hex_digit from py/lexer.c and makes unichar_hex_digit
1 parent 97ce883 commit 3ad94d6

7 files changed

Lines changed: 59 additions & 12 deletions

File tree

docs/library/ubinascii.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,8 @@ Functions
1313
.. function:: hexlify(data)
1414

1515
Convert binary data to hexadecimal representation. Return bytes string.
16+
17+
.. function:: unhexlify(data)
18+
19+
Convert hexadecimal data to binary representation. Return bytes string.
20+
(i.e. inverse of hexlify)

extmod/modubinascii.c

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
#if MICROPY_PY_UBINASCII
3636

3737
STATIC mp_obj_t mod_binascii_hexlify(mp_uint_t n_args, const mp_obj_t *args) {
38+
// Second argument is for an extension to allow a separator to be used
39+
// between values.
3840
(void)n_args;
3941
mp_buffer_info_t bufinfo;
4042
mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
@@ -58,10 +60,39 @@ STATIC mp_obj_t mod_binascii_hexlify(mp_uint_t n_args, const mp_obj_t *args) {
5860
}
5961
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_hexlify_obj, 1, 2, mod_binascii_hexlify);
6062

63+
STATIC mp_obj_t mod_binascii_unhexlify(mp_obj_t data) {
64+
mp_buffer_info_t bufinfo;
65+
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
66+
67+
if ((bufinfo.len & 1) != 0) {
68+
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "odd-length string"));
69+
}
70+
vstr_t vstr;
71+
vstr_init_len(&vstr, bufinfo.len / 2);
72+
byte *in = bufinfo.buf, *out = (byte*)vstr.buf;
73+
byte hex_byte = 0;
74+
for (mp_uint_t i = bufinfo.len; i--;) {
75+
byte hex_ch = *in++;
76+
if (unichar_isxdigit(hex_ch)) {
77+
hex_byte += unichar_xdigit_value(hex_ch);
78+
} else {
79+
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "non-hex digit found"));
80+
}
81+
if (i & 1) {
82+
hex_byte <<= 4;
83+
} else {
84+
*out++ = hex_byte;
85+
hex_byte = 0;
86+
}
87+
}
88+
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
89+
}
90+
MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_unhexlify_obj, mod_binascii_unhexlify);
91+
6192
STATIC const mp_map_elem_t mp_module_binascii_globals_table[] = {
6293
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ubinascii) },
6394
{ MP_OBJ_NEW_QSTR(MP_QSTR_hexlify), (mp_obj_t)&mod_binascii_hexlify_obj },
64-
// { MP_OBJ_NEW_QSTR(MP_QSTR_unhexlify), (mp_obj_t)&mod_binascii_unhexlify_obj },
95+
{ MP_OBJ_NEW_QSTR(MP_QSTR_unhexlify), (mp_obj_t)&mod_binascii_unhexlify_obj },
6596
// { MP_OBJ_NEW_QSTR(MP_QSTR_a2b_base64), (mp_obj_t)&mod_binascii_a2b_base64_obj },
6697
// { MP_OBJ_NEW_QSTR(MP_QSTR_b2a_base64), (mp_obj_t)&mod_binascii_b2a_base64_obj },
6798
};

py/lexer.c

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -261,16 +261,6 @@ STATIC const char *tok_kw[] = {
261261
"__debug__",
262262
};
263263

264-
STATIC mp_uint_t hex_digit(unichar c) {
265-
// c is assumed to be hex digit
266-
mp_uint_t n = c - '0';
267-
if (n > 9) {
268-
n &= ~('a' - 'A');
269-
n -= ('A' - ('9' + 1));
270-
}
271-
return n;
272-
}
273-
274264
// This is called with CUR_CHAR() before first hex digit, and should return with
275265
// it pointing to last hex digit
276266
// num_digits must be greater than zero
@@ -282,7 +272,7 @@ STATIC bool get_hex(mp_lexer_t *lex, mp_uint_t num_digits, mp_uint_t *result) {
282272
if (!unichar_isxdigit(c)) {
283273
return false;
284274
}
285-
num = (num << 4) + hex_digit(c);
275+
num = (num << 4) + unichar_xdigit_value(c);
286276
}
287277
*result = num;
288278
return true;

py/misc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ bool unichar_isupper(unichar c);
127127
bool unichar_islower(unichar c);
128128
unichar unichar_tolower(unichar c);
129129
unichar unichar_toupper(unichar c);
130+
mp_uint_t unichar_xdigit_value(unichar c);
130131
mp_uint_t unichar_charlen(const char *str, mp_uint_t len);
131132
#define UTF8_IS_NONASCII(ch) ((ch) & 0x80)
132133
#define UTF8_IS_CONT(ch) (((ch) & 0xC0) == 0x80)

py/qstrdefs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,7 @@ Q(sha256)
584584
#if MICROPY_PY_UBINASCII
585585
Q(ubinascii)
586586
Q(hexlify)
587+
Q(unhexlify)
587588
#endif
588589

589590
#if MICROPY_PY_MACHINE

py/unicode.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,13 @@ unichar unichar_toupper(unichar c) {
169169
}
170170
return c;
171171
}
172+
173+
mp_uint_t unichar_xdigit_value(unichar c) {
174+
// c is assumed to be hex digit
175+
mp_uint_t n = c - '0';
176+
if (n > 9) {
177+
n &= ~('a' - 'A');
178+
n -= ('A' - ('9' + 1));
179+
}
180+
return n;
181+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
try:
2+
import ubinascii as binascii
3+
except ImportError:
4+
import binascii
5+
6+
print(binascii.unhexlify(b'0001020304050607'))
7+
print(binascii.unhexlify(b'08090a0b0c0d0e0f'))
8+
print(binascii.unhexlify(b'7f80ff'))
9+
print(binascii.unhexlify(b'313233344142434461626364'))

0 commit comments

Comments
 (0)