StringInputStream::skip()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 29
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4.0092

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 13
c 1
b 0
f 0
nc 4
nop 1
dl 0
loc 29
ccs 11
cts 12
cp 0.9167
crap 4.0092
rs 9.8333
1
<?php
2
3
namespace WebStream\IO;
4
5
use WebStream\Exception\Extend\InvalidArgumentException;
0 ignored issues
show
Bug introduced by
The type WebStream\Exception\Exte...nvalidArgumentException 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...
6
7
/**
8
 * StringInputStream
9
 * @author Ryuichi TANAKA.
10
 * @since 2016/02/07
11
 * @version 0.7
12
 */
13
class StringInputStream extends InputStream
14
{
15
    /**
16
     * @var int 文字列長
17
     */
18
    private $length;
19
20
    /**
21
     * @var bool 終端かどうか
22
     */
23
    private bool $isEOF = false;
24
25
    /**
26
     * construct
27
     * @param string $str 文字列
28
     */
29
    public function __construct(string $str)
30
    {
31
        parent::__construct($str);
32
        $this->length = strlen($str);
33
    }
34
35
    /**
36
     * 入力ストリームを閉じる
37
     */
38 20
    public function close()
39
    {
40 20
        $this->stream = null;
41
    }
42
43
    /**
44
     * {@inheritdoc}
45
     */
46 16
    public function read(int $length = 0)
47
    {
48 16
        if ($this->stream === null) {
49 1
            return null;
50
        }
51
52 15
        if ($this->eof()) {
53 2
            return null;
54
        }
55
56
        // SkipでポインタをずらしただけではEOFにはならない、FileInputStream実装に合わせる
57
        // Skipでずらしたあとreadすると空文字を返し、もう一度readするとEOFを認識する
58
        // ファイルの終端より先にポインタをすすめることは「可能」=書き込みと同じ
59
        // なので、現在の終端位置より先に進めてもEOF自体にはならない。進めた位置はEOFのひとつ前
60
        // だからもう一回readするとEOFに到達する。なのでskipを使ってもEOF到達できない
61 15
        if ($this->cursorPosition > $this->length - 1) {
62 4
            $this->isEOF = true;
63
64 4
            return "";
65
        }
66
67
        $out = "";
68 11
        if ($length === 0) {
69 7
            $length = 1;
70 7
            $out = substr($this->stream, $this->cursorPosition, $length);
71 7
            $this->cursorPosition += 1;
72
        } else {
73
            // $lengthがファイル終端を越えないようにする
74 4
            if (($this->cursorPosition + $length) > $this->length) {
75 2
                $length = $this->length - $this->cursorPosition;
76
            }
77
78 4
            $out = substr($this->stream, $this->cursorPosition, $length);
79 4
            $this->cursorPosition += $length;
80
        }
81
82 11
        return $out;
83
    }
84
85
    /**
86
     * 入力ストリームから行単位でデータを読み込む
87
     * 末尾に改行コードは含まない
88
     * @return string 読み込みデータ
89
     */
90 1
    public function readLine()
91
    {
92 1
        if ($this->stream === null) {
93
            return null;
94
        }
95
96 1
        if ($this->eof()) {
97
            return null;
98
        }
99
100
        // 処理対象の残りのバイト数
101 1
        $targetLength = $this->length - $this->cursorPosition;
102
103
        // 処理対象の文字列
104 1
        $text = substr($this->stream, $this->cursorPosition, $targetLength);
105 1
        $lengthEOL = strlen(PHP_EOL);
106 1
        $notLinePart = strstr($text, PHP_EOL);
107
108 1
        $notLinePartLength = 0;
109 1
        if ($notLinePart !== false) {
110 1
            $notLinePartLength = strlen($notLinePart);
111
        }
112
113 1
        $offset = $targetLength - $notLinePartLength;
114 1
        $out = substr($text, 0, $offset);
115 1
        $out = $out === false ? null : $out;
116 1
        $this->skip($offset + $lengthEOL);
117
118 1
        return $out;
119
    }
120
121
    /**
122
     * {@inheritdoc}
123
     */
124 14
    public function skip(int $pos)
125
    {
126 14
        if ($this->stream === null) {
127
            return -1;
128
        }
129
130
        // ファイル終端到達後、skipを実行すると後方にポインタが移動する
131
        // このときEOFだったものがEOFでなくなる
132 14
        $start = $this->cursorPosition;
133
134
        // 現在位置が負になった場合は-1を返して終了
135 14
        if ($this->cursorPosition + $pos < 0) {
136 2
            return -1;
137
        }
138
139 12
        $this->cursorPosition += $pos;
140 12
        $this->isEOF = false;
141
142
        // skipした実際のバイト数
143
        $skipNum = 0;
144 12
        if ($start > $this->cursorPosition) {
145
            // 後方へ移動
146 1
            $skipNum = $start - $this->cursorPosition;
147
        } else {
148
            // 前方へ移動
149 12
            $skipNum = $this->cursorPosition - $start;
150
        }
151
152 12
        return $skipNum;
153
    }
154
155
    /**
156
     * {@inheritdoc}
157
     */
158 16
    public function eof()
159
    {
160 16
        return $this->isEOF;
161
    }
162
163
    /**
164
     * {@inheritdoc}
165
     */
166 2
    public function isMarkSupported()
167
    {
168 2
        return true;
169
    }
170
}
171