File Coverage

blib/lib/Encode/MIME/EncWords.pm
Criterion Covered Total %
statement 69 110 62.7
branch 28 78 35.9
condition 10 13 76.9
subroutine 8 10 80.0
pod 5 5 100.0
total 120 216 55.5


line stmt bran cond sub pod time code
1             # -*- perl -*-
2              
3             package Encode::MIME::EncWords;
4             require 5.007003;
5              
6 2     2   16177 use strict;
  2         4  
  2         72  
7 2     2   9 use warnings;
  2         3  
  2         78  
8 2     2   10 use Carp qw(croak carp);
  2         3  
  2         144  
9 2     2   925 use MIME::EncWords;
  2         19  
  2         243  
10              
11             our $VERSION = '0.03';
12              
13             # Default of options
14             my $Config = {
15             Charset => 'UTF-8',
16             # Encoding => specified by each subclass.
17             # Folding => fixes to "\n".
18             # Replacement => given by encode()/decode().
19             # others => derived from MIME::EncWords:
20             map { ($_ => $MIME::EncWords::Config->{$_}) }
21             qw(Detect7bit Field Mapping MaxLineLen Minimal)
22             };
23              
24             $Encode::Encoding{'MIME-EncWords'} = bless {
25             Encoding => 'A',
26             Name => 'MIME-EncWords',
27             } => __PACKAGE__;
28              
29             $Encode::Encoding{'MIME-EncWords-B'} = bless {
30             Encoding => 'B',
31             Name => 'MIME-EncWords-B',
32             } => __PACKAGE__;
33              
34             $Encode::Encoding{'MIME-EncWords-Q'} = bless {
35             Encoding => 'Q',
36             Name => 'MIME-EncWords-Q',
37             } => __PACKAGE__;
38              
39             $Encode::Encoding{'MIME-EncWords-ISO_2022_JP'} = bless {
40             Charset => 'ISO-2022-JP',
41             Encoding => 'B',
42             Name => 'MIME-EncWords-ISO_2022_JP',
43             } => __PACKAGE__;
44              
45 2     2   15 use base qw(Encode::Encoding);
  2         8  
  2         1957  
46              
47 0     0 1 0 sub needs_lines { 1 }
48 0     0 1 0 sub perlio_ok { 0 }
49              
50             sub decode($$;$) {
51 11     11 1 2034 my ($obj, $str, $chk) = @_;
52              
53 11   33     20 my %opts = map { ($_ => ($obj->{$_} || $Config->{$_})) }
  22         113  
54             qw(Detect7bit Mapping);
55 11 50       22 $chk = 0 if ref $chk; # coderef not supported.
56 11 50       25 my $repl = ($chk & 4) ? ($chk & ~4 | 1) : $chk;
57              
58 11         12 local $@;
59 11         11 my $skip = 0; # for RETURN_ON_ERR
60 11         9 my $ret = undef;
61 11         20 pos($str) = 0;
62 11         228 foreach my $line (
63             $str =~ m{ \G (.*?) (?:\r\n|[\r\n]) (?![ \t]) }cgsx,
64             substr($str, pos($str))
65             ) {
66 32 100       55 if (defined $ret) {
67 21 50       49 $ret .= "\n" unless $skip;
68             } else {
69 11         14 $ret = '';
70             }
71 32 50       55 if ($skip) {
72 0         0 $_[1] .= "\n";
73 0         0 $_[1] .= $line;
74 0         0 next;
75             }
76 32 100       63 next unless length $line;
77              
78 24         74 my @words = MIME::EncWords::decode_mimewords($line, %opts);
79 24 50       49 if ($@) { # broken MIME encoding.
80 0 0       0 croak $@ if $chk & 1; # DIE_ON_ERR
81 0 0       0 carp $@ if $chk & 2; # WARN_ON_ERR
82 0 0       0 if ($chk & 4) { # RETURN_ON_ERR
83 0         0 $_[1] = $line;
84 0         0 $skip = 1;
85 0         0 next;
86             }
87             }
88 24         56 for (my $i = 0; $i <= $#words; $i++) {
89 58         52 my $word = $words[$i];
90 58   100     208 my $cset = MIME::Charset->new(($word->[1] || 'US-ASCII'),
91             Mapping => $opts{Mapping});
92 58 50       5287 if (! $cset->decoder) { # unknown charset or ``8BIT''.
93 0         0 $@ = 'Unknown charset "'.$cset->as_string.'"';
94 0 0       0 croak $@ if $chk & 1;
95 0 0       0 carp $@ if $chk & 2;
96 0 0       0 if ($chk & 4) {
97             # already decoded... re-encoding
98 0         0 $_[1] =
99             MIME::EncWords::encode_mimewords([splice @words, $i],
100             Encoding => 'B',
101             Folding => '',
102             MaxLineLen => -1);
103 0         0 $skip = 1;
104 0         0 last;
105             }
106 0         0 $ret .= Encode::decode("ISO-8859-1", $word->[0], 0); #FIXME
107              
108 0         0 next;
109             }
110 58         207 eval {
111 58         109 $ret .= $cset->decode($word->[0], $repl);
112             };
113 58 50       748 if ($@) {
114 0         0 $@ =~ s/ at .+? line \d+[.\n]*$//;
115 0 0       0 croak $@ if $chk & 1;
116 0 0       0 carp $@ if $chk & 2;
117 0 0       0 if ($chk & 4) {
118             # already decoded... re-encoding
119 0         0 $_[1] =
120             MIME::EncWords::encode_mimewords([splice @words, $i],
121             Encoding => 'B',
122             Folding => '',
123             MaxLineLen => -1);
124 0         0 $skip = 1;
125 0         0 last;
126             }
127             }
128             }
129             }
130              
131 11 50       44 if ($chk & 4) { # RETURN_ON_ERR
    50          
132 0 0       0 $_[1] = '' unless $skip;
133             } elsif ($chk) { # ! LEAVE_SRC
134 0 0       0 $_[1] = $ret unless $chk & 8;
135             }
136 11         34 return $ret;
137             }
138              
139             sub encode($$;$) {
140 18     18 1 16286 my ($obj, $str, $chk) = @_;
141              
142 18   100     32 my %opts = map { ($_ => ($obj->{$_} || $Config->{$_})) }
  126         433  
143             qw(Charset Detect7bit Encoding Field Mapping MaxLineLen Minimal);
144 18   50     48 $opts{Charset} ||= 'UTF-8';
145 18         28 $opts{Folding} = "\n";
146 18 50       36 $chk = 0 if ref $chk; # coderef not supported.
147 18 50       32 my $repl = ($chk & 4) ? ($chk & ~4 | 1) : $chk;
148              
149 18 100 100     87 $str = Encode::decode('ISO-8859-1', $str)
150             if ! Encode::is_utf8($str) and $str =~ /[^\x00-\x7F]/;
151              
152 18         39 local $@;
153 18         15 my $skip = 0; # for RETURN_ON_ERR
154 18         17 my $ret = undef;
155 18         56 pos($str) = 0;
156 18         160 foreach my $line (
157             $str =~ m{ \G (.*?) (?:\r\n|[\r\n]) (?![ \t]) }cgsx,
158             substr($str, pos($str))
159             ) {
160 27 100       44 if (defined $ret) {
161 9 50       19 $ret .= "\n" unless $skip;
162             } else {
163 18         23 $ret = '';
164             }
165 27 50       45 if ($skip) {
166 0         0 $_[1] .= "\n";
167 0         0 $_[1] .= $line;
168 0         0 next;
169             }
170 27 100       100 next unless length $line;
171              
172 22         26 eval {
173 22         99 $ret .= MIME::EncWords::encode_mimewords($line, %opts,
174             Replacement => $repl);
175             };
176 22 50       61 if ($@) {
177 0         0 $@ =~ s/ at .+? line \d+[.\n]*$//;
178 0 0       0 croak $@ if $chk & 1; # DIE_ON_ERR
179 0 0       0 carp $@ if $chk & 2; # WARN_ON_ERR
180 0 0       0 if ($chk & 4) { # RETURN_ON_ERR
181 0         0 $_[1] = $line;
182 0         0 $skip = 1;
183 0         0 next;
184             }
185             }
186             }
187              
188 18 50       56 if ($chk & 4) { # RETURN_ON_ERR
    50          
189 0 0       0 $_[1] = '' unless $skip;
190             } elsif ($chk) { # ! LEAVE_SRC
191 0 0       0 $_[1] = '' unless $chk & 8; # FIXME:spec?
192             }
193 18         67 return $ret;
194             }
195              
196             sub config {
197 2 50   2 1 627 my $klass = shift if scalar @_ % 2;
198 2         5 my %opts = @_;
199 2         5 foreach my $key (keys %opts) {
200 2 50       5 croak "Unknown config option: $key" unless exists $Config->{$key};
201 2         7 $Config->{$key} = $opts{$key};
202             }
203             }
204              
205             1;
206             __END__