|  | @@ -60,6 +60,48 @@ void base16_encode ( const uint8_t *raw, size_t len, char *encoded ) {
 | 
		
	
		
			
			| 60 | 60 |  	assert ( strlen ( encoded ) == base16_encoded_len ( len ) );
 | 
		
	
		
			
			| 61 | 61 |  }
 | 
		
	
		
			
			| 62 | 62 |  
 | 
		
	
		
			
			|  | 63 | +/**
 | 
		
	
		
			
			|  | 64 | + * Decode hexadecimal string
 | 
		
	
		
			
			|  | 65 | + *
 | 
		
	
		
			
			|  | 66 | + * @v encoded		Encoded string
 | 
		
	
		
			
			|  | 67 | + * @v separator		Byte separator character, or 0 for no separator
 | 
		
	
		
			
			|  | 68 | + * @v data		Buffer
 | 
		
	
		
			
			|  | 69 | + * @v len		Length of buffer
 | 
		
	
		
			
			|  | 70 | + * @ret len		Length of data, or negative error
 | 
		
	
		
			
			|  | 71 | + */
 | 
		
	
		
			
			|  | 72 | +int hex_decode ( const char *encoded, char separator, void *data, size_t len ) {
 | 
		
	
		
			
			|  | 73 | +	uint8_t *out = data;
 | 
		
	
		
			
			|  | 74 | +	unsigned int count = 0;
 | 
		
	
		
			
			|  | 75 | +	unsigned int sixteens;
 | 
		
	
		
			
			|  | 76 | +	unsigned int units;
 | 
		
	
		
			
			|  | 77 | +
 | 
		
	
		
			
			|  | 78 | +	while ( *encoded ) {
 | 
		
	
		
			
			|  | 79 | +
 | 
		
	
		
			
			|  | 80 | +		/* Check separator, if applicable */
 | 
		
	
		
			
			|  | 81 | +		if ( count && separator && ( ( *(encoded++) != separator ) ) )
 | 
		
	
		
			
			|  | 82 | +			return -EINVAL;
 | 
		
	
		
			
			|  | 83 | +
 | 
		
	
		
			
			|  | 84 | +		/* Extract digits.  Note that either digit may be NUL,
 | 
		
	
		
			
			|  | 85 | +		 * which would be interpreted as an invalid value by
 | 
		
	
		
			
			|  | 86 | +		 * strtoul_charval(); there is therefore no need for an
 | 
		
	
		
			
			|  | 87 | +		 * explicit end-of-string check.
 | 
		
	
		
			
			|  | 88 | +		 */
 | 
		
	
		
			
			|  | 89 | +		sixteens = strtoul_charval ( *(encoded++) );
 | 
		
	
		
			
			|  | 90 | +		if ( sixteens >= 16 )
 | 
		
	
		
			
			|  | 91 | +			return -EINVAL;
 | 
		
	
		
			
			|  | 92 | +		units = strtoul_charval ( *(encoded++) );
 | 
		
	
		
			
			|  | 93 | +		if ( units >= 16 )
 | 
		
	
		
			
			|  | 94 | +			return -EINVAL;
 | 
		
	
		
			
			|  | 95 | +
 | 
		
	
		
			
			|  | 96 | +		/* Store result */
 | 
		
	
		
			
			|  | 97 | +		if ( count < len )
 | 
		
	
		
			
			|  | 98 | +			out[count] = ( ( sixteens << 4 ) | units );
 | 
		
	
		
			
			|  | 99 | +		count++;
 | 
		
	
		
			
			|  | 100 | +
 | 
		
	
		
			
			|  | 101 | +	}
 | 
		
	
		
			
			|  | 102 | +	return count;
 | 
		
	
		
			
			|  | 103 | +}
 | 
		
	
		
			
			|  | 104 | +
 | 
		
	
		
			
			| 63 | 105 |  /**
 | 
		
	
		
			
			| 64 | 106 |   * Base16-decode data
 | 
		
	
		
			
			| 65 | 107 |   *
 | 
		
	
	
		
			
			|  | @@ -75,33 +117,15 @@ void base16_encode ( const uint8_t *raw, size_t len, char *encoded ) {
 | 
		
	
		
			
			| 75 | 117 |   * to provide a buffer of the correct size.
 | 
		
	
		
			
			| 76 | 118 |   */
 | 
		
	
		
			
			| 77 | 119 |  int base16_decode ( const char *encoded, uint8_t *raw ) {
 | 
		
	
		
			
			| 78 |  | -	const char *encoded_bytes = encoded;
 | 
		
	
		
			
			| 79 |  | -	uint8_t *raw_bytes = raw;
 | 
		
	
		
			
			| 80 |  | -	char buf[3];
 | 
		
	
		
			
			| 81 |  | -	char *endp;
 | 
		
	
		
			
			| 82 |  | -	size_t len;
 | 
		
	
		
			
			| 83 |  | -
 | 
		
	
		
			
			| 84 |  | -	while ( encoded_bytes[0] ) {
 | 
		
	
		
			
			| 85 |  | -		if ( ! encoded_bytes[1] ) {
 | 
		
	
		
			
			| 86 |  | -			DBG ( "Base16-encoded string \"%s\" has invalid "
 | 
		
	
		
			
			| 87 |  | -			      "length\n", encoded );
 | 
		
	
		
			
			| 88 |  | -			return -EINVAL;
 | 
		
	
		
			
			| 89 |  | -		}
 | 
		
	
		
			
			| 90 |  | -		memcpy ( buf, encoded_bytes, 2 );
 | 
		
	
		
			
			| 91 |  | -		buf[2] = '\0';
 | 
		
	
		
			
			| 92 |  | -		*(raw_bytes++) = strtoul ( buf, &endp, 16 );
 | 
		
	
		
			
			| 93 |  | -		if ( *endp != '\0' ) {
 | 
		
	
		
			
			| 94 |  | -			DBG ( "Base16-encoded string \"%s\" has invalid "
 | 
		
	
		
			
			| 95 |  | -			      "byte \"%s\"\n", encoded, buf );
 | 
		
	
		
			
			| 96 |  | -			return -EINVAL;
 | 
		
	
		
			
			| 97 |  | -		}
 | 
		
	
		
			
			| 98 |  | -		encoded_bytes += 2;
 | 
		
	
		
			
			| 99 |  | -	}
 | 
		
	
		
			
			| 100 |  | -	len = ( raw_bytes - raw );
 | 
		
	
		
			
			|  | 120 | +	int len;
 | 
		
	
		
			
			|  | 121 | +
 | 
		
	
		
			
			|  | 122 | +	len = hex_decode ( encoded, 0, raw, -1UL );
 | 
		
	
		
			
			|  | 123 | +	if ( len < 0 )
 | 
		
	
		
			
			|  | 124 | +		return len;
 | 
		
	
		
			
			| 101 | 125 |  
 | 
		
	
		
			
			| 102 | 126 |  	DBG ( "Base16-decoded \"%s\" to:\n", encoded );
 | 
		
	
		
			
			| 103 | 127 |  	DBG_HDA ( 0, raw, len );
 | 
		
	
		
			
			| 104 | 128 |  	assert ( len <= base16_decoded_max_len ( encoded ) );
 | 
		
	
		
			
			| 105 | 129 |  
 | 
		
	
		
			
			| 106 |  | -	return ( len );
 | 
		
	
		
			
			|  | 130 | +	return len;
 | 
		
	
		
			
			| 107 | 131 |  }
 |