diff options
-rw-r--r-- | docs/library/ubinascii.rst | 5 | ||||
-rw-r--r-- | extmod/modubinascii.c | 33 | ||||
-rw-r--r-- | py/lexer.c | 12 | ||||
-rw-r--r-- | py/misc.h | 1 | ||||
-rw-r--r-- | py/qstrdefs.h | 1 | ||||
-rw-r--r-- | py/unicode.c | 10 | ||||
-rw-r--r-- | tests/extmod/ubinascii_unhexlify.py | 9 |
7 files changed, 59 insertions, 12 deletions
diff --git a/docs/library/ubinascii.rst b/docs/library/ubinascii.rst index 9dba9180d2..a6327ea308 100644 --- a/docs/library/ubinascii.rst +++ b/docs/library/ubinascii.rst @@ -13,3 +13,8 @@ Functions .. function:: hexlify(data) Convert binary data to hexadecimal representation. Return bytes string. + +.. function:: unhexlify(data) + + Convert hexadecimal data to binary representation. Return bytes string. + (i.e. inverse of hexlify) diff --git a/extmod/modubinascii.c b/extmod/modubinascii.c index e258818af4..5e366cae89 100644 --- a/extmod/modubinascii.c +++ b/extmod/modubinascii.c @@ -35,6 +35,8 @@ #if MICROPY_PY_UBINASCII STATIC mp_obj_t mod_binascii_hexlify(mp_uint_t n_args, const mp_obj_t *args) { + // Second argument is for an extension to allow a separator to be used + // between values. (void)n_args; mp_buffer_info_t bufinfo; 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) { } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_hexlify_obj, 1, 2, mod_binascii_hexlify); +STATIC mp_obj_t mod_binascii_unhexlify(mp_obj_t data) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ); + + if ((bufinfo.len & 1) != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "odd-length string")); + } + vstr_t vstr; + vstr_init_len(&vstr, bufinfo.len / 2); + byte *in = bufinfo.buf, *out = (byte*)vstr.buf; + byte hex_byte = 0; + for (mp_uint_t i = bufinfo.len; i--;) { + byte hex_ch = *in++; + if (unichar_isxdigit(hex_ch)) { + hex_byte += unichar_xdigit_value(hex_ch); + } else { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "non-hex digit found")); + } + if (i & 1) { + hex_byte <<= 4; + } else { + *out++ = hex_byte; + hex_byte = 0; + } + } + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_unhexlify_obj, mod_binascii_unhexlify); + STATIC const mp_map_elem_t mp_module_binascii_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ubinascii) }, { MP_OBJ_NEW_QSTR(MP_QSTR_hexlify), (mp_obj_t)&mod_binascii_hexlify_obj }, -// { MP_OBJ_NEW_QSTR(MP_QSTR_unhexlify), (mp_obj_t)&mod_binascii_unhexlify_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_unhexlify), (mp_obj_t)&mod_binascii_unhexlify_obj }, // { MP_OBJ_NEW_QSTR(MP_QSTR_a2b_base64), (mp_obj_t)&mod_binascii_a2b_base64_obj }, // { MP_OBJ_NEW_QSTR(MP_QSTR_b2a_base64), (mp_obj_t)&mod_binascii_b2a_base64_obj }, }; diff --git a/py/lexer.c b/py/lexer.c index 536208e41f..12cb5ae5b2 100644 --- a/py/lexer.c +++ b/py/lexer.c @@ -261,16 +261,6 @@ STATIC const char *tok_kw[] = { "__debug__", }; -STATIC mp_uint_t hex_digit(unichar c) { - // c is assumed to be hex digit - mp_uint_t n = c - '0'; - if (n > 9) { - n &= ~('a' - 'A'); - n -= ('A' - ('9' + 1)); - } - return n; -} - // This is called with CUR_CHAR() before first hex digit, and should return with // it pointing to last hex digit // 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) { if (!unichar_isxdigit(c)) { return false; } - num = (num << 4) + hex_digit(c); + num = (num << 4) + unichar_xdigit_value(c); } *result = num; return true; @@ -127,6 +127,7 @@ bool unichar_isupper(unichar c); bool unichar_islower(unichar c); unichar unichar_tolower(unichar c); unichar unichar_toupper(unichar c); +mp_uint_t unichar_xdigit_value(unichar c); mp_uint_t unichar_charlen(const char *str, mp_uint_t len); #define UTF8_IS_NONASCII(ch) ((ch) & 0x80) #define UTF8_IS_CONT(ch) (((ch) & 0xC0) == 0x80) diff --git a/py/qstrdefs.h b/py/qstrdefs.h index 5d0dc9d274..a5e543bbbc 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -584,6 +584,7 @@ Q(sha256) #if MICROPY_PY_UBINASCII Q(ubinascii) Q(hexlify) +Q(unhexlify) #endif #if MICROPY_PY_MACHINE diff --git a/py/unicode.c b/py/unicode.c index db4aa438ac..63e9601185 100644 --- a/py/unicode.c +++ b/py/unicode.c @@ -169,3 +169,13 @@ unichar unichar_toupper(unichar c) { } return c; } + +mp_uint_t unichar_xdigit_value(unichar c) { + // c is assumed to be hex digit + mp_uint_t n = c - '0'; + if (n > 9) { + n &= ~('a' - 'A'); + n -= ('A' - ('9' + 1)); + } + return n; +} diff --git a/tests/extmod/ubinascii_unhexlify.py b/tests/extmod/ubinascii_unhexlify.py new file mode 100644 index 0000000000..1ec6972c5b --- /dev/null +++ b/tests/extmod/ubinascii_unhexlify.py @@ -0,0 +1,9 @@ +try: + import ubinascii as binascii +except ImportError: + import binascii + +print(binascii.unhexlify(b'0001020304050607')) +print(binascii.unhexlify(b'08090a0b0c0d0e0f')) +print(binascii.unhexlify(b'7f80ff')) +print(binascii.unhexlify(b'313233344142434461626364')) |