1 1.1 elric /* $NetBSD: punycode.c,v 1.2 2017/01/28 21:31:50 christos Exp $ */ 2 1.1 elric 3 1.1 elric /* 4 1.1 elric * Copyright (c) 2004 Kungliga Tekniska Hgskolan 5 1.1 elric * (Royal Institute of Technology, Stockholm, Sweden). 6 1.1 elric * All rights reserved. 7 1.1 elric * 8 1.1 elric * Redistribution and use in source and binary forms, with or without 9 1.1 elric * modification, are permitted provided that the following conditions 10 1.1 elric * are met: 11 1.1 elric * 12 1.1 elric * 1. Redistributions of source code must retain the above copyright 13 1.1 elric * notice, this list of conditions and the following disclaimer. 14 1.1 elric * 15 1.1 elric * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 elric * notice, this list of conditions and the following disclaimer in the 17 1.1 elric * documentation and/or other materials provided with the distribution. 18 1.1 elric * 19 1.1 elric * 3. Neither the name of the Institute nor the names of its contributors 20 1.1 elric * may be used to endorse or promote products derived from this software 21 1.1 elric * without specific prior written permission. 22 1.1 elric * 23 1.1 elric * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 1.1 elric * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 1.1 elric * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 1.1 elric * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 1.1 elric * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 1.1 elric * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 1.1 elric * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 1.1 elric * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 1.1 elric * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 1.1 elric * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 1.1 elric * SUCH DAMAGE. 34 1.1 elric */ 35 1.1 elric 36 1.1 elric #ifdef HAVE_CONFIG_H 37 1.1 elric #include <config.h> 38 1.1 elric #endif 39 1.1 elric #include <string.h> 40 1.1 elric #include "windlocl.h" 41 1.1 elric 42 1.1 elric static const unsigned base = 36; 43 1.1 elric static const unsigned t_min = 1; 44 1.1 elric static const unsigned t_max = 26; 45 1.1 elric static const unsigned skew = 38; 46 1.1 elric static const unsigned damp = 700; 47 1.1 elric static const unsigned initial_n = 128; 48 1.1 elric static const unsigned initial_bias = 72; 49 1.1 elric 50 1.1 elric static unsigned 51 1.1 elric digit(unsigned n) 52 1.1 elric { 53 1.1 elric return "abcdefghijklmnopqrstuvwxyz0123456789"[n]; 54 1.1 elric } 55 1.1 elric 56 1.1 elric static unsigned 57 1.1 elric adapt(unsigned delta, unsigned numpoints, int first) 58 1.1 elric { 59 1.1 elric unsigned k; 60 1.1 elric 61 1.1 elric if (first) 62 1.1 elric delta = delta / damp; 63 1.1 elric else 64 1.1 elric delta /= 2; 65 1.1 elric delta += delta / numpoints; 66 1.1 elric k = 0; 67 1.1 elric while (delta > ((base - t_min) * t_max) / 2) { 68 1.1 elric delta /= base - t_min; 69 1.1 elric k += base; 70 1.1 elric } 71 1.1 elric return k + (((base - t_min + 1) * delta) / (delta + skew)); 72 1.1 elric } 73 1.1 elric 74 1.1 elric /** 75 1.1 elric * Convert an UCS4 string to a puny-coded DNS label string suitable 76 1.1 elric * when combined with delimiters and other labels for DNS lookup. 77 1.1 elric * 78 1.1 elric * @param in an UCS4 string to convert 79 1.1 elric * @param in_len the length of in. 80 1.1 elric * @param out the resulting puny-coded string. The string is not NUL 81 1.1 elric * terminatied. 82 1.1 elric * @param out_len before processing out_len should be the length of 83 1.1 elric * the out variable, after processing it will be the length of the out 84 1.1 elric * string. 85 1.1 elric * 86 1.1 elric * @return returns 0 on success, an wind error code otherwise 87 1.1 elric * @ingroup wind 88 1.1 elric */ 89 1.1 elric 90 1.1 elric int 91 1.1 elric wind_punycode_label_toascii(const uint32_t *in, size_t in_len, 92 1.1 elric char *out, size_t *out_len) 93 1.1 elric { 94 1.1 elric unsigned n = initial_n; 95 1.1 elric unsigned delta = 0; 96 1.1 elric unsigned bias = initial_bias; 97 1.1 elric unsigned h = 0; 98 1.1 elric unsigned b; 99 1.1 elric unsigned i; 100 1.1 elric unsigned o = 0; 101 1.1 elric unsigned m; 102 1.1 elric 103 1.1 elric for (i = 0; i < in_len; ++i) { 104 1.1 elric if (in[i] < 0x80) { 105 1.1 elric ++h; 106 1.1 elric if (o >= *out_len) 107 1.1 elric return WIND_ERR_OVERRUN; 108 1.1 elric out[o++] = in[i]; 109 1.1 elric } 110 1.1 elric } 111 1.1 elric b = h; 112 1.1 elric if (b > 0) { 113 1.1 elric if (o >= *out_len) 114 1.1 elric return WIND_ERR_OVERRUN; 115 1.1 elric out[o++] = 0x2D; 116 1.1 elric } 117 1.1 elric /* is this string punycoded */ 118 1.1 elric if (h < in_len) { 119 1.1 elric if (o + 4 >= *out_len) 120 1.1 elric return WIND_ERR_OVERRUN; 121 1.1 elric memmove(out + 4, out, o); 122 1.1 elric memcpy(out, "xn--", 4); 123 1.1 elric o += 4; 124 1.1 elric } 125 1.1 elric 126 1.1 elric while (h < in_len) { 127 1.1 elric m = (unsigned)-1; 128 1.1 elric for (i = 0; i < in_len; ++i) 129 1.1 elric if(in[i] < m && in[i] >= n) 130 1.1 elric m = in[i]; 131 1.1 elric 132 1.1 elric delta += (m - n) * (h + 1); 133 1.1 elric n = m; 134 1.1 elric for (i = 0; i < in_len; ++i) { 135 1.1 elric if (in[i] < n) { 136 1.1 elric ++delta; 137 1.1 elric } else if (in[i] == n) { 138 1.1 elric unsigned q = delta; 139 1.1 elric unsigned k; 140 1.1 elric for (k = base; ; k += base) { 141 1.1 elric unsigned t; 142 1.1 elric if (k <= bias) 143 1.1 elric t = t_min; 144 1.1 elric else if (k >= bias + t_max) 145 1.1 elric t = t_max; 146 1.1 elric else 147 1.1 elric t = k - bias; 148 1.1 elric if (q < t) 149 1.1 elric break; 150 1.1 elric if (o >= *out_len) 151 1.1 elric return WIND_ERR_OVERRUN; 152 1.1 elric out[o++] = digit(t + ((q - t) % (base - t))); 153 1.1 elric q = (q - t) / (base - t); 154 1.1 elric } 155 1.1 elric if (o >= *out_len) 156 1.1 elric return WIND_ERR_OVERRUN; 157 1.1 elric out[o++] = digit(q); 158 1.1 elric /* output */ 159 1.1 elric bias = adapt(delta, h + 1, h == b); 160 1.1 elric delta = 0; 161 1.1 elric ++h; 162 1.1 elric } 163 1.1 elric } 164 1.1 elric ++delta; 165 1.1 elric ++n; 166 1.1 elric } 167 1.1 elric 168 1.1 elric *out_len = o; 169 1.1 elric return 0; 170 1.1 elric } 171