line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Convert::RACE; |
2
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
30315
|
use strict; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
122
|
|
4
|
2
|
|
|
2
|
|
12
|
use vars qw($VERSION @ISA @EXPORT); |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
221
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
BEGIN { |
7
|
2
|
|
|
2
|
|
10
|
require Exporter; |
8
|
2
|
|
|
|
|
35
|
@ISA = qw(Exporter); |
9
|
2
|
|
|
|
|
6
|
@EXPORT = qw(to_race from_race); |
10
|
|
|
|
|
|
|
|
11
|
2
|
|
|
|
|
30
|
$VERSION = '0.07'; |
12
|
|
|
|
|
|
|
} |
13
|
|
|
|
|
|
|
|
14
|
2
|
|
|
2
|
|
11
|
use Carp (); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
56
|
|
15
|
2
|
|
|
2
|
|
4106
|
use Convert::Base32 qw(encode_base32 decode_base32); |
|
2
|
|
|
|
|
9942
|
|
|
2
|
|
|
|
|
1554
|
|
16
|
|
|
|
|
|
|
|
17
|
2
|
|
|
2
|
|
23
|
use constant COMPRESS_EXCEPTION => 'Invalid encoding to compress'; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
456
|
|
18
|
2
|
|
|
2
|
|
12
|
use constant DECOMPRESS_EXCEPTION => 'Invalid format to decompress'; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
3118
|
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
my $_prefix_tag = 'bq--'; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
sub prefix_tag { |
23
|
0
|
|
|
0
|
1
|
0
|
my $class = shift; |
24
|
0
|
0
|
|
|
|
0
|
$_prefix_tag = $_[0] if (@_); |
25
|
0
|
|
|
|
|
0
|
return $_prefix_tag; |
26
|
|
|
|
|
|
|
} |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
sub to_race($) { |
29
|
9
|
|
|
9
|
1
|
377
|
my $str = shift; |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# 2.2.1 Check the input string for disallowed names |
32
|
9
|
50
|
|
|
|
20
|
unless (_include_disallowed_names($str)) { |
33
|
0
|
|
|
|
|
0
|
Carp::croak('String includes no internationalized characters'); |
34
|
|
|
|
|
|
|
} |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
# 2.2.2 Compress the pre-converted string |
37
|
9
|
|
|
|
|
22
|
my $compressed = _compress($str); |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
# 2.2.3 Check the length of the compressed string |
40
|
9
|
50
|
|
|
|
26
|
if (length($compressed) > 36) { |
41
|
0
|
|
|
|
|
0
|
Carp::croak('String too long'); |
42
|
|
|
|
|
|
|
} |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
# 2.2.4 Encode the compressed string with Base32 |
45
|
9
|
|
|
|
|
29
|
my $encoded = encode_base32($compressed); |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
# 2.2.5 Prepend "bq--" to the encoded string and finish |
48
|
9
|
|
|
|
|
3110
|
return $_prefix_tag . $encoded; |
49
|
|
|
|
|
|
|
} |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
sub from_race($) { |
52
|
9
|
|
|
9
|
1
|
18
|
my $str = lc(shift); |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# 2.3.1 Strip the "bq--" |
55
|
9
|
50
|
|
|
|
78
|
$str =~ s/^$_prefix_tag// or Carp::croak("String not begin with $_prefix_tag"); |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
# 2.3.2 Decode the stripped string with Base32 |
58
|
9
|
|
|
|
|
28
|
my $decoded = decode_base32($str); |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
# 2.3.3 Decompress the decoded string |
61
|
9
|
|
|
|
|
489
|
my $decompressed = _decompress($decoded); |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
# 2.3.4 Check the internationalized string for disallowed names |
64
|
9
|
50
|
|
|
|
22
|
unless (_include_disallowed_names($decompressed)) { |
65
|
0
|
|
|
|
|
0
|
Carp::croak('Decoded string includes no internationalized characters'); |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
|
68
|
9
|
|
|
|
|
40
|
return $decompressed; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
sub _compress($) { |
73
|
9
|
|
|
9
|
|
12
|
my $str = shift; |
74
|
|
|
|
|
|
|
|
75
|
9
|
|
|
|
|
18
|
my @unique_upper_octet = _make_uniq_upper_octet($str); |
76
|
9
|
100
|
100
|
|
|
50
|
if (@unique_upper_octet > 2 || |
|
6
|
|
66
|
|
|
22
|
|
77
|
|
|
|
|
|
|
(@unique_upper_octet == 2 && |
78
|
|
|
|
|
|
|
! grep { $_ eq "\x00" } @unique_upper_octet)) { |
79
|
|
|
|
|
|
|
# from more than 2 rows |
80
|
|
|
|
|
|
|
# or from 2 rows neither of with is 0 |
81
|
2
|
|
|
|
|
177
|
return "\xD8" . $str; |
82
|
|
|
|
|
|
|
} |
83
|
|
|
|
|
|
|
|
84
|
4
|
|
|
|
|
11
|
my $u1 = @unique_upper_octet == 1 |
85
|
7
|
100
|
|
|
|
19
|
? $unique_upper_octet[0] : (grep { $_ ne "\x00" } @unique_upper_octet)[0]; |
86
|
7
|
50
|
|
|
|
23
|
if ($u1 =~ /^[\xd8-\xdc]{1}$/) { |
87
|
0
|
|
|
|
|
0
|
Carp::croak(COMPRESS_EXCEPTION); |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
7
|
|
|
|
|
9
|
my $res = $u1; |
91
|
|
|
|
|
|
|
|
92
|
7
|
|
|
|
|
27
|
while ($str =~ m/(.)(.)/gs) { |
93
|
23
|
|
|
|
|
126
|
my ($u2, $n1) = ($1, $2); |
94
|
23
|
50
|
66
|
|
|
379
|
if ($u2 eq "\x00" and $n1 eq "\x99") { |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
95
|
0
|
|
|
|
|
0
|
Carp::croak(COMPRESS_EXCEPTION); |
96
|
|
|
|
|
|
|
} elsif ($u2 eq $u1 and $n1 ne "\xff") { |
97
|
20
|
|
|
|
|
74
|
$res .= $n1; |
98
|
|
|
|
|
|
|
} elsif ($u2 eq $u1 and $n1 eq "\xff") { |
99
|
1
|
|
|
|
|
5
|
$res .= "\xff\x99"; |
100
|
|
|
|
|
|
|
} else { |
101
|
2
|
|
|
|
|
10
|
$res .= "\xff$n1"; |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
|
105
|
7
|
|
|
|
|
105
|
return $res; |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub _decompress($) { |
110
|
9
|
|
|
9
|
|
12
|
my $str = shift; |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
# 1) |
113
|
9
|
|
|
|
|
22
|
my ($u1, $rest) = (substr($str,0,1), substr($str,1)); |
114
|
9
|
50
|
|
|
|
23
|
if (length($str) == 1) { |
115
|
0
|
|
|
|
|
0
|
Carp::croak(DECOMPRESS_EXCEPTION); |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
|
118
|
9
|
100
|
|
|
|
18
|
if ($u1 eq "\xd8") { |
119
|
|
|
|
|
|
|
# 8) |
120
|
2
|
|
|
|
|
4
|
my $lcheck = $rest; |
121
|
2
|
50
|
|
|
|
7
|
if (length($lcheck) % 2) { |
122
|
0
|
|
|
|
|
0
|
Carp::croak(DECOMPRESS_EXCEPTION); |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
# 9) |
125
|
2
|
|
|
|
|
4
|
my @unique_upper_octet = _make_uniq_upper_octet($lcheck); |
126
|
2
|
50
|
66
|
|
|
24
|
if (@unique_upper_octet == 1 || |
|
2
|
|
33
|
|
|
7
|
|
127
|
|
|
|
|
|
|
(@unique_upper_octet == 2 && |
128
|
|
|
|
|
|
|
grep { $_ eq "\x00" } @unique_upper_octet)) { |
129
|
0
|
|
|
|
|
0
|
Carp::croak(DECOMPRESS_EXCEPTION); |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
# 10) |
132
|
2
|
|
|
|
|
7
|
return $lcheck; |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
7
|
|
|
|
|
9
|
my $buffer = ''; |
136
|
7
|
|
|
|
|
10
|
my $pos = 0; |
137
|
|
|
|
|
|
|
# 2) |
138
|
7
|
|
|
|
|
29
|
while (1) { |
139
|
30
|
100
|
|
|
|
59
|
if ($pos == length($rest)) { |
140
|
|
|
|
|
|
|
# 11) |
141
|
7
|
50
|
|
|
|
18
|
if (length($buffer) % 2) { |
142
|
0
|
|
|
|
|
0
|
Carp::croak(DECOMPRESS_EXCEPTION); |
143
|
|
|
|
|
|
|
} |
144
|
7
|
|
|
|
|
17
|
return $buffer; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
|
147
|
23
|
|
|
|
|
34
|
my $n1 = substr($rest, $pos, 1); |
148
|
23
|
100
|
66
|
|
|
224
|
if ($n1 eq "\xff") { |
|
|
50
|
|
|
|
|
|
149
|
|
|
|
|
|
|
# 5) |
150
|
3
|
50
|
|
|
|
8
|
if ($pos == length($rest)-1) { |
151
|
0
|
|
|
|
|
0
|
Carp::croak(DECOMPRESS_EXCEPTION); |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
# 6) |
154
|
3
|
|
|
|
|
5
|
$pos++; |
155
|
3
|
|
|
|
|
5
|
$n1 = substr($rest, $pos, 1); |
156
|
3
|
100
|
|
|
|
7
|
if ($n1 eq "\x99") { |
157
|
1
|
|
|
|
|
3
|
$buffer .= $u1 . "\xff"; |
158
|
1
|
|
|
|
|
84
|
next; |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
# 7) |
161
|
2
|
|
|
|
|
4
|
$buffer .= "\x00" . $n1; |
162
|
2
|
|
|
|
|
4
|
next; |
163
|
|
|
|
|
|
|
} elsif ($u1 eq "\x00" and $n1 eq "\x99") { |
164
|
|
|
|
|
|
|
# 3) |
165
|
0
|
|
|
|
|
0
|
Carp::croak(DECOMPRESS_EXCEPTION); |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
# 4) |
168
|
20
|
|
|
|
|
28
|
$buffer .= $u1 . $n1; |
169
|
20
|
|
|
|
|
24
|
next; |
170
|
23
|
|
|
|
|
26
|
} continue { $pos++; } |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
sub _make_uniq_upper_octet($) { |
175
|
11
|
|
|
11
|
|
15
|
my $str = shift; |
176
|
|
|
|
|
|
|
|
177
|
11
|
|
|
|
|
13
|
my %seen; |
178
|
11
|
|
|
|
|
40
|
while ($str =~ m/(.)./gs) { |
179
|
39
|
|
|
|
|
226
|
$seen{$1}++; |
180
|
|
|
|
|
|
|
} |
181
|
11
|
|
|
|
|
47
|
return keys %seen; |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
sub _include_disallowed_names($) { |
185
|
|
|
|
|
|
|
# RFC 1035: letter, digit, hyphen |
186
|
18
|
|
|
18
|
|
92
|
return $_[0] !~ /^(?:\x00[\x30-\x39\x41-\x5a\x61-\x7a\x2d])*$/; |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
1; |
191
|
|
|
|
|
|
|
__END__ |