Skip to content

Commit

Permalink
[base16] Generalise base16_decode() to hex_decode()
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
mcb30 committed Jul 12, 2013
1 parent 362a628 commit 076f58c
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 37 deletions.
72 changes: 48 additions & 24 deletions src/core/base16.c
Expand Up @@ -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
*
Expand All @@ -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;

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 );
int len;

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;
}
13 changes: 13 additions & 0 deletions src/core/misc.c
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions src/include/ipxe/base16.h
Expand Up @@ -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 */
14 changes: 1 addition & 13 deletions src/include/stdlib.h
Expand Up @@ -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 );

Expand Down

0 comments on commit 076f58c

Please sign in to comment.