File Coverage

lib/Net/IDN/Punycode.xs
Criterion Covered Total %
statement 0 107 0.0
branch 0 94 0.0
condition n/a
subroutine n/a
pod n/a
total 0 201 0.0


line stmt bran cond sub pod time code
1             #include "EXTERN.h"
2             #include "perl.h"
3             #include "XSUB.h"
4              
5             #ifdef XS_VERSION
6             #undef XS_VERSION
7             #endif
8             #define XS_VERSION "2.499_20180929"
9              
10             #define BASE 36
11             #define TMIN 1
12             #define TMAX 26
13             #define SKEW 38
14             #define DAMP 700
15             #define INITIAL_BIAS 72
16             #define INITIAL_N 128
17              
18             #define isBASE(x) UTF8_IS_INVARIANT((unsigned char)x)
19             #define DELIM '-'
20              
21             #define TMIN_MAX(t) (((t) < TMIN) ? (TMIN) : ((t) > TMAX) ? (TMAX) : (t))
22              
23             #ifndef utf8_to_uvchr_buf
24             #define utf8_to_uvchr_buf(in_p,in_e,u8) utf8_to_uvchr(in_p,u8);
25             #endif
26              
27             static char enc_digit[BASE] = {
28             'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
29             'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
30             '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
31             };
32              
33             static IV dec_digit[0x80] = {
34             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 00..0F */
35             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 10..1F */
36             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 20..2F */
37             26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1, /* 30..3F */
38             -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 40..4F */
39             15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 50..5F */
40             -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 60..6F */
41             15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 70..7F */
42             };
43              
44             static int adapt(int delta, int numpoints, int first) {
45             int k;
46              
47 0 0         delta /= first ? DAMP : 2;
    0          
48 0           delta += delta/numpoints;
49              
50 0 0         for(k=0; delta > ((BASE-TMIN) * TMAX)/2; k += BASE)
    0          
51 0           delta /= BASE-TMIN;
52              
53 0           return k + (((BASE-TMIN+1) * delta) / (delta+SKEW));
54             };
55              
56             static void
57 0           grow_string(SV *const sv, char **start, char **current, char **end, STRLEN add)
58             {
59             STRLEN len;
60              
61 0 0         if(*current + add <= *end)
62             return;
63              
64 0           len = (*current - *start);
65 0 0         *start = SvGROW(sv, (len + add + 15) & ~15);
    0          
66 0           *current = *start + len;
67 0           *end = *start + SvLEN(sv);
68             }
69              
70             MODULE = Net::IDN::Punycode PACKAGE = Net::IDN::Punycode
71              
72             SV*
73             encode_punycode(input)
74             SV * input
75             PREINIT:
76             UV c, m, n = INITIAL_N;
77             int k, q, t;
78             int bias = INITIAL_BIAS;
79             int delta = 0, skip_delta;
80              
81             const char *in_s, *in_p, *in_e, *skip_p;
82             char *re_s, *re_p, *re_e;
83             int first = 1;
84             STRLEN length_guess, len, h, u8;
85              
86             CODE:
87 0 0         in_s = in_p = SvPVutf8(input, len);
88 0           in_e = in_s + len;
89              
90             length_guess = len;
91 0 0         if(length_guess < 64) length_guess = 64; /* optimise for maximum length of domain names */
92 0           length_guess += 2; /* plus DELIM + '\0' */
93              
94 0           RETVAL = NEWSV('P',length_guess);
95 0           SvPOK_only(RETVAL);
96 0 0         re_s = re_p = SvPV_nolen(RETVAL);
97 0           re_e = re_s + SvLEN(RETVAL);
98             h = 0;
99              
100             /* copy basic code points */
101 0 0         while(in_p < in_e) {
102 0 0         if( isBASE(*in_p) ) {
103 0           grow_string(RETVAL, &re_s, &re_p, &re_e, sizeof(char));
104 0           *re_p++ = *in_p;
105 0           h++;
106             }
107 0           in_p++;
108             }
109              
110             /* add DELIM if needed */
111 0 0         if(h) {
112 0           grow_string(RETVAL, &re_s, &re_p, &re_e, sizeof(char));
113 0           *re_p++ = DELIM;
114             }
115              
116             for(;;) {
117             /* find smallest code point not yet handled */
118             m = UV_MAX;
119             q = skip_delta = 0;
120              
121 0 0         for(in_p = skip_p = in_s; in_p < in_e;) {
122 0 0         c = utf8_to_uvchr_buf((U8*)in_p, (U8*)in_e, &u8);
123             c = NATIVE_TO_UNI(c);
124              
125 0 0         if(c >= n && c < m) {
126             m = c;
127             skip_p = in_p;
128             skip_delta = q;
129             }
130 0 0         if(c < n)
131 0           ++q;
132 0           in_p += u8;
133             }
134 0 0         if(m == UV_MAX)
135             break;
136              
137             /* increase delta to the state corresponding to
138             the m code point at the beginning of the string */
139 0           delta += (m-n) * (h+1);
140             n = m;
141              
142             /* now find the chars to be encoded in this round */
143              
144 0           delta += skip_delta;
145 0 0         for(in_p = skip_p; in_p < in_e;) {
146 0 0         c = utf8_to_uvchr_buf((U8*)in_p, (U8*)in_e, &u8);
147             c = NATIVE_TO_UNI(c);
148              
149 0 0         if(c < n) {
150 0           ++delta;
151 0 0         } else if( c == n ) {
152             q = delta;
153              
154 0           for(k = BASE;; k += BASE) {
155 0 0         t = TMIN_MAX(k - bias);
156 0 0         if(q < t) break;
157 0           grow_string(RETVAL, &re_s, &re_p, &re_e, sizeof(char));
158 0           *re_p++ = enc_digit[t + ((q-t) % (BASE-t))];
159 0           q = (q-t) / (BASE-t);
160 0           }
161 0 0         if(q > BASE) croak("input exceeds punycode limit");
162 0           grow_string(RETVAL, &re_s, &re_p, &re_e, sizeof(char));
163 0           *re_p++ = enc_digit[q];
164 0           bias = adapt(delta, h+1, first);
165             delta = first = 0;
166 0           ++h;
167             }
168 0           in_p += u8;
169             }
170 0           ++delta;
171 0           ++n;
172 0           }
173 0           grow_string(RETVAL, &re_s, &re_p, &re_e, sizeof(char));
174 0           *re_p = 0;
175 0           SvCUR_set(RETVAL, re_p - re_s);
176             OUTPUT:
177             RETVAL
178              
179             SV*
180             decode_punycode(input)
181             SV * input
182             PREINIT:
183             UV c, n = INITIAL_N;
184             IV dc;
185             int i = 0, oldi, j, k, t, w;
186              
187             int bias = INITIAL_BIAS;
188             int delta = 0, skip_delta;
189              
190             const char *in_s, *in_p, *in_e, *skip_p;
191             char *re_s, *re_p, *re_e;
192             int first = 1;
193             STRLEN length_guess, len, h, u8;
194              
195             CODE:
196 0 0         in_s = in_p = SvPV_nolen(input);
197 0           in_e = SvEND(input);
198              
199 0           length_guess = SvCUR(input) * 2;
200 0 0         if(length_guess < 256) length_guess = 256;
201              
202 0           RETVAL = NEWSV('D',length_guess);
203 0           SvPOK_only(RETVAL);
204 0 0         re_s = re_p = SvPV_nolen(RETVAL);
205 0           re_e = re_s + SvLEN(RETVAL);
206              
207             skip_p = NULL;
208 0 0         for(in_p = in_s; in_p < in_e; in_p++) {
209 0           c = *in_p; /* we don't care whether it's UTF-8 */
210 0 0         if(!isBASE(c)) croak("non-base character in input for decode_punycode");
211 0 0         if(c == DELIM) skip_p = in_p;
212 0           grow_string(RETVAL, &re_s, &re_p, &re_e, 1);
213 0           *re_p++ = c; /* copy it */
214             }
215              
216 0 0         if(skip_p) {
217 0           h = skip_p - in_s; /* base chars handled */
218 0           re_p = re_s + h; /* points to end of base chars */
219 0           skip_p++; /* skip over DELIM */
220             } else {
221             h = 0; /* no base chars */
222 0           re_p = re_s;
223             skip_p = in_s; /* read everything */
224             }
225              
226 0 0         for(in_p = skip_p; in_p < in_e; i++) {
227             oldi = i;
228             w = 1;
229              
230 0           for(k = BASE;; k+= BASE) {
231 0 0         if(!(in_p < in_e)) croak("incomplete encoded code point in decode_punycode");
232 0           dc = dec_digit[*in_p++]; /* we already know it's in 0..127 */
233 0 0         if(dc < 0) croak("invalid digit in input for decode_punycode");
234 0           c = (UV)dc;
235 0           i += c * w;
236 0 0         t = TMIN_MAX(k - bias);
237 0 0         if(c < t) break;
238 0           w *= BASE-t;
239 0           }
240 0           h++;
241 0           bias = adapt(i-oldi, h, first);
242             first = 0;
243 0           n += i / h; /* code point n to insert */
244 0           i = i % h; /* at position i */
245              
246 0 0         u8 = UNISKIP(n); /* how many bytes we need */
    0          
    0          
    0          
    0          
    0          
    0          
247              
248             j = i;
249 0 0         for(skip_p = re_s; j > 0; j--) /* find position in UTF-8 */
250 0           skip_p+=UTF8SKIP(skip_p);
251              
252 0           grow_string(RETVAL, &re_s, &re_p, &re_e, u8);
253 0 0         if(skip_p < re_p) /* move succeeding chars */
254 0           Move(skip_p, skip_p + u8, re_p - skip_p, char);
255 0           re_p += u8;
256 0           uvuni_to_utf8_flags((U8*)skip_p, n, UNICODE_ALLOW_ANY);
257             }
258              
259 0 0         if(!first) SvUTF8_on(RETVAL); /* UTF-8 chars have been inserted */
260 0           grow_string(RETVAL, &re_s, &re_p, &re_e, 1);
261 0           *re_p = 0;
262 0           SvCUR_set(RETVAL, re_p - re_s);
263             OUTPUT:
264             RETVAL