1/* 2 * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 2000-2003 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id: hex.c,v 1.20 2008/09/25 04:02:39 tbox Exp $ */ 19 20/*! \file */ 21 22#include <config.h> 23 24#include <ctype.h> 25 26#include <isc/buffer.h> 27#include <isc/hex.h> 28#include <isc/lex.h> 29#include <isc/string.h> 30#include <isc/util.h> 31 32#define RETERR(x) do { \ 33 isc_result_t _r = (x); \ 34 if (_r != ISC_R_SUCCESS) \ 35 return (_r); \ 36 } while (0) 37 38 39/* 40 * BEW: These static functions are copied from lib/dns/rdata.c. 41 */ 42static isc_result_t 43str_totext(const char *source, isc_buffer_t *target); 44 45static isc_result_t 46mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length); 47 48static const char hex[] = "0123456789ABCDEF"; 49 50isc_result_t 51isc_hex_totext(isc_region_t *source, int wordlength, 52 const char *wordbreak, isc_buffer_t *target) 53{ 54 char buf[3]; 55 unsigned int loops = 0; 56 57 if (wordlength < 2) 58 wordlength = 2; 59 60 memset(buf, 0, sizeof(buf)); 61 while (source->length > 0) { 62 buf[0] = hex[(source->base[0] >> 4) & 0xf]; 63 buf[1] = hex[(source->base[0]) & 0xf]; 64 RETERR(str_totext(buf, target)); 65 isc_region_consume(source, 1); 66 67 loops++; 68 if (source->length != 0 && 69 (int)((loops + 1) * 2) >= wordlength) 70 { 71 loops = 0; 72 RETERR(str_totext(wordbreak, target)); 73 } 74 } 75 return (ISC_R_SUCCESS); 76} 77 78/*% 79 * State of a hex decoding process in progress. 80 */ 81typedef struct { 82 int length; /*%< Desired length of binary data or -1 */ 83 isc_buffer_t *target; /*%< Buffer for resulting binary data */ 84 int digits; /*%< Number of buffered hex digits */ 85 int val[2]; 86} hex_decode_ctx_t; 87 88static inline void 89hex_decode_init(hex_decode_ctx_t *ctx, int length, isc_buffer_t *target) 90{ 91 ctx->digits = 0; 92 ctx->length = length; 93 ctx->target = target; 94} 95 96static inline isc_result_t 97hex_decode_char(hex_decode_ctx_t *ctx, int c) { 98 char *s; 99 100 if ((s = strchr(hex, toupper(c))) == NULL) 101 return (ISC_R_BADHEX); 102 ctx->val[ctx->digits++] = s - hex; 103 if (ctx->digits == 2) { 104 unsigned char num; 105 106 num = (ctx->val[0] << 4) + (ctx->val[1]); 107 RETERR(mem_tobuffer(ctx->target, &num, 1)); 108 if (ctx->length >= 0) { 109 if (ctx->length == 0) 110 return (ISC_R_BADHEX); 111 else 112 ctx->length -= 1; 113 } 114 ctx->digits = 0; 115 } 116 return (ISC_R_SUCCESS); 117} 118 119static inline isc_result_t 120hex_decode_finish(hex_decode_ctx_t *ctx) { 121 if (ctx->length > 0) 122 return (ISC_R_UNEXPECTEDEND); 123 if (ctx->digits != 0) 124 return (ISC_R_BADHEX); 125 return (ISC_R_SUCCESS); 126} 127 128isc_result_t 129isc_hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) { 130 hex_decode_ctx_t ctx; 131 isc_textregion_t *tr; 132 isc_token_t token; 133 isc_boolean_t eol; 134 135 hex_decode_init(&ctx, length, target); 136 137 while (ctx.length != 0) { 138 unsigned int i; 139 140 if (length > 0) 141 eol = ISC_FALSE; 142 else 143 eol = ISC_TRUE; 144 RETERR(isc_lex_getmastertoken(lexer, &token, 145 isc_tokentype_string, eol)); 146 if (token.type != isc_tokentype_string) 147 break; 148 tr = &token.value.as_textregion; 149 for (i = 0; i < tr->length; i++) 150 RETERR(hex_decode_char(&ctx, tr->base[i])); 151 } 152 if (ctx.length < 0) 153 isc_lex_ungettoken(lexer, &token); 154 RETERR(hex_decode_finish(&ctx)); 155 return (ISC_R_SUCCESS); 156} 157 158isc_result_t 159isc_hex_decodestring(const char *cstr, isc_buffer_t *target) { 160 hex_decode_ctx_t ctx; 161 162 hex_decode_init(&ctx, -1, target); 163 for (;;) { 164 int c = *cstr++; 165 if (c == '\0') 166 break; 167 if (c == ' ' || c == '\t' || c == '\n' || c== '\r') 168 continue; 169 RETERR(hex_decode_char(&ctx, c)); 170 } 171 RETERR(hex_decode_finish(&ctx)); 172 return (ISC_R_SUCCESS); 173} 174 175static isc_result_t 176str_totext(const char *source, isc_buffer_t *target) { 177 unsigned int l; 178 isc_region_t region; 179 180 isc_buffer_availableregion(target, ®ion); 181 l = strlen(source); 182 183 if (l > region.length) 184 return (ISC_R_NOSPACE); 185 186 memcpy(region.base, source, l); 187 isc_buffer_add(target, l); 188 return (ISC_R_SUCCESS); 189} 190 191static isc_result_t 192mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) { 193 isc_region_t tr; 194 195 isc_buffer_availableregion(target, &tr); 196 if (length > tr.length) 197 return (ISC_R_NOSPACE); 198 memcpy(tr.base, base, length); 199 isc_buffer_add(target, length); 200 return (ISC_R_SUCCESS); 201} 202