[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 <mcb30@ipxe.org>
pull/13/head
Michael Brown 2013-07-12 14:44:20 +02:00
parent 362a628e52
commit 076f58c4bf
4 changed files with 63 additions and 36 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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 */

View File

@ -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 );