File Coverage

blib/lib/Encode/Escape/Unicode.pm
Criterion Covered Total %
statement 27 86 31.4
branch 4 34 11.7
condition 0 6 0.0
subroutine 8 21 38.1
pod 2 15 13.3
total 41 162 25.3


line stmt bran cond sub pod time code
1             # Encoding of Unicode Escape Sequences (or Escaped Unicode)
2              
3             # $Id: Unicode.pm,v 1.13 2007-12-05 22:11:11+09 you Exp $
4              
5             package Encode::Escape::Unicode;
6              
7             our $VERSION = do { q$Revision: 1.13 $ =~ /\d+\.(\d+)/; sprintf "%.2f", $1 / 100 };
8              
9 1     1   26166 use 5.008008;
  1         4  
  1         43  
10 1     1   5 use strict;
  1         3  
  1         44  
11 1     1   6 use warnings;
  1         2  
  1         28  
12              
13 1     1   954 use Encode::Encoding;
  1         12738  
  1         42  
14 1     1   9 use base qw(Encode::Encoding);
  1         2  
  1         1828  
15              
16             __PACKAGE__->Define(qw/unicode-escape unicode_escape/);
17              
18             sub import {
19              
20 1     1   21 __PACKAGE__->enmode('default');
21 1         3 __PACKAGE__->demode('default');
22              
23 1         7 require Encode;
24 1         39 Encode->export_to_level(1, @_);
25             }
26              
27             our $enmode;
28             our $demode;
29             sub encoder($);
30             sub decoder($);
31              
32             #
33             # == encoder/decoder modes ==
34             #
35             our %encoder = (
36             undef => \&perl_encoder,
37             '' => \&perl_encoder,
38             default => \&perl_encoder,
39             perl => \&perl_encoder,
40             java => \&python_encoder,
41             python => \&python_encoder,
42             csharp => \&python_encoder,
43             );
44              
45             our %decoder = (
46             undef => \&perl_decoder,
47             '' => \&perl_decoder,
48             default => \&perl_decoder,
49             perl => \&perl_decoder,
50             java => \&python_decoder,
51             python => \&python_decoder,
52             csharp => \&python_decoder,
53             );
54              
55             #
56             # == encode/decode ==
57             #
58              
59             sub encode($$;$) {
60 0     0 1 0 my ($obj, $str, $chk) = @_;
61 0 0       0 $_[1] = '' if $chk;
62 0         0 return encoder $str;
63             }
64              
65              
66             sub decode($$;$) {
67 0     0 1 0 my ($obj, $str, $chk) = @_;
68 0 0       0 $_[1] = '' if $chk;
69 0         0 return decoder $str;
70             }
71              
72             #
73             # == enmode/demode ==
74             #
75              
76             sub enmode ($$) {
77 1     1 0 3 my ($class, $mode) = @_;
78 1 50       6 $mode = 'undef' unless defined $mode;
79 1 50       3 unless (exists $encoder{$mode}) {
80 0         0 require Carp;
81 0         0 Carp::croak(
82             "Unknown enmode '$mode' for encoding '" . $class->name() . "'"
83             );
84             }
85 1         2 $enmode = $mode;
86             }
87              
88             sub demode ($$) {
89 1     1 0 2 my ($class, $mode) = @_;
90 1 50       5 $mode = 'undef' unless defined $mode;
91 1 50       4 unless (exists $decoder{$mode}) {
92 0         0 require Carp;
93 0         0 Carp::croak(
94             "Unknown demode '$mode' for encoding '" . $class->name() . "'"
95             );
96             }
97 1         2 $demode = $mode;
98             }
99              
100              
101             #
102             # = DATA AND SUBROUTINES FOR INTERNAL USE =
103             #
104              
105              
106             #
107             # == encoder/decoder ==
108             #
109              
110             sub encoder($) {
111 0 0   0 0   local $_ = ( defined $_[0] ? $_[0] : '' );
112 0           return $encoder{$enmode}->($_);
113             }
114             sub decoder($) {
115 0 0   0 0   local $_ = ( defined $_[0] ? $_[0] : '' );
116 0           return $decoder{$demode}->($_);
117             }
118              
119             #
120             # == enmode_encoder / demode_decoder ==
121             #
122              
123             # default (perl) escape sequences
124             #
125             sub perl_encoder($) {
126              
127 0 0   0 0   local $_ = ( defined $_[0] ? $_[0] : '' );
128              
129 0           $_ = escape($_);
130 0           s/([\x00-\x1f\x{7f}-\x{ffff}])/"\\x\{".uc(chr2hex($1))."\}"/gse;
  0            
131              
132 0           return $_;
133             }
134              
135             sub perl_decoder($) {
136              
137 0 0   0 0   local $_ = ( defined $_[0] ? $_[0] : '' );
138              
139 0           s/((?:\A|\G|[^\\]))\\x([\da-fA-F]{1,2})/$1.hex2chr($2)/gse;
  0            
140 0           s/((?:\A|\G|[^\\]))\\x\{([\da-fA-F]{1,4})\}/$1.hex2chr($2)/gse;
  0            
141              
142 0           return unescape($_);
143             }
144              
145             # python (or java, c#) escape sequences
146             #
147             sub python_encoder($) {
148              
149 0 0   0 0   local $_ = ( defined $_[0] ? $_[0] : '' );
150              
151 0           $_ = escape($_);
152 0           s/([\x00-\x1f\x{7f}-\x{ffff}])/'\u'.chr2hex($1)/gse;
  0            
153              
154 0           return $_;
155             }
156              
157             sub python_decoder {
158              
159 0 0   0 0   local $_ = ( defined $_[0] ? $_[0] : '' );
160              
161 0           s/((?:\A|\G|[^\\]))\\u([\da-fA-F]{4})/$1.hex2chr($2)/gse;
  0            
162              
163 0           return unescape($_);
164             }
165              
166             #
167             # == common data and subroutines ==
168             #
169              
170             my %ESCAPED = (
171             "\\" => '\\',
172             "\r" => 'r',
173             "\n" => 'n',
174             "\t" => 't',
175             "\a" => 'a',
176             "\b" => 'b',
177             "\e" => 'e',
178             "\f" => 'f',
179             "\"" => '"',
180             "\$" => '$',
181             "\@" => '@',
182             );
183              
184             my %UNESCAPED = ( reverse %ESCAPED );
185              
186             sub escape ($) {
187 0 0   0 0   local $_ = ( defined $_[0] ? $_[0] : '' );
188 0           s/([\a\b\e\f\r\n\t\"\\\$\@])/\\$ESCAPED{$1}/sg;
189 0           return $_;
190             }
191              
192             sub unescape ($) {
193 0 0   0 0   local $_ = ( defined $_[0] ? $_[0] : '' );
194              
195 0           s/((?:\A|\G|[^\\]))\\([0-7]{1,3})/$1.oct2chr($2)/gse;
  0            
196              
197 0           s/((?:\A|\G|[^\\]))\\([^aAbBeEfFrRnNtT\\\"\$\@])/$1$2/g;
198              
199 0           s/((?:\A|\G|[^\\]))\\([aAbBeEfFrRnNtT\\\"\$\@])/$1.$UNESCAPED{lc($2)}/gse;
  0            
200              
201 0           return $_;
202             }
203              
204              
205              
206             sub chr2hex {
207 0     0 0   my($c) = @_;
208 0 0         if ( ord($c) < 65536 ) {
209 0           return sprintf("%04x", ord($c));
210             }
211             else {
212 0           require Carp;
213 0           Carp::croak (
214             "'unicode-escape' codec can't encode character: ordinal " . ord($c)
215             );
216             }
217             }
218              
219             sub hex2chr {
220 0     0 0   my($hex) = @_;
221 0 0 0       if ( hex($hex) >= 0 and hex($hex) < 65536) {
222 0           return chr(hex($hex));
223             }
224             else {
225 0           require Carp;
226 0           Carp::croak(
227             "'unicode-escape' codec can't decode escape sequence: "
228             . "\\x$hex (ordinal " . hex($hex) . ")"
229             );
230             }
231             }
232              
233             sub oct2chr {
234 0     0 0   my($oct) = @_;
235 0 0 0       if ( oct($oct) >= 0 and oct($oct) < 256 ) {
236 0           return chr(oct($oct));
237             }
238             else {
239 0           require Carp;
240 0           Carp::croak (
241             "'unicode-escape' codec can't decode escape sequence: "
242             . "\\$oct (ordinal " . oct($oct). ")"
243             );
244             }
245             }
246              
247             $\ = "\n";
248              
249              
250             1;
251             __END__