Add strn_fromhex(), improve hexvalue()

Implement fromhex() and fromhexstr() using strn_fromhex()
This commit is contained in:
Andrew Bettison 2013-09-03 17:29:41 +09:30
parent 9d1c3e0cba
commit 34bbfb9b30
2 changed files with 75 additions and 23 deletions

71
str.c
View File

@ -43,32 +43,67 @@ char *tohex(char *dstHex, const unsigned char *srcBinary, size_t bytes)
}
/* Convert nbinary*2 ASCII hex characters [0-9A-Fa-f] to nbinary bytes of data. Can be used to
perform the conversion in-place, eg, fromhex(buf, (char*)buf, n); Returns -1 if a non-hex-digit
character is encountered, otherwise returns the number of binary bytes produced (= nbinary).
@author Andrew Bettison <andrew@servalproject.com>
* perform the conversion in-place, eg, fromhex(buf, (char*)buf, n); Returns -1 if a non-hex-digit
* character is encountered, otherwise returns the number of binary bytes produced (= nbinary).
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
size_t fromhex(unsigned char *dstBinary, const char *srcHex, size_t nbinary)
{
size_t count = 0;
while (count != nbinary) {
unsigned char high = hexvalue(*srcHex++);
if (high & 0xf0) return -1;
unsigned char low = hexvalue(*srcHex++);
if (low & 0xf0) return -1;
dstBinary[count++] = (high << 4) + low;
}
return count;
if (strn_fromhex(dstBinary, nbinary, srcHex, NULL) == nbinary)
return nbinary;
return -1;
}
/* Convert nbinary*2 ASCII hex characters [0-9A-Fa-f] followed by a nul '\0' character to nbinary bytes of data. Can be used to
perform the conversion in-place, eg, fromhex(buf, (char*)buf, n); Returns -1 if a non-hex-digit
character is encountered or the character immediately following the last hex digit is not a nul,
otherwise returns zero.
@author Andrew Bettison <andrew@servalproject.com>
/* Convert nbinary*2 ASCII hex characters [0-9A-Fa-f] followed by a nul '\0' character to nbinary
* bytes of data. Can be used to perform the conversion in-place, eg, fromhex(buf, (char*)buf, n);
* Returns -1 if a non-hex-digit character is encountered or the character immediately following the
* last hex digit is not a nul, otherwise returns zero.
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
int fromhexstr(unsigned char *dstBinary, const char *srcHex, size_t nbinary)
{
return (fromhex(dstBinary, srcHex, nbinary) == nbinary && srcHex[nbinary * 2] == '\0') ? 0 : -1;
const char *p;
if (strn_fromhex(dstBinary, nbinary, srcHex, &p) == nbinary && *p == '\0')
return 0;
return -1;
}
/* Decode pairs of ASCII hex characters [0-9A-Fa-f] into binary data with an optional upper limit on
* the number of binary bytes produced (destination buffer size). Returns the number of binary
* bytes decoded. If 'afterHex' is not NULL, then sets *afterHex to point to the source character
* immediately following the last hex digit consumed.
*
* Can be used to perform a conversion in-place, eg:
*
* strn_fromhex((unsigned char *)buf, n, (const char *)buf, NULL);
*
* Can also be used to count hex digits without converting, eg:
*
* strn_fromhex(NULL, -1, buf, NULL);
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
size_t strn_fromhex(unsigned char *dstBinary, ssize_t dstlen, const char *srcHex, const char **afterHex)
{
unsigned char *dstorig = dstBinary;
unsigned char *dstend = dstBinary + dstlen;
while (dstlen == -1 || dstBinary < dstend) {
int high = hexvalue(srcHex[0]);
if (high == -1)
break;
int low = hexvalue(srcHex[1]);
if (low == -1)
break;
if (dstorig != NULL)
*dstBinary = (high << 4) + low;
++dstBinary;
srcHex += 2;
}
if (afterHex)
*afterHex = srcHex;
return dstBinary - dstorig;
}
/* Does this whole buffer contain the same value? */

27
str.h
View File

@ -64,19 +64,36 @@ extern const char hexdigit[16];
char *tohex(char *dstHex, const unsigned char *srcBinary, size_t bytes);
size_t fromhex(unsigned char *dstBinary, const char *srcHex, size_t nbinary);
int fromhexstr(unsigned char *dstBinary, const char *srcHex, size_t nbinary);
int is_all_matching(const unsigned char *ptr, size_t len, unsigned char value);
char *str_toupper_inplace(char *s);
size_t strn_fromhex(unsigned char *dstBinary, ssize_t dstlen, const char *src, const char **afterp);
#define alloca_tohex(buf,len) tohex((char *)alloca((len)*2+1), (buf), (len))
__STR_INLINE int hexvalue(char c)
{
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
switch (c) {
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
case 'a': case 'A': return 10;
case 'b': case 'B': return 11;
case 'c': case 'C': return 12;
case 'd': case 'D': return 13;
case 'e': case 'E': return 14;
case 'f': case 'F': return 15;
}
return -1;
}
int is_all_matching(const unsigned char *ptr, size_t len, unsigned char value);
char *str_toupper_inplace(char *s);
char *toprint(char *dstStr, ssize_t dstBufSiz, const char *srcBuf, size_t srcBytes, const char quotes[2]);
char *toprint_str(char *dstStr, ssize_t dstBufSiz, const char *srcStr, const char quotes[2]);
size_t toprint_len(const char *srcBuf, size_t srcBytes, const char quotes[2]);