Completed
Push — master ( 30aab1...cadcfa )
by Asmir
07:00
created

StringInputStream   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 299
Duplicated Lines 0 %

Coupling/Cohesion

Dependencies 1

Importance

Changes 0
Metric Value
wmc 32
cbo 1
dl 0
loc 299
rs 9.84
c 0
b 0
f 0

17 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 18 2
A __toString() 0 4 1
A replaceLinefeeds() 0 17 1
A currentLine() 0 9 3
A getCurrentLine() 0 4 1
A columnOffset() 0 25 3
A getColumnOffset() 0 4 1
A current() 0 4 1
A next() 0 4 1
A rewind() 0 4 1
A valid() 0 8 2
A remainingChars() 0 11 2
A charsUntil() 0 17 4
A charsWhile() 0 16 4
A unconsume() 0 6 2
A peek() 0 8 2
A key() 0 4 1
1
<?php
2
/**
3
 * Loads a string to be parsed.
4
 */
5
namespace Masterminds\HTML5\Parser;
6
7
/*
8
 *
9
* Based on code from html5lib:
10
11
Copyright 2009 Geoffrey Sneddon <http://gsnedders.com/>
12
13
Permission is hereby granted, free of charge, to any person obtaining a
14
copy of this software and associated documentation files (the
15
    "Software"), to deal in the Software without restriction, including
16
without limitation the rights to use, copy, modify, merge, publish,
17
distribute, sublicense, and/or sell copies of the Software, and to
18
permit persons to whom the Software is furnished to do so, subject to
19
the following conditions:
20
21
The above copyright notice and this permission notice shall be included
22
in all copies or substantial portions of the Software.
23
24
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
27
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
28
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
29
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
30
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31
32
*/
33
34
// Some conventions:
35
// - /* */ indicates verbatim text from the HTML 5 specification
36
//   MPB: Not sure which version of the spec. Moving from HTML5lib to
37
//   HTML5-PHP, I have been using this version:
38
//   http://www.w3.org/TR/2012/CR-html5-20121217/Overview.html#contents
39
//
40
// - // indicates regular comments
41
42
/**
43
 * @deprecated since 2.4, to remove in 3.0. Use a string in the scanner instead.
44
 */
45
class StringInputStream implements InputStream
46
{
47
    /**
48
     * The string data we're parsing.
49
     */
50
    private $data;
51
52
    /**
53
     * The current integer byte position we are in $data
54
     */
55
    private $char;
56
57
    /**
58
     * Length of $data; when $char === $data, we are at the end-of-file.
59
     */
60
    private $EOF;
61
62
    /**
63
     * Parse errors.
64
     */
65
    public $errors = array();
66
67
    /**
68
     * Create a new InputStream wrapper.
69
     *
70
     * @param string $data Data to parse
71
     * @param string $encoding The encoding to use for the data.
72
     * @param string $debug A fprintf format to use to echo the data on stdout.
73
     */
74
    public function __construct($data, $encoding = 'UTF-8', $debug = '')
75
    {
76
        $data = UTF8Utils::convertToUTF8($data, $encoding);
77
        if ($debug) {
78
            fprintf(STDOUT, $debug, $data, strlen($data));
79
        }
80
81
        // There is good reason to question whether it makes sense to
82
        // do this here, since most of these checks are done during
83
        // parsing, and since this check doesn't actually *do* anything.
84
        $this->errors = UTF8Utils::checkForIllegalCodepoints($data);
85
86
        $data = $this->replaceLinefeeds($data);
87
88
        $this->data = $data;
89
        $this->char = 0;
90
        $this->EOF = strlen($data);
91
    }
92
93
    public function __toString()
94
    {
95
        return $this->data;
96
    }
97
98
    /**
99
     * Replace linefeed characters according to the spec.
100
     */
101
    protected function replaceLinefeeds($data)
102
    {
103
        /*
104
         * U+000D CARRIAGE RETURN (CR) characters and U+000A LINE FEED (LF) characters are treated specially.
105
         * Any CR characters that are followed by LF characters must be removed, and any CR characters not
106
         * followed by LF characters must be converted to LF characters. Thus, newlines in HTML DOMs are
107
         * represented by LF characters, and there are never any CR characters in the input to the tokenization
108
         * stage.
109
         */
110
        $crlfTable = array(
111
            "\0" => "\xEF\xBF\xBD",
112
            "\r\n" => "\n",
113
            "\r" => "\n"
114
        );
115
116
        return strtr($data, $crlfTable);
117
    }
118
119
    /**
120
     * Returns the current line that the tokenizer is at.
121
     */
122
    public function currentLine()
123
    {
124
        if (empty($this->EOF) || $this->char == 0) {
125
            return 1;
126
        }
127
        // Add one to $this->char because we want the number for the next
128
        // byte to be processed.
129
        return substr_count($this->data, "\n", 0, min($this->char, $this->EOF)) + 1;
130
    }
131
132
    /**
133
     *
134
     * @deprecated
135
     *
136
     */
137
    public function getCurrentLine()
138
    {
139
        return $this->currentLine();
140
    }
141
142
    /**
143
     * Returns the current column of the current line that the tokenizer is at.
144
     *
145
     * Newlines are column 0. The first char after a newline is column 1.
146
     *
147
     * @return int The column number.
148
     */
149
    public function columnOffset()
150
    {
151
        // Short circuit for the first char.
152
        if ($this->char == 0) {
153
            return 0;
154
        }
155
        // strrpos is weird, and the offset needs to be negative for what we
156
        // want (i.e., the last \n before $this->char). This needs to not have
157
        // one (to make it point to the next character, the one we want the
158
        // position of) added to it because strrpos's behaviour includes the
159
        // final offset byte.
160
        $backwardFrom = $this->char - 1 - strlen($this->data);
161
        $lastLine = strrpos($this->data, "\n", $backwardFrom);
162
163
        // However, for here we want the length up until the next byte to be
164
        // processed, so add one to the current byte ($this->char).
165
        if ($lastLine !== false) {
166
            $findLengthOf = substr($this->data, $lastLine + 1, $this->char - 1 - $lastLine);
167
        } else {
168
            // After a newline.
169
            $findLengthOf = substr($this->data, 0, $this->char);
170
        }
171
172
        return UTF8Utils::countChars($findLengthOf);
173
    }
174
175
    /**
176
     *
177
     * @deprecated
178
     *
179
     */
180
    public function getColumnOffset()
181
    {
182
        return $this->columnOffset();
183
    }
184
185
    /**
186
     * Get the current character.
187
     *
188
     * @return string The current character.
189
     */
190
    public function current()
191
    {
192
        return $this->data[$this->char];
193
    }
194
195
    /**
196
     * Advance the pointer.
197
     * This is part of the Iterator interface.
198
     */
199
    public function next()
200
    {
201
        $this->char ++;
202
    }
203
204
    /**
205
     * Rewind to the start of the string.
206
     */
207
    public function rewind()
208
    {
209
        $this->char = 0;
210
    }
211
212
    /**
213
     * Is the current pointer location valid.
214
     *
215
     * @return bool Is the current pointer location valid.
216
     */
217
    public function valid()
218
    {
219
        if ($this->char < $this->EOF) {
220
            return true;
221
        }
222
223
        return false;
224
    }
225
226
    /**
227
     * Get all characters until EOF.
228
     *
229
     * This reads to the end of the file, and sets the read marker at the
230
     * end of the file.
231
     *
232
     * @note This performs bounds checking
233
     *
234
     * @return string Returns the remaining text. If called when the InputStream is
235
     *         already exhausted, it returns an empty string.
236
     */
237
    public function remainingChars()
238
    {
239
        if ($this->char < $this->EOF) {
240
            $data = substr($this->data, $this->char);
241
            $this->char = $this->EOF;
242
243
            return $data;
244
        }
245
246
        return ''; // false;
247
    }
248
249
    /**
250
     * Read to a particular match (or until $max bytes are consumed).
251
     *
252
     * This operates on byte sequences, not characters.
253
     *
254
     * Matches as far as possible until we reach a certain set of bytes
255
     * and returns the matched substring.
256
     *
257
     * @param string $bytes
258
     *            Bytes to match.
259
     * @param int $max
260
     *            Maximum number of bytes to scan.
261
     * @return mixed Index or false if no match is found. You should use strong
262
     *         equality when checking the result, since index could be 0.
263
     */
264
    public function charsUntil($bytes, $max = null)
265
    {
266
        if ($this->char >= $this->EOF) {
267
            return false;
268
        }
269
270
        if ($max === 0 || $max) {
271
            $len = strcspn($this->data, $bytes, $this->char, $max);
272
        } else {
273
            $len = strcspn($this->data, $bytes, $this->char);
274
        }
275
276
        $string = (string) substr($this->data, $this->char, $len);
277
        $this->char += $len;
278
279
        return $string;
280
    }
281
282
    /**
283
     * Returns the string so long as $bytes matches.
284
     *
285
     * Matches as far as possible with a certain set of bytes
286
     * and returns the matched substring.
287
     *
288
     * @param string $bytes
289
     *            A mask of bytes to match. If ANY byte in this mask matches the
290
     *            current char, the pointer advances and the char is part of the
291
     *            substring.
292
     * @param int $max
293
     *            The max number of chars to read.
294
     *
295
     * @return string
296
     */
297
    public function charsWhile($bytes, $max = null)
298
    {
299
        if ($this->char >= $this->EOF) {
300
            return false;
301
        }
302
303
        if ($max === 0 || $max) {
304
            $len = strspn($this->data, $bytes, $this->char, $max);
305
        } else {
306
            $len = strspn($this->data, $bytes, $this->char);
307
        }
308
        $string = (string) substr($this->data, $this->char, $len);
309
        $this->char += $len;
310
311
        return $string;
312
    }
313
314
    /**
315
     * Unconsume characters.
316
     *
317
     * @param int $howMany
318
     *            The number of characters to unconsume.
319
     */
320
    public function unconsume($howMany = 1)
321
    {
322
        if (($this->char - $howMany) >= 0) {
323
            $this->char = $this->char - $howMany;
324
        }
325
    }
326
327
    /**
328
     * Look ahead without moving cursor.
329
     */
330
    public function peek()
331
    {
332
        if (($this->char + 1) <= $this->EOF) {
333
            return $this->data[$this->char + 1];
334
        }
335
336
        return false;
337
    }
338
339
    public function key()
340
    {
341
        return $this->char;
342
    }
343
}
344