Passed
Push — master ( 12b94f...668c77 )
by Gilles
03:31
created

Content::copyByToken()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 3
dl 0
loc 5
ccs 3
cts 3
cp 1
crap 1
rs 10
1
<?php 
2
3
declare(strict_types=1);
4
5
namespace PHPHtmlParser;
6
7
8
use PHPHtmlParser\Exceptions\LogicalException;
9
10
/**
11
 * Class Content
12
 *
13
 * @package PHPHtmlParser
14
 */
15
class Content
16
{
17
18
    /**
19
     * The content string.
20
     *
21
     * @var string
22
     */
23
    protected $content;
24
25
    /**
26
     * The size of the content.
27
     *
28
     * @var integer
29
     */
30
    protected $size;
31
32
    /**
33
     * The current position we are in the content.
34
     *
35
     * @var integer
36
     */
37
    protected $pos;
38
39
    /**
40
     * The following 4 strings are tags that are important to us.
41
     *
42
     * @var string
43
     */
44
    protected $blank = " \t\r\n";
45
    protected $equal = ' =/>';
46
    protected $slash = " />\r\n\t";
47
    protected $attr = ' >';
48
49
    /**
50
     * Content constructor.
51
     *
52
     * @param string $content
53
     */
54 285
    public function __construct(string $content = '')
55
    {
56 285
        $this->content = $content;
57 285
        $this->size    = strlen($content);
58 285
        $this->pos     = 0;
59 285
    }
60
61
    /**
62
     * Returns the current position of the content.
63
     *
64
     * @return int
65
     */
66 6
    public function getPosition(): int
67
    {
68 6
        return $this->pos;
69
    }
70
71
    /**
72
     * Gets the current character we are at.
73
     *
74
     * @param ?int $char
75
     * @return string
76
     */
77 270
    public function char(?int $char = null): string
78
    {
79 270
        $pos = $this->pos;
80 270
        if ( ! is_null($char)) {
81 213
            $pos = $char;
82
        }
83
84 270
        if ( ! isset($this->content[$pos])) {
85 240
            return '';
86
        }
87
88 264
        return $this->content[$pos];
89
    }
90
91
    /**
92
     * Moves the current position forward.
93
     *
94
     * @param int $count
95
     * @return Content
96
     * @chainable
97
     */
98 255
    public function fastForward(int $count): Content
99
    {
100 255
        $this->pos += $count;
101
102 255
        return $this;
103
    }
104
105
    /**
106
     * Moves the current position backward.
107
     *
108
     * @param int $count
109
     * @return Content
110
     * @chainable
111
     */
112 18
    public function rewind(int $count): Content
113
    {
114 18
        $this->pos -= $count;
115 18
        if ($this->pos < 0) {
116 3
            $this->pos = 0;
117
        }
118
119 18
        return $this;
120
    }
121
122
    /**
123
     * Copy the content until we find the given string.
124
     *
125
     * @param string $string
126
     * @param bool $char
127
     * @param bool $escape
128
     * @return string
129
     */
130 261
    public function copyUntil(string $string, bool $char = false, bool $escape = false): string
131
    {
132 261
        if ($this->pos >= $this->size) {
133
            // nothing left
134 240
            return '';
135
        }
136
137 261
        if ($escape) {
138 231
            $position = $this->pos;
139 231
            $found    = false;
140 231
            while ( ! $found) {
141 231
                $position = strpos($this->content, $string, $position);
142 231
                if ($position === false) {
143
                    // reached the end
144 210
                    break;
145
                }
146
147 210
                if ($this->char($position - 1) == '\\') {
148
                    // this character is escaped
149 3
                    ++$position;
150 3
                    continue;
151
                }
152
153 210
                $found = true;
154
            }
155 258
        } elseif ($char) {
156 246
            $position = strcspn($this->content, $string, $this->pos);
157 246
            $position += $this->pos;
158
        } else {
159 252
            $position = strpos($this->content, $string, $this->pos);
160
        }
161
162 261
        if ($position === false) {
0 ignored issues
show
introduced by
The condition $position === false is always false.
Loading history...
163
            // could not find character, just return the remaining of the content
164 219
            $return    = substr($this->content, $this->pos, $this->size - $this->pos);
165 219
            if ($return === false) {
166
                throw new LogicalException('Substr returned false with position '.$this->pos.'.');
167
            }
168 219
            $this->pos = $this->size;
169
170 219
            return $return;
171
        }
172
173 252
        if ($position == $this->pos) {
174
            // we are at the right place
175 240
            return '';
176
        }
177
178 252
        $return = substr($this->content, $this->pos, $position - $this->pos);
179 252
        if ($return === false) {
180
            throw new LogicalException('Substr returned false with position '.$this->pos.'.');
181
        }
182
        // set the new position
183 252
        $this->pos = $position;
184
185 252
        return $return;
186
    }
187
188
    /**
189
     * Copies the content until the string is found and return it
190
     * unless the 'unless' is found in the substring.
191
     *
192
     * @param string $string
193
     * @param string $unless
194
     * @return string
195
     */
196 228
    public function copyUntilUnless(string $string, string $unless)
197
    {
198 228
        $lastPos = $this->pos;
199 228
        $this->fastForward(1);
200 228
        $foundString = $this->copyUntil($string, true, true);
201
202 228
        $position = strcspn($foundString, $unless);
203 228
        if ($position == strlen($foundString)) {
204 42
            return $string.$foundString;
205
        }
206
        // rewind changes and return nothing
207 228
        $this->pos = $lastPos;
208
209 228
        return '';
210
    }
211
212
    /**
213
     * Copies the content until it reaches the token string.,
214
     *
215
     * @param string $token
216
     * @param bool $char
217
     * @param bool $escape
218
     * @return string
219
     * @uses $this->copyUntil()
220
     */
221 243
    public function copyByToken(string $token, bool $char = false, bool $escape = false)
222
    {
223 243
        $string = $this->$token;
224
225 243
        return $this->copyUntil($string, $char, $escape);
226
    }
227
228
    /**
229
     * Skip a given set of characters.
230
     *
231
     * @param string $string
232
     * @param bool $copy
233
     * @return Content|string
234
     */
235 249
    public function skip(string $string, bool $copy = false)
236
    {
237 249
        $len = strspn($this->content, $string, $this->pos);
238
239
        // make it chainable if they don't want a copy
240 249
        $return = $this;
241 249
        if ($copy) {
242 234
            $return = substr($this->content, $this->pos, $len);
243 234
            if ($return === false) {
244
                throw new LogicalException('Substr returned false with position '.$this->pos.'.');
245
            }
246
        }
247
248
        // update the position
249 249
        $this->pos += $len;
250
251 249
        return $return;
252
    }
253
254
    /**
255
     * Skip a given token of pre-defined characters.
256
     *
257
     * @param string $token
258
     * @param bool $copy
259
     * @return Content|string
260
     * @uses $this->skip()
261
     */
262 243
    public function skipByToken(string $token, bool $copy = false)
263
    {
264 243
        $string = $this->$token;
265
266 243
        return $this->skip($string, $copy);
267
    }
268
}
269