Passed
Push — master ( be291e...71d0f2 )
by Zaahid
03:55
created

CharsetStream   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 158
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 37
dl 0
loc 158
ccs 40
cts 40
cp 1
rs 10
c 0
b 0
f 0
wmc 15

9 Methods

Rating   Name   Duplication   Size   Complexity  
A eof() 0 3 2
A tell() 0 3 1
A __construct() 0 6 1
A read() 0 15 3
A seek() 0 3 1
A getSize() 0 3 1
A readRawCharsIntoBuffer() 0 10 4
A isSeekable() 0 3 1
A write() 0 6 1
1
<?php
2
/**
3
 * This file is part of the ZBateson\StreamDecorator project.
4
 *
5
 * @license http://opensource.org/licenses/bsd-license.php BSD
6
 */
7
namespace ZBateson\StreamDecorators;
8
9
use Psr\Http\Message\StreamInterface;
10
use GuzzleHttp\Psr7\StreamDecoratorTrait;
11
use ZBateson\StreamDecorators\Util\CharsetConverter;
12
use RuntimeException;
13
14
/**
15
 * GuzzleHttp\Psr7 stream decoder extension for charset conversion.
16
 *
17
 * @author Zaahid Bateson
18
 */
19
class CharsetStream implements StreamInterface
20
{
21
    use StreamDecoratorTrait;
22
23
    /**
24
     * @var CharsetConverter the charset converter
25
     */
26
    protected $converter = null;
27
    
28
    /**
29
     * @var string charset of the source stream
30
     */
31
    protected $streamCharset = 'ISO-8859-1';
32
    
33
    /**
34
     * @var string charset of strings passed in write operations, and returned
35
     *      in read operations.
36
     */
37
    protected $stringCharset = 'UTF-8';
38
39
    /**
40
     * @var int current read/write position
41
     */
42
    private $position = 0;
43
44
    /**
45
     * @var int number of $stringCharset characters in $buffer
46
     */
47
    private $bufferLength = 0;
48
49
    /**
50
     * @var string a buffer of characters read in the original $streamCharset
51
     *      encoding
52
     */
53
    private $buffer = '';
54
55
    /**
56
     * @param StreamInterface $stream Stream to decorate
57
     * @param string $streamCharset The underlying stream's charset
58
     * @param string $stringCharset The charset to encode strings to (or
59
     *        expected for write)
60
     */
61 8
    public function __construct(StreamInterface $stream, $streamCharset = 'ISO-8859-1', $stringCharset = 'UTF-8')
62
    {
63 8
        $this->stream = $stream;
64 8
        $this->converter = new CharsetConverter();
65 8
        $this->streamCharset = $streamCharset;
66 8
        $this->stringCharset = $stringCharset;
67 8
    }
68
69
    /**
70
     * Overridden to return the position in the target encoding.
71
     *
72
     * @return int
73
     */
74 2
    public function tell()
75
    {
76 2
        return $this->position;
77
    }
78
79
    /**
80
     * Returns null, getSize isn't supported
81
     *
82
     * @return null
83
     */
84 1
    public function getSize()
85
    {
86 1
        return null;
87
    }
88
89
    /**
90
     * Not supported.
91
     *
92
     * @param int $offset
93
     * @param int $whence
94
     * @throws RuntimeException
95
     */
96 1
    public function seek($offset, $whence = SEEK_SET)
97
    {
98 1
        throw new RuntimeException('Cannot seek a CharsetStream');
99
    }
100
101
    /**
102
     * Overridden to return false
103
     *
104
     * @return boolean
105
     */
106 1
    public function isSeekable()
107
    {
108 1
        return false;
109
    }
110
111
    /**
112
     * Reads a minimum of $length characters from the underlying stream in its
113
     * encoding into $this->buffer
114
     *
115
     * @param int $length
116
     */
117 6
    private function readRawCharsIntoBuffer($length)
118
    {
119 6
        $n = $length + 32;
120 6
        while ($this->bufferLength < $n) {
121 6
            $raw = $this->stream->read($n + 512);
122 6
            if ($raw === false || $raw === '') {
123 6
                return;
124
            }
125 6
            $this->buffer .= $raw;
126 6
            $this->bufferLength = $this->converter->getLength($this->buffer, $this->streamCharset);
127
        }
128 4
    }
129
130
    /**
131
     * Returns true if the end of stream has been reached.
132
     *
133
     * @return type
0 ignored issues
show
Bug introduced by
The type ZBateson\StreamDecorators\type was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
134
     */
135 6
    public function eof()
136
    {
137 6
        return ($this->bufferLength === 0 && $this->stream->eof());
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->bufferLeng...&& $this->stream->eof() returns the type boolean which is incompatible with the documented return type ZBateson\StreamDecorators\type.
Loading history...
138
    }
139
140
    /**
141
     * Reads up to $length decoded bytes from the underlying stream and returns
142
     * them after converting to the target string charset.
143
     *
144
     * @param int $length
145
     * @return string
146
     */
147 6
    public function read($length)
148
    {
149
        // let Guzzle decide what to do.
150 6
        if ($length <= 0 || $this->eof()) {
151 1
            return $this->stream->read($length);
152
        }
153 6
        $this->readRawCharsIntoBuffer($length);
154 6
        $numChars = min([$this->bufferLength, $length]);
155 6
        $chars = $this->converter->getSubstr($this->buffer, $this->streamCharset, 0, $numChars);
156
        
157 6
        $this->position += $numChars;
158 6
        $this->buffer = $this->converter->getSubstr($this->buffer, $this->streamCharset, $numChars);
159 6
        $this->bufferLength = $this->bufferLength - $numChars;
160
161 6
        return $this->converter->convert($chars, $this->streamCharset, $this->stringCharset);
162
    }
163
164
    /**
165
     * Writes the passed string to the underlying stream after converting it to
166
     * the target stream encoding.
167
     *
168
     * @param string $string
169
     * @return int the number of bytes written
170
     */
171 1
    public function write($string)
172
    {
173 1
        $converted = $this->converter->convert($string, $this->stringCharset, $this->streamCharset);
174 1
        $written = $this->converter->getLength($converted, $this->streamCharset);
175 1
        $this->position += $written;
176 1
        return $this->stream->write($converted);
177
    }
178
}
179