From 076f58c4bf9fa1ae0faa65a731523cb531705974 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 12 Jul 2013 14:44:20 +0200 Subject: [PATCH] [base16] Generalise base16_decode() to hex_decode() Provide a generic hex_decode() routine which can be shared between the Base16 code and the "hex" and "hexhyp" settings parsers. Signed-off-by: Michael Brown --- src/core/base16.c | 70 ++++++++++++++++++++++++++------------- src/core/misc.c | 13 ++++++++ src/include/ipxe/base16.h | 2 ++ src/include/stdlib.h | 14 +------- 4 files changed, 63 insertions(+), 36 deletions(-) diff --git a/src/core/base16.c b/src/core/base16.c index 1f0e536c5..7fa4b2009 100644 --- a/src/core/base16.c +++ b/src/core/base16.c @@ -60,6 +60,48 @@ void base16_encode ( const uint8_t *raw, size_t len, char *encoded ) { assert ( strlen ( encoded ) == base16_encoded_len ( len ) ); } +/** + * Decode hexadecimal string + * + * @v encoded Encoded string + * @v separator Byte separator character, or 0 for no separator + * @v data Buffer + * @v len Length of buffer + * @ret len Length of data, or negative error + */ +int hex_decode ( const char *encoded, char separator, void *data, size_t len ) { + uint8_t *out = data; + unsigned int count = 0; + unsigned int sixteens; + unsigned int units; + + while ( *encoded ) { + + /* Check separator, if applicable */ + if ( count && separator && ( ( *(encoded++) != separator ) ) ) + return -EINVAL; + + /* Extract digits. Note that either digit may be NUL, + * which would be interpreted as an invalid value by + * strtoul_charval(); there is therefore no need for an + * explicit end-of-string check. + */ + sixteens = strtoul_charval ( *(encoded++) ); + if ( sixteens >= 16 ) + return -EINVAL; + units = strtoul_charval ( *(encoded++) ); + if ( units >= 16 ) + return -EINVAL; + + /* Store result */ + if ( count < len ) + out[count] = ( ( sixteens << 4 ) | units ); + count++; + + } + return count; +} + /** * Base16-decode data * @@ -75,33 +117,15 @@ void base16_encode ( const uint8_t *raw, size_t len, char *encoded ) { * to provide a buffer of the correct size. */ int base16_decode ( const char *encoded, uint8_t *raw ) { - const char *encoded_bytes = encoded; - uint8_t *raw_bytes = raw; - char buf[3]; - char *endp; - size_t len; + int len; - while ( encoded_bytes[0] ) { - if ( ! encoded_bytes[1] ) { - DBG ( "Base16-encoded string \"%s\" has invalid " - "length\n", encoded ); - return -EINVAL; - } - memcpy ( buf, encoded_bytes, 2 ); - buf[2] = '\0'; - *(raw_bytes++) = strtoul ( buf, &endp, 16 ); - if ( *endp != '\0' ) { - DBG ( "Base16-encoded string \"%s\" has invalid " - "byte \"%s\"\n", encoded, buf ); - return -EINVAL; - } - encoded_bytes += 2; - } - len = ( raw_bytes - raw ); + len = hex_decode ( encoded, 0, raw, -1UL ); + if ( len < 0 ) + return len; DBG ( "Base16-decoded \"%s\" to:\n", encoded ); DBG_HDA ( 0, raw, len ); assert ( len <= base16_decoded_max_len ( encoded ) ); - return ( len ); + return len; } diff --git a/src/core/misc.c b/src/core/misc.c index 11342481a..eaceddfea 100644 --- a/src/core/misc.c +++ b/src/core/misc.c @@ -33,6 +33,19 @@ int inet_aton ( const char *cp, struct in_addr *inp ) { return 0; } +unsigned int strtoul_charval ( unsigned int charval ) { + + if ( charval >= 'a' ) { + charval = ( charval - 'a' + 10 ); + } else if ( charval >= 'A' ) { + charval = ( charval - 'A' + 10 ); + } else if ( charval <= '9' ) { + charval = ( charval - '0' ); + } + + return charval; +} + unsigned long strtoul ( const char *p, char **endp, int base ) { unsigned long ret = 0; int negative = 0; diff --git a/src/include/ipxe/base16.h b/src/include/ipxe/base16.h index f0c9842f9..60e3f2315 100644 --- a/src/include/ipxe/base16.h +++ b/src/include/ipxe/base16.h @@ -33,6 +33,8 @@ static inline size_t base16_decoded_max_len ( const char *encoded ) { } extern void base16_encode ( const uint8_t *raw, size_t len, char *encoded ); +extern int hex_decode ( const char *string, char separator, void *data, + size_t len ); extern int base16_decode ( const char *encoded, uint8_t *raw ); #endif /* _IPXE_BASE16_H */ diff --git a/src/include/stdlib.h b/src/include/stdlib.h index 3d30858ff..bca85a234 100644 --- a/src/include/stdlib.h +++ b/src/include/stdlib.h @@ -34,19 +34,7 @@ static inline int strtoul_base ( const char **pp, int base ) return base; } -static inline unsigned int strtoul_charval ( unsigned int charval ) -{ - if ( charval >= 'a' ) { - charval = ( charval - 'a' + 10 ); - } else if ( charval >= 'A' ) { - charval = ( charval - 'A' + 10 ); - } else if ( charval <= '9' ) { - charval = ( charval - '0' ); - } - - return charval; -} - +extern unsigned int strtoul_charval ( unsigned int charval ); extern unsigned long strtoul ( const char *p, char **endp, int base ); extern unsigned long long strtoull ( const char *p, char **endp, int base );