Completed
Push — master ( 42b3e6...c7cf7f )
by Zaahid
02:29
created

UUEncodeStreamFilter::filterLine()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 10
rs 8.8571
cc 5
eloc 7
nc 3
nop 1
1
<?php
2
/**
3
 * This file is part of the ZBateson\MailMimeParser project.
4
 *
5
 * @license http://opensource.org/licenses/bsd-license.php BSD
6
 */
7
namespace ZBateson\MailMimeParser;
8
9
use php_user_filter;
10
11
/**
12
 * Stream filter converts uuencoded text to its raw binary.
13
 *
14
 * @author Zaahid Bateson
15
 */
16
class UUEncodeStreamFilter extends php_user_filter
17
{
18
    /**
19
     * Name used when registering with stream_filter_register.
20
     */
21
    const STREAM_FILTER_NAME = 'mailmimeparser-uudecode';
22
    
23
    /**
24
     * @var string Leftovers from the last incomplete line that was parsed, to
25
     *      be prepended to the next line read.
26
     */
27
    private $leftover = '';
28
    
29
    /**
30
     * Returns an array of complete lines (including line endings) from the 
31
     * passed $bucket object.
32
     * 
33
     * If the last line on $bucket is incomplete, it's assigned to
34
     * $this->leftover and prepended to the first element of the first line in
35
     * the next call to getLines.
36
     * 
37
     * @param object $bucket
38
     * @return string[]
39
     */
40
    private function getLines($bucket)
41
    {
42
        $lines = preg_split(
43
            '/([^\r\n]+[\r\n]+)/',
44
            $bucket->data,
45
            -1,
46
            PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY
47
        );
48
        if (!empty($this->leftover)) {
49
            $lines[0] = $this->leftover . $lines[0];
50
            $this->leftover = '';
51
        }
52
        $last = end($lines);
53
        if ($last[strlen($last) - 1] !== "\n") {
54
            $this->leftover = array_pop($lines);
55
        }
56
        return $lines;
57
    }
58
    
59
    /**
60
     * Filters a single line of encoded input.  Returns NULL if the end has been
61
     * reached.
62
     * 
63
     * @param string $line
64
     * @return string the decoded line
65
     */
66
    private function filterLine($line)
67
    {
68
        $cur = trim($line);
69
        if (empty($cur) || preg_match('/^begin \d{3} .*$/', $cur)) {
70
            return '';
71
        } elseif ($cur === '`' || $cur === 'end') {
72
            return null;
73
        }
74
        return convert_uudecode($cur);
75
    }
76
    
77
    /**
78
     * Filters the lines in the passed $lines array, returning a concatenated
79
     * string of decoded lines.
80
     * 
81
     * @param array $lines
82
     * @param int $consumed
83
     * @return string
84
     */
85
    private function filterBucketLines(array $lines, &$consumed)
86
    {
87
        $data = '';
88
        foreach ($lines as $line) {
89
            $consumed += strlen($line);
90
            $filtered = $this->filterLine($line);
91
            if ($filtered === null) {
92
                break;
93
            }
94
            $data .= $filtered;
95
        }
96
        return $data;
97
    }
98
    
99
    /**
100
     * Filter implementation converts encoding before returning PSFS_PASS_ON.
101
     * 
102
     * @param resource $in
103
     * @param resource $out
104
     * @param int $consumed
105
     * @param bool $closing
106
     * @return int
107
     */
108
    public function filter($in, $out, &$consumed, $closing)
109
    {
110
        while ($bucket = stream_bucket_make_writeable($in)) {
111
            $lines = $this->getLines($bucket);
112
            $bucket->data = $this->filterBucketLines($lines, $consumed);
113
            stream_bucket_append($out, $bucket);
114
        }
115
        return PSFS_PASS_ON;
116
    }
117
}
118