File Coverage

blib/lib/MIME/EcoEncode/Fold.pm
Criterion Covered Total %
statement 117 124 94.3
branch 51 62 82.2
condition 4 6 66.6
subroutine 6 6 100.0
pod 0 3 0.0
total 178 201 88.5


line stmt bran cond sub pod time code
1             # Copyright (C) 2013 MURATA Yasuhisa
2             # This program is free software; you can redistribute it and/or
3             # modify it under the same terms as Perl itself.
4              
5             package MIME::EcoEncode::Fold;
6              
7 1     1   27481 use 5.008005;
  1         5  
  1         43  
8 1     1   5 use strict;
  1         2  
  1         46  
9 1     1   5 use warnings;
  1         2  
  1         1875  
10              
11             require Exporter;
12              
13             our @ISA = qw(Exporter);
14             our @EXPORT_OK = qw($VERSION);
15             our @EXPORT = qw(mime_eco_fold);
16             our $VERSION = '0.95';
17              
18             our $LF; # line feed
19             our $BPL; # bytes per line
20             our $UTF8;
21             our $REG_W;
22              
23             our $SPL;
24              
25             sub mime_eco_fold {
26 13     13 0 13971 my $str = shift;
27              
28 13 100       38 return '' unless defined $str;
29 12 100       38 return '' if $str eq '';
30              
31 11   50     28 my $charset = shift || 'UTF-8';
32 11         12 my $cs;
33              
34 11 50       50 if ($charset =~ /^([-0-9A-Za-z_]+)$/i) {
35 11         27 $cs = lc($1);
36             }
37             else { # invalid option
38 0         0 return undef;
39             }
40              
41 11   100     39 our $LF = shift || "\n "; # line feed
42 11   50     22 our $BPL = shift || 990; # bytes per line
43 11         11 our $UTF8 = 1;
44 11         39 our $REG_W = qr/(.)/;
45              
46 11         42 $LF =~ /([^\x0d\x0a]*)$/;
47 11         18 our $SPL = length($1);
48              
49 11         15 my $jp = 0;
50              
51 11 100       25 if ($cs ne 'utf-8') {
52 4         6 $UTF8 = 0;
53 4 100       12 if ($cs eq 'iso-2022-jp') {
    50          
    0          
    0          
    0          
54 2         3 $jp = 1;
55             }
56             elsif ($cs eq 'shift_jis') {
57             # range of 2nd byte : [\x40-\x7e\x80-\xfc]
58 2         6 $REG_W = qr/([\x81-\x9f\xe0-\xfc]?.)/;
59             }
60             elsif ($cs eq 'gb2312') { # Simplified Chinese
61             # range of 2nd byte : [\xa1-\xfe]
62 0         0 $REG_W = qr/([\xa1-\xfe]?.)/;
63             }
64             elsif ($cs eq 'euc-kr') { # Korean
65             # range of 2nd byte : [\xa1-\xfe]
66 0         0 $REG_W = qr/([\xa1-\xfe]?.)/;
67             }
68             elsif ($cs eq 'big5') { # Traditional Chinese
69             # range of 2nd byte : [\x40-\x7e\xa1-\xfe]
70 0         0 $REG_W = qr/([\x81-\xfe]?.)/;
71             }
72             else { # Single Byte (Latin, Cyrillic, ...)
73             ;
74             }
75             }
76              
77 11         15 my $result = '';
78 11 100       26 my $refsub = $jp ? \&line_fold_jp : \&line_fold;
79 11         13 my $odd = 0;
80              
81 11         242 for my $line (split /(\x0d?\x0a|\x0d)/, $str) {
82 58 100       78 if ($odd) {
83 28         33 $result .= $line;
84 28         37 $odd = 0;
85             }
86             else {
87 30         68 $result .= &$refsub($line);
88 30         51 $odd = 1;
89             }
90             }
91 11         62 return $result;
92             }
93              
94              
95             sub line_fold {
96 22     22 0 24 my $str = shift;
97              
98 22 100       49 return '' if $str eq '';
99              
100 18         20 my $str_len = length($str);
101              
102 18         18 our $BPL;
103              
104 18 100       37 return $str if $str_len <= $BPL;
105              
106 13         14 our $LF;
107 13         12 our $UTF8;
108 13         12 our $REG_W;
109 13         11 our $SPL;
110              
111 13         17 my $w = '';
112 13         10 my $w_len;
113 13         14 my $w_bak = '';
114 13         13 my $result = '';
115 13         16 my $max_len = $BPL;
116              
117 13         38 my ($chunk, $chunk_len) = ('', 0);
118 13         17 my $str_pos = 0;
119              
120 13 100       37 utf8::decode($str) if $UTF8; # UTF8 flag on
121              
122 13         64 while ($str =~ /$REG_W/g) {
123 423         495 $w = $1;
124 423 100       716 utf8::encode($w) if $UTF8; # UTF8 flag off
125 423         349 $w_len = length($w); # size of one character
126 423 100       576 if ($chunk_len + $w_len > $max_len) {
127 17         23 $result .= $chunk . "$LF";
128 17         18 $str_pos += $chunk_len;
129 17         19 $max_len = $BPL - $w_len - $SPL;
130 17 100       30 if ($str_len - $str_pos <= $max_len) {
131 13 100       29 utf8::encode($str) if $UTF8; # UTF8 flag off
132 13         18 $chunk = substr($str, $str_pos);
133 13         19 last;
134             }
135 4         13 $chunk = $w;
136 4         15 $chunk_len = $w_len;
137             }
138             else {
139 406         349 $chunk .= $w;
140 406         1389 $chunk_len += $w_len;
141             }
142             }
143 13         38 return $result . $chunk;
144             }
145              
146              
147             sub line_fold_jp {
148 8     8 0 11 my $str = shift;
149              
150 8 100       17 return '' if $str eq '';
151              
152 6         6 our $BPL;
153              
154 6 50       11 return $str if length($str) <= $BPL;
155              
156 6         4 our $LF;
157 6         5 our $SPL;
158              
159 6         6 my $k_in = 0; # ascii: 0, zen: 1 or 2, han: 9
160 6         6 my $k_in_bak = -1;
161 6         5 my $k_out;
162             my $ec;
163 0         0 my $w1;
164 6         6 my $w1_bak = '';
165 6         6 my $w = '';
166 6         5 my $w_len;
167 6         6 my $w_bak = '';
168 6         7 my $result = '';
169 6         4 my $max_len = $BPL;
170              
171 6         19 while ($str =~ /(\e(..)|.)/g) {
172 225         301 ($w1, $ec) = ($1, $2);
173 225         194 $w .= $w1;
174 225 100       267 if (defined $ec) {
175 20         22 $w1_bak = $w1;
176 20 100       48 if ($ec eq '(B') {
    100          
177 8         7 $k_in = 0;
178             }
179             elsif ($ec eq '$B') {
180 8         8 $k_in = 1;
181             }
182             else {
183 4         5 $k_in = 9;
184             }
185 20         45 next;
186             }
187             else {
188 205 100       400 if ($k_in == 1) {
    100          
189 21         16 $k_in = 2;
190 21         47 next;
191             }
192             elsif ($k_in == 2) {
193 21         19 $k_in = 1;
194             }
195             }
196 184 100       236 $k_out = $k_in ? 3 : 0; # 3 is "\e\(B"
197 184 100       294 if (pos($str) + $k_out > $max_len) {
198 10         10 $w_len = length($w);
199 10 100       13 if ($k_in_bak) {
200 4         12 $result .= $w_bak .
201             substr($str, 0, pos($str) - $w_len, "") . "\e\(B$LF";
202 4 50       8 if ($k_in) {
203 4 50       5 if ($k_in_bak == $k_in) {
204 4         8 $w = $w1_bak . $w;
205             }
206             }
207             else {
208 0         0 $w = $w1;
209             }
210             }
211             else {
212 6         20 $result .= $w_bak .
213             substr($str, 0, pos($str) - $w_len, "") . "$LF";
214             }
215 10         13 substr($str, 0, $w_len, "");
216 10         11 $max_len = $BPL - length($w) - $SPL;
217 10 100       27 if (length($str) <= $max_len) {
218 6         19 return $result . $w . $str;
219             }
220 4         5 $w_bak = $w;
221             }
222 178         151 $k_in_bak = $k_in;
223 178         488 $w = '';
224             }
225 0           return $result . $w_bak . $str; # impossible
226             }
227              
228             1;