summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/core/base16.c72
-rw-r--r--src/core/misc.c13
-rw-r--r--src/include/ipxe/base16.h2
-rw-r--r--src/include/stdlib.h14
4 files changed, 64 insertions, 37 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
@@ -61,6 +61,48 @@ void base16_encode ( const uint8_t *raw, size_t len, char *encoded ) {
}
/**
+ * 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
*
* @v encoded Encoded string
@@ -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;
}
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 );