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