File Coverage

lib/Pcore/Util/IDN/PP.pm
Criterion Covered Total %
statement 66 99 66.6
branch 20 34 58.8
condition n/a
subroutine 7 9 77.7
pod 0 4 0.0
total 93 146 63.7


line stmt bran cond sub pod time code
1             package Pcore::Util::IDN::PP;
2              
3 4     4   25 use Pcore -const, -export => [qw[domain_to_ascii domain_to_utf8]];
  4         10  
  4         30  
4              
5             # punycode directly stolen from the Mojo::Util (c)
6              
7             const our $PC_BASE => 36;
8             const our $PC_TMIN => 1;
9             const our $PC_TMAX => 26;
10             const our $PC_SKEW => 38;
11             const our $PC_DAMP => 700;
12             const our $PC_INITIAL_BIAS => 72;
13             const our $PC_INITIAL_N => 128;
14              
15 4     4 0 7 sub domain_to_ascii ($domain) {
  4         9  
  4         5  
16 4 100       18 $domain = lc join q[.], map { /[^\x00-\x7f]/sm ? 'xn--' . to_punycode($_) : $_ } split /[.]/sm, $domain, -1;
  10         52  
17              
18 4         18 utf8::downgrade($domain);
19              
20 4         10 return $domain;
21             }
22              
23 0     0 0 0 sub domain_to_utf8 ($domain) {
  0         0  
  0         0  
24 0 0       0 $domain = lc join q[.], map { /\Axn--(.+)\z/sm ? from_punycode($1) : $_ } split /[.]/sm, $domain, -1;
  0         0  
25              
26 0         0 utf8::upgrade($domain);
27              
28 0         0 return $domain;
29             }
30              
31             # direct translation of RFC 3492
32 5     5 0 8 sub to_punycode ($output) {
  5         7  
  5         6  
33 4     4   29 use integer;
  4         8  
  4         30  
34              
35 5         8 my $n = $PC_INITIAL_N;
36              
37 5         8 my $delta = 0;
38              
39 5         8 my $bias = $PC_INITIAL_BIAS;
40              
41             # Extract basic code points
42 5         11 my $len = length $output;
43              
44 5         13 my @input = map {ord} split //sm, $output;
  19         35  
45              
46 5         10 my @chars = sort grep { $_ >= $PC_INITIAL_N } @input;
  19         53  
47              
48 5         28 $output =~ s/[^\x00-\x7f]+//smg;
49              
50 5         16 my $h = my $basic = length $output;
51              
52 5 50       15 $output .= "\x2d" if $basic > 0;
53              
54 5         11 for my $m (@chars) {
55 19 100       32 next if $m < $n;
56              
57 16         26 $delta += ( $m - $n ) * ( $h + 1 );
58              
59 16         22 $n = $m;
60              
61 16         30 for ( my $i = 0; $i < $len; $i++ ) {
62 92         117 my $c = $input[$i];
63              
64 92 100       166 if ( $c < $n ) {
    100          
65 39         56 $delta++;
66             }
67             elsif ( $c == $n ) {
68 19         28 my $q = $delta;
69              
70             # Base to infinity in steps of base
71 19         26 for ( my $k = $PC_BASE; 1; $k += $PC_BASE ) {
72 35         44 my $t = $k - $bias;
73              
74 35 100       69 $t = $t < $PC_TMIN ? $PC_TMIN : $t > $PC_TMAX ? $PC_TMAX : $t;
    100          
75              
76 35 100       65 last if $q < $t;
77              
78 16         25 my $o = $t + ( ( $q - $t ) % ( $PC_BASE - $t ) );
79              
80 16 100       47 $output .= chr $o + ( $o < 26 ? 0x61 : 0x30 - 26 );
81              
82 16         33 $q = ( $q - $t ) / ( $PC_BASE - $t );
83             }
84              
85 19 50       49 $output .= chr $q + ( $q < 26 ? 0x61 : 0x30 - 26 );
86              
87 19         50 $bias = _adapt( $delta, $h + 1, $h == $basic );
88              
89 19         31 $delta = 0;
90              
91 19         38 $h++;
92             }
93             }
94              
95 16         21 $delta++;
96              
97 16         24 $n++;
98             }
99              
100 5         31 return $output;
101             }
102              
103             # direct translation of RFC 3492
104 0     0 0 0 sub from_punycode ($input) {
  0         0  
  0         0  
105 4     4   1861 use integer;
  4         6  
  4         16  
106              
107 0         0 my $n = $PC_INITIAL_N;
108              
109 0         0 my $i = 0;
110              
111 0         0 my $bias = $PC_INITIAL_BIAS;
112              
113 0         0 my @output;
114              
115             # Consume all code points before the last delimiter
116 0 0       0 push @output, split //sm, $1 if $input =~ s/(.*)\x2d//sm;
117              
118 0         0 while ( $input ne q[] ) {
119 0         0 my $oldi = $i;
120              
121 0         0 my $w = 1;
122              
123             # Base to infinity in steps of base
124 0         0 for ( my $k = $PC_BASE; 1; $k += $PC_BASE ) {
125 0         0 my $digit = ord substr $input, 0, 1, q[];
126              
127 0 0       0 $digit = $digit < 0x40 ? $digit + ( 26 - 0x30 ) : ( $digit & 0x1f ) - 1;
128              
129 0         0 $i += $digit * $w;
130              
131 0         0 my $t = $k - $bias;
132              
133 0 0       0 $t = $t < $PC_TMIN ? $PC_TMIN : $t > $PC_TMAX ? $PC_TMAX : $t;
    0          
134              
135 0 0       0 last if $digit < $t;
136              
137 0         0 $w *= $PC_BASE - $t;
138             }
139              
140 0         0 $bias = _adapt( $i - $oldi, @output + 1, $oldi == 0 );
141              
142 0         0 $n += $i / ( @output + 1 );
143              
144 0         0 $i = $i % ( @output + 1 );
145              
146 0         0 splice @output, $i++, 0, chr $n;
147             }
148              
149 0         0 return join q[], @output;
150             }
151              
152 19     19   26 sub _adapt ( $delta, $numpoints, $firsttime ) {
  19         22  
  19         26  
  19         27  
  19         24  
153 4     4   1196 use integer;
  4         8  
  4         16  
154              
155 19 100       35 $delta = $firsttime ? $delta / $PC_DAMP : $delta / 2;
156              
157 19         25 $delta += $delta / $numpoints;
158              
159 19         24 my $k = 0;
160              
161 19         46 while ( $delta > ( ( $PC_BASE - $PC_TMIN ) * $PC_TMAX ) / 2 ) {
162 0         0 $delta /= $PC_BASE - $PC_TMIN;
163              
164 0         0 $k += $PC_BASE;
165             }
166              
167 19         40 return $k + ( ( ( $PC_BASE - $PC_TMIN + 1 ) * $delta ) / ( $delta + $PC_SKEW ) );
168             }
169              
170             1;
171             ## -----SOURCE FILTER LOG BEGIN-----
172             ##
173             ## PerlCritic profile "pcore-script" policy violations:
174             ## +------+----------------------+----------------------------------------------------------------------------------------------------------------+
175             ## | Sev. | Lines | Policy |
176             ## |======+======================+================================================================================================================|
177             ## | 3 | 116 | RegularExpressions::ProhibitCaptureWithoutTest - Capture variable used outside conditional |
178             ## |------+----------------------+----------------------------------------------------------------------------------------------------------------|
179             ## | 2 | 52 | ValuesAndExpressions::ProhibitEscapedCharacters - Numeric escapes in interpolated string |
180             ## |------+----------------------+----------------------------------------------------------------------------------------------------------------|
181             ## | 2 | 61, 71, 124 | ControlStructures::ProhibitCStyleForLoops - C-style "for" loop used |
182             ## +------+----------------------+----------------------------------------------------------------------------------------------------------------+
183             ##
184             ## -----SOURCE FILTER LOG END-----
185             __END__
186             =pod
187              
188             =encoding utf8
189              
190             =head1 NAME
191              
192             Pcore::Util::IDN::PP
193              
194             =head1 SYNOPSIS
195              
196             =head1 DESCRIPTION
197              
198             =head1 ATTRIBUTES
199              
200             =head1 METHODS
201              
202             =head1 SEE ALSO
203              
204             =cut