1135446Strhodes/*
2262706Serwin * Copyright (C) 2004, 2005, 2007, 2008, 2013, 2014  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 2000-2003  Internet Software Consortium.
4135446Strhodes *
5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6135446Strhodes * purpose with or without fee is hereby granted, provided that the above
7135446Strhodes * copyright notice and this permission notice appear in all copies.
8135446Strhodes *
9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11135446Strhodes * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15135446Strhodes * PERFORMANCE OF THIS SOFTWARE.
16135446Strhodes */
17135446Strhodes
18234010Sdougb/* $Id: hex.c,v 1.20 2008/09/25 04:02:39 tbox Exp $ */
19135446Strhodes
20170222Sdougb/*! \file */
21170222Sdougb
22135446Strhodes#include <config.h>
23135446Strhodes
24135446Strhodes#include <ctype.h>
25135446Strhodes
26135446Strhodes#include <isc/buffer.h>
27135446Strhodes#include <isc/hex.h>
28135446Strhodes#include <isc/lex.h>
29135446Strhodes#include <isc/string.h>
30135446Strhodes#include <isc/util.h>
31135446Strhodes
32135446Strhodes#define RETERR(x) do { \
33135446Strhodes	isc_result_t _r = (x); \
34135446Strhodes	if (_r != ISC_R_SUCCESS) \
35135446Strhodes		return (_r); \
36135446Strhodes	} while (0)
37135446Strhodes
38135446Strhodes
39135446Strhodes/*
40135446Strhodes * BEW: These static functions are copied from lib/dns/rdata.c.
41135446Strhodes */
42135446Strhodesstatic isc_result_t
43135446Strhodesstr_totext(const char *source, isc_buffer_t *target);
44135446Strhodes
45135446Strhodesstatic isc_result_t
46135446Strhodesmem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
47135446Strhodes
48135446Strhodesstatic const char hex[] = "0123456789ABCDEF";
49135446Strhodes
50135446Strhodesisc_result_t
51135446Strhodesisc_hex_totext(isc_region_t *source, int wordlength,
52135446Strhodes	       const char *wordbreak, isc_buffer_t *target)
53135446Strhodes{
54135446Strhodes	char buf[3];
55135446Strhodes	unsigned int loops = 0;
56135446Strhodes
57135446Strhodes	if (wordlength < 2)
58135446Strhodes		wordlength = 2;
59135446Strhodes
60135446Strhodes	memset(buf, 0, sizeof(buf));
61135446Strhodes	while (source->length > 0) {
62135446Strhodes		buf[0] = hex[(source->base[0] >> 4) & 0xf];
63135446Strhodes		buf[1] = hex[(source->base[0]) & 0xf];
64135446Strhodes		RETERR(str_totext(buf, target));
65135446Strhodes		isc_region_consume(source, 1);
66135446Strhodes
67135446Strhodes		loops++;
68135446Strhodes		if (source->length != 0 &&
69135446Strhodes		    (int)((loops + 1) * 2) >= wordlength)
70135446Strhodes		{
71135446Strhodes			loops = 0;
72135446Strhodes			RETERR(str_totext(wordbreak, target));
73135446Strhodes		}
74135446Strhodes	}
75135446Strhodes	return (ISC_R_SUCCESS);
76135446Strhodes}
77135446Strhodes
78170222Sdougb/*%
79135446Strhodes * State of a hex decoding process in progress.
80135446Strhodes */
81135446Strhodestypedef struct {
82170222Sdougb	int length;		/*%< Desired length of binary data or -1 */
83170222Sdougb	isc_buffer_t *target;	/*%< Buffer for resulting binary data */
84170222Sdougb	int digits;		/*%< Number of buffered hex digits */
85135446Strhodes	int val[2];
86135446Strhodes} hex_decode_ctx_t;
87135446Strhodes
88135446Strhodesstatic inline void
89135446Strhodeshex_decode_init(hex_decode_ctx_t *ctx, int length, isc_buffer_t *target)
90135446Strhodes{
91135446Strhodes	ctx->digits = 0;
92135446Strhodes	ctx->length = length;
93135446Strhodes	ctx->target = target;
94135446Strhodes}
95135446Strhodes
96135446Strhodesstatic inline isc_result_t
97135446Strhodeshex_decode_char(hex_decode_ctx_t *ctx, int c) {
98135446Strhodes	char *s;
99135446Strhodes
100135446Strhodes	if ((s = strchr(hex, toupper(c))) == NULL)
101135446Strhodes		return (ISC_R_BADHEX);
102262706Serwin	ctx->val[ctx->digits++] = (int)(s - hex);
103135446Strhodes	if (ctx->digits == 2) {
104135446Strhodes		unsigned char num;
105135446Strhodes
106135446Strhodes		num = (ctx->val[0] << 4) + (ctx->val[1]);
107135446Strhodes		RETERR(mem_tobuffer(ctx->target, &num, 1));
108135446Strhodes		if (ctx->length >= 0) {
109135446Strhodes			if (ctx->length == 0)
110135446Strhodes				return (ISC_R_BADHEX);
111135446Strhodes			else
112135446Strhodes				ctx->length -= 1;
113135446Strhodes		}
114135446Strhodes		ctx->digits = 0;
115135446Strhodes	}
116135446Strhodes	return (ISC_R_SUCCESS);
117135446Strhodes}
118135446Strhodes
119135446Strhodesstatic inline isc_result_t
120135446Strhodeshex_decode_finish(hex_decode_ctx_t *ctx) {
121135446Strhodes	if (ctx->length > 0)
122135446Strhodes		return (ISC_R_UNEXPECTEDEND);
123135446Strhodes	if (ctx->digits != 0)
124135446Strhodes		return (ISC_R_BADHEX);
125135446Strhodes	return (ISC_R_SUCCESS);
126135446Strhodes}
127135446Strhodes
128135446Strhodesisc_result_t
129135446Strhodesisc_hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) {
130135446Strhodes	hex_decode_ctx_t ctx;
131135446Strhodes	isc_textregion_t *tr;
132135446Strhodes	isc_token_t token;
133135446Strhodes	isc_boolean_t eol;
134135446Strhodes
135135446Strhodes	hex_decode_init(&ctx, length, target);
136135446Strhodes
137135446Strhodes	while (ctx.length != 0) {
138135446Strhodes		unsigned int i;
139135446Strhodes
140135446Strhodes		if (length > 0)
141135446Strhodes			eol = ISC_FALSE;
142135446Strhodes		else
143135446Strhodes			eol = ISC_TRUE;
144135446Strhodes		RETERR(isc_lex_getmastertoken(lexer, &token,
145135446Strhodes					      isc_tokentype_string, eol));
146135446Strhodes		if (token.type != isc_tokentype_string)
147135446Strhodes			break;
148135446Strhodes		tr = &token.value.as_textregion;
149135446Strhodes		for (i = 0; i < tr->length; i++)
150135446Strhodes			RETERR(hex_decode_char(&ctx, tr->base[i]));
151135446Strhodes	}
152135446Strhodes	if (ctx.length < 0)
153135446Strhodes		isc_lex_ungettoken(lexer, &token);
154135446Strhodes	RETERR(hex_decode_finish(&ctx));
155135446Strhodes	return (ISC_R_SUCCESS);
156135446Strhodes}
157135446Strhodes
158135446Strhodesisc_result_t
159193149Sdougbisc_hex_decodestring(const char *cstr, isc_buffer_t *target) {
160135446Strhodes	hex_decode_ctx_t ctx;
161135446Strhodes
162135446Strhodes	hex_decode_init(&ctx, -1, target);
163135446Strhodes	for (;;) {
164135446Strhodes		int c = *cstr++;
165135446Strhodes		if (c == '\0')
166135446Strhodes			break;
167135446Strhodes		if (c == ' ' || c == '\t' || c == '\n' || c== '\r')
168135446Strhodes			continue;
169135446Strhodes		RETERR(hex_decode_char(&ctx, c));
170135446Strhodes	}
171193149Sdougb	RETERR(hex_decode_finish(&ctx));
172135446Strhodes	return (ISC_R_SUCCESS);
173135446Strhodes}
174135446Strhodes
175135446Strhodesstatic isc_result_t
176135446Strhodesstr_totext(const char *source, isc_buffer_t *target) {
177135446Strhodes	unsigned int l;
178135446Strhodes	isc_region_t region;
179135446Strhodes
180135446Strhodes	isc_buffer_availableregion(target, &region);
181135446Strhodes	l = strlen(source);
182135446Strhodes
183135446Strhodes	if (l > region.length)
184135446Strhodes		return (ISC_R_NOSPACE);
185135446Strhodes
186262706Serwin	memmove(region.base, source, l);
187135446Strhodes	isc_buffer_add(target, l);
188135446Strhodes	return (ISC_R_SUCCESS);
189135446Strhodes}
190135446Strhodes
191135446Strhodesstatic isc_result_t
192135446Strhodesmem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
193135446Strhodes	isc_region_t tr;
194135446Strhodes
195135446Strhodes	isc_buffer_availableregion(target, &tr);
196135446Strhodes	if (length > tr.length)
197135446Strhodes		return (ISC_R_NOSPACE);
198262706Serwin	memmove(tr.base, base, length);
199135446Strhodes	isc_buffer_add(target, length);
200135446Strhodes	return (ISC_R_SUCCESS);
201135446Strhodes}
202