#include "uv.h"
#include "idna.h"
#include <assert.h>
#include <string.h>
#include <limits.h>
static unsigned uv__utf8_decode1_slow(const char** p,
const char* pe,
unsigned a) {
unsigned b;
unsigned c;
unsigned d;
unsigned min;
if (a > 0xF7)
return -1;
switch (pe - *p) {
default:
if (a > 0xEF) {
min = 0x10000;
a = a & 7;
b = (unsigned char) *(*p)++;
c = (unsigned char) *(*p)++;
d = (unsigned char) *(*p)++;
break;
}
case 2:
if (a > 0xDF) {
min = 0x800;
b = 0x80 | (a & 15);
c = (unsigned char) *(*p)++;
d = (unsigned char) *(*p)++;
a = 0;
break;
}
case 1:
if (a > 0xBF) {
min = 0x80;
b = 0x80;
c = 0x80 | (a & 31);
d = (unsigned char) *(*p)++;
a = 0;
break;
}
case 0:
return -1;
}
if (0x80 != (0xC0 & (b ^ c ^ d)))
return -1;
b &= 63;
c &= 63;
d &= 63;
a = (a << 18) | (b << 12) | (c << 6) | d;
if (a < min)
return -1;
if (a > 0x10FFFF)
return -1;
if (a >= 0xD800 && a <= 0xDFFF)
return -1;
return a;
}
unsigned uv__utf8_decode1(const char** p, const char* pe) {
unsigned a;
assert(*p < pe);
a = (unsigned char) *(*p)++;
if (a < 128)
return a;
return uv__utf8_decode1_slow(p, pe, a);
}
static int uv__idna_toascii_label(const char* s, const char* se,
char** d, char* de) {
static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz0123456789";
const char* ss;
unsigned c;
unsigned h;
unsigned k;
unsigned n;
unsigned m;
unsigned q;
unsigned t;
unsigned x;
unsigned y;
unsigned bias;
unsigned delta;
unsigned todo;
int first;
h = 0;
ss = s;
todo = 0;
while (s < se) {
c = uv__utf8_decode1(&s, se);
if (c == UINT_MAX)
return UV_EINVAL;
if (c < 128)
h++;
else
todo++;
}
if (todo > 0) {
if (*d < de) *(*d)++ = 'x';
if (*d < de) *(*d)++ = 'n';
if (*d < de) *(*d)++ = '-';
if (*d < de) *(*d)++ = '-';
}
x = 0;
s = ss;
while (s < se) {
c = uv__utf8_decode1(&s, se);
assert(c != UINT_MAX);
if (c > 127)
continue;
if (*d < de)
*(*d)++ = c;
if (++x == h)
break;
}
if (todo == 0)
return h;
if (h > 0)
if (*d < de)
*(*d)++ = '-';
n = 128;
bias = 72;
delta = 0;
first = 1;
while (todo > 0) {
m = -1;
s = ss;
while (s < se) {
c = uv__utf8_decode1(&s, se);
assert(c != UINT_MAX);
if (c >= n)
if (c < m)
m = c;
}
x = m - n;
y = h + 1;
if (x > ~delta / y)
return UV_E2BIG;
delta += x * y;
n = m;
s = ss;
while (s < se) {
c = uv__utf8_decode1(&s, se);
assert(c != UINT_MAX);
if (c < n)
if (++delta == 0)
return UV_E2BIG;
if (c != n)
continue;
for (k = 36, q = delta; ; k += 36) {
t = 1;
if (k > bias)
t = k - bias;
if (t > 26)
t = 26;
if (q < t)
break;
x = q - t;
y = 36 - t;
q = x / y;
t = t + x % y;
if (*d < de)
*(*d)++ = alphabet[t];
}
if (*d < de)
*(*d)++ = alphabet[q];
delta /= 2;
if (first) {
delta /= 350;
first = 0;
}
h++;
delta += delta / h;
for (bias = 0; delta > 35 * 26 / 2; bias += 36)
delta /= 35;
bias += 36 * delta / (delta + 38);
delta = 0;
todo--;
}
delta++;
n++;
}
return 0;
}
long uv__idna_toascii(const char* s, const char* se, char* d, char* de) {
const char* si;
const char* st;
unsigned c;
char* ds;
int rc;
if (s == se)
return UV_EINVAL;
ds = d;
si = s;
while (si < se) {
st = si;
c = uv__utf8_decode1(&si, se);
if (c == UINT_MAX)
return UV_EINVAL;
if (c != '.')
if (c != 0x3002)
if (c != 0xFF0E)
if (c != 0xFF61)
continue;
rc = uv__idna_toascii_label(s, st, &d, de);
if (rc < 0)
return rc;
if (d < de)
*d++ = '.';
s = si;
}
if (s < se) {
rc = uv__idna_toascii_label(s, se, &d, de);
if (rc < 0)
return rc;
}
if (d >= de)
return UV_EINVAL;
*d++ = '\0';
return d - ds;
}