Add isc_hex_* routines, which handle conversion to and from hex strings.

This commit is contained in:
Brian Wellington
2000-11-07 20:58:08 +00:00
parent b7bf1bc9d9
commit 19e0a2c2d1
6 changed files with 313 additions and 9 deletions

View File

@@ -13,7 +13,7 @@
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# $Id: Makefile.in,v 1.66 2000/09/20 19:06:02 gson Exp $
# $Id: Makefile.in,v 1.67 2000/11/07 20:58:04 bwelling Exp $
srcdir = @srcdir@
VPATH = @srcdir@
@@ -51,7 +51,7 @@ WIN32OBJS = win32/condition.@O@ win32/dir.@O@ win32/file.@O@ \
OBJS = @ISC_EXTRA_OBJS@ \
assertions.@O@ base64.@O@ bitstring.@O@ buffer.@O@ \
bufferlist.@O@ commandline.@O@ error.@O@ event.@O@ \
heap.@O@ hmacmd5.@O@ \
heap.@O@ hex.@O@ hmacmd5.@O@ \
lex.@O@ lfsr.@O@ lib.@O@ log.@O@ \
md5.@O@ mem.@O@ mutexblock.@O@ netaddr.@O@ ondestroy.@O@ \
quota.@O@ random.@O@ \
@@ -64,7 +64,7 @@ OBJS = @ISC_EXTRA_OBJS@ \
SRCS = @ISC_EXTRA_SRCS@ \
assertions.c base64.c bitstring.c buffer.c \
bufferlist.c commandline.c error.c event.c \
heap.c hmacmd5.c \
heap.c hex.c hmacmd5.c \
lex.c lfsr.c lib.c log.c \
md5.c mem.c mutexblock.c netaddr.c ondestroy.c \
quota.c random.c \

224
lib/isc/hex.c Normal file
View File

@@ -0,0 +1,224 @@
#include <config.h>
#include <isc/buffer.h>
#include <isc/hex.h>
#include <isc/lex.h>
#include <isc/string.h>
#include <isc/util.h>
#define RETERR(x) do { \
isc_result_t _r = (x); \
if (_r != ISC_R_SUCCESS) \
return (_r); \
} while (0)
/*
* BEW: These static functions are copied from lib/dns/rdata.c.
*/
static isc_result_t
str_totext(const char *source, isc_buffer_t *target);
static isc_result_t
gettoken(isc_lex_t *lexer, isc_token_t *token, isc_tokentype_t expect,
isc_boolean_t eol);
static isc_result_t
mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
static const char hex[] = "0123456789ABCDEF";
isc_result_t
isc_hex_totext(isc_region_t *source, int wordlength,
const char *wordbreak, isc_buffer_t *target)
{
char buf[3];
unsigned int loops = 0;
if (wordlength < 2)
wordlength = 2;
memset(buf, 0, sizeof buf);
while (source->length > 0) {
buf[0] = hex[(source->base[0] >> 4) & 0xf];
buf[1] = hex[(source->base[0]) & 0xf];
RETERR(str_totext(buf, target));
isc_region_consume(source, 1);
loops++;
if (source->length != 0 &&
(int)((loops + 1) * 2) >= wordlength)
{
loops = 0;
RETERR(str_totext(wordbreak, target));
}
}
return (ISC_R_SUCCESS);
}
/*
* State of a hex decoding process in progress.
*/
typedef struct {
int length; /* Desired length of binary data or -1 */
isc_buffer_t *target; /* Buffer for resulting binary data */
int digits; /* Number of buffered hex digits */
int val[2];
} hex_decode_ctx_t;
static inline void
hex_decode_init(hex_decode_ctx_t *ctx, int length, isc_buffer_t *target)
{
ctx->digits = 0;
ctx->length = length;
ctx->target = target;
}
static inline isc_result_t
hex_decode_char(hex_decode_ctx_t *ctx, int c) {
char *s;
if ((s = strchr(hex, c)) == NULL)
return (ISC_R_BADHEX);
ctx->val[ctx->digits++] = s - hex;
if (ctx->digits == 2) {
int n;
unsigned char num;
num = (ctx->val[0] << 4) + (ctx->val[1]);
RETERR(mem_tobuffer(ctx->target, &num, 1));
if (ctx->length >= 0) {
if (n > ctx->length)
return (ISC_R_BADHEX);
else
ctx->length -= n;
}
ctx->digits = 0;
}
return (ISC_R_SUCCESS);
}
static inline isc_result_t
hex_decode_finish(hex_decode_ctx_t *ctx) {
if (ctx->length > 0)
return (ISC_R_UNEXPECTEDEND);
if (ctx->digits != 0)
return (ISC_R_BADHEX);
return (ISC_R_SUCCESS);
}
isc_result_t
isc_hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
hex_decode_ctx_t ctx;
isc_textregion_t *tr;
isc_token_t token;
hex_decode_init(&ctx, length, target);
while (ctx.length != 0) {
unsigned int i;
if (length > 0)
RETERR(gettoken(lexer, &token, isc_tokentype_string,
ISC_FALSE));
else
RETERR(gettoken(lexer, &token, isc_tokentype_string,
ISC_TRUE));
if (token.type != isc_tokentype_string)
break;
tr = &token.value.as_textregion;
for (i = 0 ;i < tr->length; i++)
RETERR(hex_decode_char(&ctx, tr->base[i]));
}
RETERR(hex_decode_finish(&ctx));
return (ISC_R_SUCCESS);
}
isc_result_t
isc_hex_decodestring(isc_mem_t *mctx, char *cstr, isc_buffer_t *target) {
hex_decode_ctx_t ctx;
UNUSED(mctx);
hex_decode_init(&ctx, -1, target);
for (;;) {
int c = *cstr++;
if (c == '\0')
break;
if (c == ' ' || c == '\t' || c == '\n' || c== '\r')
continue;
RETERR(hex_decode_char(&ctx, c));
}
RETERR(hex_decode_finish(&ctx));
return (ISC_R_SUCCESS);
}
static isc_result_t
str_totext(const char *source, isc_buffer_t *target) {
unsigned int l;
isc_region_t region;
isc_buffer_availableregion(target, &region);
l = strlen(source);
if (l > region.length)
return (ISC_R_NOSPACE);
memcpy(region.base, source, l);
isc_buffer_add(target, l);
return (ISC_R_SUCCESS);
}
static isc_result_t
mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
isc_region_t tr;
isc_buffer_availableregion(target, &tr);
if (length > tr.length)
return (ISC_R_NOSPACE);
memcpy(tr.base, base, length);
isc_buffer_add(target, length);
return (ISC_R_SUCCESS);
}
static isc_result_t
gettoken(isc_lex_t *lexer, isc_token_t *token, isc_tokentype_t expect,
isc_boolean_t eol)
{
unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE;
isc_result_t result;
if (expect == isc_tokentype_qstring)
options |= ISC_LEXOPT_QSTRING;
else if (expect == isc_tokentype_number)
options |= ISC_LEXOPT_NUMBER;
result = isc_lex_gettoken(lexer, options, token);
switch (result) {
case ISC_R_SUCCESS:
break;
case ISC_R_NOMEMORY:
return (ISC_R_NOMEMORY);
case ISC_R_NOSPACE:
return (ISC_R_NOSPACE);
default:
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_lex_gettoken() failed: %s",
isc_result_totext(result));
return (ISC_R_UNEXPECTED);
}
if (eol && ((token->type == isc_tokentype_eol) ||
(token->type == isc_tokentype_eof)))
return (ISC_R_SUCCESS);
if (token->type == isc_tokentype_string &&
expect == isc_tokentype_qstring)
return (ISC_R_SUCCESS);
if (token->type != expect) {
isc_lex_ungettoken(lexer, token);
if (token->type == isc_tokentype_eol ||
token->type == isc_tokentype_eof)
return (ISC_R_UNEXPECTEDEND);
return (ISC_R_UNEXPECTEDTOKEN);
}
return (ISC_R_SUCCESS);
}

View File

@@ -13,7 +13,7 @@
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# $Id: Makefile.in,v 1.44 2000/09/20 19:06:03 gson Exp $
# $Id: Makefile.in,v 1.45 2000/11/07 20:58:06 bwelling Exp $
srcdir = @srcdir@
VPATH = @srcdir@
@@ -29,7 +29,7 @@ top_srcdir = @top_srcdir@
HEADERS = assertions.h base64.h bitstring.h boolean.h buffer.h \
bufferlist.h commandline.h entropy.h error.h event.h \
eventclass.h \
file.h formatcheck.h fsaccess.h heap.h hmacmd5.h \
file.h formatcheck.h fsaccess.h heap.h hex.h hmacmd5.h \
interfaceiter.h @ISC_IPV6_H@ lang.h lex.h \
lfsr.h lib.h list.h log.h magic.h md5.h mem.h msgcat.h \
mutexblock.h netaddr.h ondestroy.h os.h \

78
lib/isc/include/isc/hex.h Normal file
View File

@@ -0,0 +1,78 @@
#ifndef ISC_HEX_H
#define ISC_HEX_H 1
#include <isc/lang.h>
#include <isc/types.h>
ISC_LANG_BEGINDECLS
/***
*** Functions
***/
isc_result_t
isc_hex_totext(isc_region_t *source, int wordlength,
const char *wordbreak, isc_buffer_t *target);
/*
* Convert data into hex encoded text.
*
* Notes:
* The hex encoded text in 'target' will be divided into
* words of at most 'wordlength' characters, separated by
* the 'wordbreak' string. No parentheses will surround
* the text.
*
* Requires:
* 'source' is a region containing binary data
* 'target' is a text buffer containing available space
* 'wordbreak' points to a null-terminated string of
* zero or more whitespace characters
*
* Ensures:
* target will contain the hex encoded version of the data
* in source. The 'used' pointer in target will be advanced as
* necessary.
*/
isc_result_t
isc_hex_decodestring(isc_mem_t *mctx, char *cstr, isc_buffer_t *target);
/*
* Decode a null-terminated hex string.
*
* Requires:
* 'mctx' is non-null.
* 'cstr' is non-null.
* 'target' is a valid buffer.
*
* Returns:
* ISC_R_SUCCESS -- the entire decoded representation of 'cstring'
* fit in 'target'.
* ISC_R_BADHEX -- 'cstr' is not a valid hex encoding.
*
* Other error returns are any possible error code from:
* isc_lex_create(),
* isc_lex_openbuffer(),
* isc_hex_tobuffer().
*/
isc_result_t
isc_hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length);
/*
* Convert hex encoded text from a lexer context into data.
*
* Requires:
* 'lex' is a valid lexer context
* 'target' is a buffer containing binary data
* 'length' is an integer
*
* Ensures:
* target will contain the data represented by the hex encoded
* string parsed by the lexer. No more than length bytes will be read,
* if length is positive. The 'used' pointer in target will be
* advanced as necessary.
*/
ISC_LANG_ENDDECLS
#endif /* ISC_HEX_H */

View File

@@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: result.h,v 1.50 2000/08/15 23:30:22 tale Exp $ */
/* $Id: result.h,v 1.51 2000/11/07 20:58:07 bwelling Exp $ */
#ifndef ISC_RESULT_H
#define ISC_RESULT_H 1
@@ -72,11 +72,12 @@
#define ISC_R_QUEUEFULL 46 /* queue is full */
#define ISC_R_FAMILYMISMATCH 47 /* address family mismatch */
#define ISC_R_FAMILYNOSUPPORT 48 /* AF not supported */
#define ISC_R_BADHEX 49 /* bad hex encoding */
/*
* Not a result code: the number of results.
*/
#define ISC_R_NRESULTS 49
#define ISC_R_NRESULTS 50
ISC_LANG_BEGINDECLS

View File

@@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: result.c,v 1.48 2000/08/15 01:43:36 marka Exp $ */
/* $Id: result.c,v 1.49 2000/11/07 20:58:05 bwelling Exp $ */
#include <config.h>
@@ -86,7 +86,8 @@ static const char *text[ISC_R_NRESULTS] = {
"not a directory", /* 45 */
"queue is full", /* 46 */
"address family mismatch", /* 47 */
"address family not supported" /* 48 */
"address family not supported", /* 48 */
"bad hex encoding", /* 49 */
};
#define ISC_RESULT_RESULTSET 2