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