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   64801 use strict;
  2         5  
  2         96  
7 2     2   84 use warnings;
  2         5  
  2         80  
8 2     2   119 use Carp qw(croak carp);
  2         6  
  2         199  
9 2     2   2448 use MIME::EncWords;
  2         223  
  2         364  
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   22 use base qw(Encode::Encoding);
  2         4  
  2         3618  
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 3577 my ($obj, $str, $chk) = @_;
52              
53 11   33     180 my %opts = map { ($_ => ($obj->{$_} || $Config->{$_})) }
  22         166  
54             qw(Detect7bit Mapping);
55 11 50       45 $chk = 0 if ref $chk; # coderef not supported.
56 11 50       36 my $repl = ($chk & 4) ? ($chk & ~4 | 1) : $chk;
57              
58 11         12 local $@;
59 11         17 my $skip = 0; # for RETURN_ON_ERR
60 11         16 my $ret = undef;
61 11         32 pos($str) = 0;
62 11         515 foreach my $line (
63             $str =~ m{ \G (.*?) (?:\r\n|[\r\n]) (?![ \t]) }cgsx,
64             substr($str, pos($str))
65             ) {
66 32 100       75 if (defined $ret) {
67 21 50       70 $ret .= "\n" unless $skip;
68             } else {
69 11         22 $ret = '';
70             }
71 32 50       81 if ($skip) {
72 0         0 $_[1] .= "\n";
73 0         0 $_[1] .= $line;
74 0         0 next;
75             }
76 32 100       91 next unless length $line;
77              
78 24         110 my @words = MIME::EncWords::decode_mimewords($line, %opts);
79 24 50       80 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         65 for (my $i = 0; $i <= $#words; $i++) {
89 58         82 my $word = $words[$i];
90 58   100     829 my $cset = MIME::Charset->new(($word->[1] || 'US-ASCII'),
91             Mapping => $opts{Mapping});
92 58 50       11004 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         772 eval {
111 58         171 $ret .= $cset->decode($word->[0], $repl);
112             };
113 58 50       1585 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       115 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         53 return $ret;
137             }
138              
139             sub encode($$;$) {
140 18     18 1 56991 my ($obj, $str, $chk) = @_;
141              
142 18   100     47 my %opts = map { ($_ => ($obj->{$_} || $Config->{$_})) }
  126         838  
143             qw(Charset Detect7bit Encoding Field Mapping MaxLineLen Minimal);
144 18   50     81 $opts{Charset} ||= 'UTF-8';
145 18         48 $opts{Folding} = "\n";
146 18 50       59 $chk = 0 if ref $chk; # coderef not supported.
147 18 50       56 my $repl = ($chk & 4) ? ($chk & ~4 | 1) : $chk;
148              
149 18 100 100     123 $str = Encode::decode('ISO-8859-1', $str)
150             if ! Encode::is_utf8($str) and $str =~ /[^\x00-\x7F]/;
151              
152 18         52 local $@;
153 18         25 my $skip = 0; # for RETURN_ON_ERR
154 18         26 my $ret = undef;
155 18         76 pos($str) = 0;
156 18         232 foreach my $line (
157             $str =~ m{ \G (.*?) (?:\r\n|[\r\n]) (?![ \t]) }cgsx,
158             substr($str, pos($str))
159             ) {
160 27 100       64 if (defined $ret) {
161 9 50       29 $ret .= "\n" unless $skip;
162             } else {
163 18         36 $ret = '';
164             }
165 27 50       240 if ($skip) {
166 0         0 $_[1] .= "\n";
167 0         0 $_[1] .= $line;
168 0         0 next;
169             }
170 27 100       205 next unless length $line;
171              
172 22         35 eval {
173 22         413 $ret .= MIME::EncWords::encode_mimewords($line, %opts,
174             Replacement => $repl);
175             };
176 22 50       101 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       88 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         128 return $ret;
194             }
195              
196             sub config {
197 2 50   2 1 1892 my $klass = shift if scalar @_ % 2;
198 2         7 my %opts = @_;
199 2         6 foreach my $key (keys %opts) {
200 2 50       8 croak "Unknown config option: $key" unless exists $Config->{$key};
201 2         10 $Config->{$key} = $opts{$key};
202             }
203             }
204              
205             1;
206             __END__