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