File Coverage

lib/Encode/Unicode/UTF7.pm
Criterion Covered Total %
statement 53 60 88.3
branch 12 22 54.5
condition n/a
subroutine 10 11 90.9
total 75 93 80.6


line stmt bran cond sub time code
1           #
2           # $Id: UTF7.pm,v 2.7 2013/04/26 18:30:46 dankogai Exp $
3           #
4           package Encode::Unicode::UTF7;
5 2     2 592509 use strict;
  2       8  
  2       103  
6 2     2 11 use warnings;
  2       5  
  2       91  
7 2     2 12 no warnings 'redefine';
  2       3  
  2       104  
8 2     2 11 use base qw(Encode::Encoding);
  2       5  
  2       183  
9           __PACKAGE__->Define('UTF-7');
10           our $VERSION = do { my @r = ( q$Revision: 2.7 $ =~ /\d+/g ); sprintf "%d." . "%02d" x $#r, @r };
11 2     2 981 use MIME::Base64;
  2       1663  
  2       180  
12 2     2 12 use Encode;
  2       5  
  2       1279  
13            
14           #
15           # Algorithms taken from Unicode::String by Gisle Aas
16           #
17            
18           our $OPTIONAL_DIRECT_CHARS = 1;
19           my $specials = quotemeta "\'(),-./:?";
20           $OPTIONAL_DIRECT_CHARS
21           and $specials .= quotemeta "!\"#$%&*;<=>@[]^_`{|}";
22            
23           # \s will not work because it matches U+3000 DEOGRAPHIC SPACE
24           # We use qr/[\n\r\t\ ] instead
25           my $re_asis = qr/(?:[\n\r\t\ A-Za-z0-9$specials])/;
26           my $re_encoded = qr/(?:[^\n\r\t\ A-Za-z0-9$specials])/;
27           my $e_utf16 = find_encoding("UTF-16BE");
28            
29 0     0 0 sub needs_lines { 1 }
30            
31           sub encode($$;$) {
32 7     7 6109 my ( $obj, $str, $chk ) = @_;
33 7       447 my $len = length($str);
34 7       28 pos($str) = 0;
35 7       29 my $bytes = substr($str, 0, 0); # to propagate taintedness
36 7       30 while ( pos($str) < $len ) {
37 4207 100     24113 if ( $str =~ /\G($re_asis+)/ogc ) {
    50        
38 2107       5232 my $octets = $1;
39 2107       4746 utf8::downgrade($octets);
40 2107       8908 $bytes .= $octets;
41           }
42           elsif ( $str =~ /\G($re_encoded+)/ogsc ) {
43 2100 50     6463 if ( $1 eq "+" ) {
44 0       0 $bytes .= "+-";
45           }
46           else {
47 2100       4598 my $s = $1;
48 2100       16585 my $base64 = encode_base64( $e_utf16->encode($s), '' );
49 2100       8727 $base64 =~ s/=+$//;
50 2100       11475 $bytes .= "+$base64-";
51           }
52           }
53           else {
54 0       0 die "This should not happen! (pos=" . pos($str) . ")";
55           }
56           }
57 7 50     25 $_[1] = '' if $chk;
58 7       44 return $bytes;
59           }
60            
61           sub decode($$;$) {
62 2     2 13 use re 'taint';
  2       4  
  2       209  
63 7     7 740 my ( $obj, $bytes, $chk ) = @_;
64 7       929 my $len = length($bytes);
65 7       21 my $str = substr($bytes, 0, 0); # to propagate taintedness;
66 7       26 pos($bytes) = 0;
67 2     2 11 no warnings 'uninitialized';
  2       5  
  2       696  
68 7       29 while ( pos($bytes) < $len ) {
69 4207 100     90216 if ( $bytes =~ /\G([^+]+)/ogc ) {
    50        
    50        
    0        
70 2107       8477 $str .= $1;
71           }
72           elsif ( $bytes =~ /\G\+-/ogc ) {
73 0       0 $str .= "+";
74           }
75           elsif ( $bytes =~ /\G\+([A-Za-z0-9+\/]+)-?/ogsc ) {
76 2100       5056 my $base64 = $1;
77 2100       5516 my $pad = length($base64) % 4;
78 2100 100     7653 $base64 .= "=" x ( 4 - $pad ) if $pad;
79 2100       21397 $str .= $e_utf16->decode( decode_base64($base64) );
80           }
81           elsif ( $bytes =~ /\G\+/ogc ) {
82 0 0     0 $^W and warn "Bad UTF7 data escape";
83 0       0 $str .= "+";
84           }
85           else {
86 0       0 die "This should not happen " . pos($bytes);
87           }
88           }
89 7 50     20 $_[1] = '' if $chk;
90 7       62 return $str;
91           }
92           1;
93           __END__