]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[base16] Generalise base16_decode() to hex_decode()
authorMichael Brown <mcb30@ipxe.org>
Fri, 12 Jul 2013 12:44:20 +0000 (14:44 +0200)
committerMichael Brown <mcb30@ipxe.org>
Fri, 12 Jul 2013 13:14:36 +0000 (15:14 +0200)
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>
src/core/base16.c
src/core/misc.c
src/include/ipxe/base16.h
src/include/stdlib.h

index 1f0e536c5a4ff0b36c6b07cacba7a29be082dfd9..7fa4b20094406e4cae1847b9b68a21724525c703 100644 (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;
-
-       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;
 }
index 11342481a73c12cfad1163d16d989027accc8d52..eaceddfea5fec02cd678cd5b5b261416ded192fb 100644 (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;
index f0c9842f952b2e7fc2658fea27fde8a73aefe703..60e3f2315728cffe29e1e4e12155313a35e32969 100644 (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 */
index 3d30858ffcd25e12b3b37da2b362e6d361cf2999..bca85a234e6014fa3ab2b008c6631a4bf79bcc7c 100644 (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 );