1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* This file is part of the stream package |
4
|
|
|
* |
5
|
|
|
* @author Daniel Schröder <[email protected]> |
6
|
|
|
*/ |
7
|
|
|
|
8
|
|
|
namespace GravityMedia\Stream; |
9
|
|
|
|
10
|
|
|
use GravityMedia\Stream\Exception; |
11
|
|
|
|
12
|
|
|
/** |
13
|
|
|
* Stream class. |
14
|
|
|
* |
15
|
|
|
* @package GravityMedia\Stream |
16
|
|
|
*/ |
17
|
|
|
class Stream |
18
|
|
|
{ |
19
|
|
|
/** |
20
|
|
|
* @var string[] |
21
|
|
|
*/ |
22
|
|
|
private static $readModes = ['r', 'w+', 'r+', 'x+', 'c+', 'rb', 'w+b', 'r+b', 'x+b', 'c+b', 'rt', 'w+t', |
23
|
|
|
'r+t', 'x+t', 'c+t', 'a+']; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* @var string[] |
27
|
|
|
*/ |
28
|
|
|
private static $writeModes = ['w', 'w+', 'rw', 'r+', 'x+', 'c+', 'wb', 'w+b', 'r+b', 'x+b', 'c+b', 'w+t', |
29
|
|
|
'r+t', 'x+t', 'c+t', 'a', 'a+']; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* @var resource |
33
|
|
|
*/ |
34
|
|
|
protected $resource; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* @var bool |
38
|
|
|
*/ |
39
|
|
|
protected $local; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* @var bool |
43
|
|
|
*/ |
44
|
|
|
protected $readable; |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* @var bool |
48
|
|
|
*/ |
49
|
|
|
protected $writable; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* @var bool |
53
|
|
|
*/ |
54
|
|
|
protected $seekable; |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* @var string |
58
|
|
|
*/ |
59
|
|
|
protected $uri; |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* @var int |
63
|
|
|
*/ |
64
|
|
|
protected $byteOrder; |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* @var int |
68
|
|
|
*/ |
69
|
|
|
protected static $machineByteOrder; |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* Create stream object from resource. |
73
|
|
|
* |
74
|
|
|
* @param resource $resource |
75
|
|
|
* |
76
|
|
|
* @throws Exception\InvalidArgumentException An exception will be thrown for invalid resource arguments. |
77
|
|
|
* |
78
|
|
|
* @return static |
79
|
|
|
*/ |
80
|
50 |
|
public static function fromResource($resource) |
81
|
|
|
{ |
82
|
50 |
|
if (!is_resource($resource)) { |
83
|
2 |
|
throw new Exception\InvalidArgumentException('Invalid resource'); |
84
|
|
|
} |
85
|
|
|
|
86
|
48 |
|
$stream = new static(); |
87
|
|
|
|
88
|
48 |
|
return $stream->bindResource($resource); |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* Bind resource to stream and gather meta data. |
93
|
|
|
* |
94
|
|
|
* @param resource $resource The resource to bind to the stream. |
95
|
|
|
* |
96
|
|
|
* @throws Exception\InvalidArgumentException An exception will be thrown for invalid resource arguments. |
97
|
|
|
* |
98
|
|
|
* @return $this |
99
|
|
|
*/ |
100
|
48 |
|
public function bindResource($resource) |
101
|
|
|
{ |
102
|
48 |
|
if (!is_resource($resource)) { |
103
|
2 |
|
throw new Exception\InvalidArgumentException('Invalid resource'); |
104
|
|
|
} |
105
|
|
|
|
106
|
48 |
|
$metaData = stream_get_meta_data($resource); |
107
|
|
|
|
108
|
48 |
|
$this->resource = $resource; |
109
|
48 |
|
$this->local = stream_is_local($resource); |
110
|
48 |
|
$this->readable = in_array($metaData['mode'], self::$readModes); |
111
|
48 |
|
$this->writable = in_array($metaData['mode'], self::$writeModes); |
112
|
48 |
|
$this->seekable = $metaData['seekable']; |
113
|
48 |
|
$this->uri = $metaData['uri']; |
114
|
|
|
|
115
|
48 |
|
return $this; |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* Return whether the stream is local. |
120
|
|
|
* |
121
|
|
|
* @return bool |
122
|
|
|
*/ |
123
|
6 |
|
public function isLocal() |
124
|
|
|
{ |
125
|
6 |
|
return $this->local; |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* Return whether read access on the stream will be granted. |
130
|
|
|
* |
131
|
|
|
* @return bool |
132
|
|
|
*/ |
133
|
8 |
|
public function isReadable() |
134
|
|
|
{ |
135
|
8 |
|
return $this->readable; |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* Return whether write access on the stream will be granted. |
140
|
|
|
* |
141
|
|
|
* @return bool |
142
|
|
|
*/ |
143
|
12 |
|
public function isWritable() |
144
|
|
|
{ |
145
|
12 |
|
return $this->writable; |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
/** |
149
|
|
|
* Return whether the stream can be sought. |
150
|
|
|
* |
151
|
|
|
* @return bool |
152
|
|
|
*/ |
153
|
12 |
|
public function isSeekable() |
154
|
|
|
{ |
155
|
12 |
|
return $this->seekable; |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
/** |
159
|
|
|
* Get the URI or filename associated with the stream. |
160
|
|
|
* |
161
|
|
|
* @return string |
162
|
|
|
*/ |
163
|
4 |
|
public function getUri() |
164
|
|
|
{ |
165
|
4 |
|
return $this->uri; |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
/** |
169
|
|
|
* Get the byte order for integer handling. |
170
|
|
|
* |
171
|
|
|
* @return int |
172
|
|
|
*/ |
173
|
4 |
|
public function getByteOrder() |
174
|
|
|
{ |
175
|
4 |
|
if (null === $this->byteOrder) { |
176
|
2 |
|
return ByteOrder::MACHINE_ENDIAN; |
177
|
|
|
} |
178
|
|
|
|
179
|
2 |
|
return $this->byteOrder; |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* Set the byte order for integer handling. |
184
|
|
|
* |
185
|
|
|
* @param int $byteOrder The byte order to set. Must be one of the constants defined by the byte order enum. |
186
|
|
|
* |
187
|
|
|
* @throws Exception\InvalidArgumentException An exception will be thrown for invalid byte order arguments. |
188
|
|
|
* |
189
|
|
|
* @return $this |
190
|
|
|
*/ |
191
|
4 |
|
public function setByteOrder($byteOrder) |
192
|
|
|
{ |
193
|
4 |
|
if (!in_array($byteOrder, ByteOrder::values(), true)) { |
194
|
2 |
|
throw new Exception\InvalidArgumentException('Invalid byte order'); |
195
|
|
|
} |
196
|
|
|
|
197
|
2 |
|
$this->byteOrder = $byteOrder; |
198
|
|
|
|
199
|
2 |
|
return $this; |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* Get the machine byte order. |
204
|
|
|
* |
205
|
|
|
* @return int |
206
|
|
|
*/ |
207
|
184 |
|
public function getMachineByteOrder() |
208
|
|
|
{ |
209
|
184 |
|
if (null === static::$machineByteOrder) { |
210
|
2 |
|
static::$machineByteOrder = ByteOrder::BIG_ENDIAN; |
211
|
|
|
|
212
|
2 |
|
list(, $value) = @unpack('s', "\x01\x00"); |
213
|
2 |
|
if (1 === $value) { |
214
|
2 |
|
static::$machineByteOrder = ByteOrder::LITTLE_ENDIAN; |
215
|
1 |
|
} |
216
|
1 |
|
} |
217
|
|
|
|
218
|
184 |
|
return static::$machineByteOrder; |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
/** |
222
|
|
|
* Get information about the stream. |
223
|
|
|
* |
224
|
|
|
* @param string $info The information to retrieve. |
225
|
|
|
* |
226
|
|
|
* @throws Exception\IOException An exception will be thrown for invalid stream resources. |
227
|
|
|
* |
228
|
|
|
* @return int |
229
|
|
|
*/ |
230
|
4 |
|
protected function getStat($info) |
231
|
|
|
{ |
232
|
4 |
|
if (!is_resource($this->resource)) { |
233
|
2 |
|
throw new Exception\IOException('Invalid stream resource'); |
234
|
|
|
} |
235
|
|
|
|
236
|
2 |
|
$uri = $this->getUri(); |
237
|
2 |
|
if (is_string($uri)) { |
238
|
2 |
|
clearstatcache(true, $uri); |
239
|
1 |
|
} |
240
|
|
|
|
241
|
2 |
|
$stat = fstat($this->resource); |
242
|
|
|
|
243
|
2 |
|
return $stat[$info]; |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
/** |
247
|
|
|
* Get size of the stream in bytes |
248
|
|
|
* |
249
|
|
|
* @throws Exception\BadMethodCallException An exception will be thrown for non-local streams. |
250
|
|
|
* @throws Exception\IOException An exception will be thrown for invalid stream resources. |
251
|
|
|
* |
252
|
|
|
* @return int |
253
|
|
|
*/ |
254
|
6 |
|
public function getSize() |
255
|
|
|
{ |
256
|
6 |
|
if (!$this->isLocal()) { |
257
|
2 |
|
throw new Exception\BadMethodCallException('Stream not local'); |
258
|
|
|
} |
259
|
|
|
|
260
|
4 |
|
return $this->getStat('size'); |
261
|
|
|
} |
262
|
|
|
|
263
|
|
|
/** |
264
|
|
|
* Return whether the end of the stream was reached. |
265
|
|
|
* |
266
|
|
|
* @throws Exception\IOException An exception will be thrown for invalid stream resources. |
267
|
|
|
* |
268
|
|
|
* @return bool |
269
|
|
|
* @link http://www.php.net/manual/en/function.feof.php |
270
|
|
|
*/ |
271
|
4 |
|
public function eof() |
272
|
|
|
{ |
273
|
4 |
|
if (!is_resource($this->resource)) { |
274
|
2 |
|
throw new Exception\IOException('Invalid stream resource'); |
275
|
|
|
} |
276
|
|
|
|
277
|
2 |
|
return feof($this->resource); |
278
|
|
|
} |
279
|
|
|
|
280
|
|
|
/** |
281
|
|
|
* Return the current position of the stream. |
282
|
|
|
* |
283
|
|
|
* @throws Exception\IOException An exception will be thrown for invalid stream resources. |
284
|
|
|
* |
285
|
|
|
* @return int |
286
|
|
|
* @link http://www.php.net/manual/en/function.ftell.php |
287
|
|
|
*/ |
288
|
8 |
|
public function tell() |
289
|
|
|
{ |
290
|
8 |
|
if (!is_resource($this->resource)) { |
291
|
2 |
|
throw new Exception\IOException('Invalid stream resource'); |
292
|
|
|
} |
293
|
|
|
|
294
|
6 |
|
return ftell($this->resource); |
295
|
|
|
} |
296
|
|
|
|
297
|
|
|
/** |
298
|
|
|
* Seek and return the position of the stream. |
299
|
|
|
* |
300
|
|
|
* @param int $offset The offset. |
301
|
|
|
* @param int $whence Either SEEK_SET (which is default), SEEK_CUR or SEEK_END. |
302
|
|
|
* |
303
|
|
|
* @throws Exception\BadMethodCallException An exception will be thrown for non-seekable streams. |
304
|
|
|
* @throws Exception\IOException An exception will be thrown for invalid stream resources or when the |
305
|
|
|
* position could not be set. |
306
|
|
|
* |
307
|
|
|
* @return int |
308
|
|
|
* @link http://www.php.net/manual/en/function.fseek.php |
309
|
|
|
*/ |
310
|
12 |
|
public function seek($offset, $whence = SEEK_SET) |
311
|
|
|
{ |
312
|
12 |
|
if (!$this->isSeekable()) { |
313
|
2 |
|
throw new Exception\BadMethodCallException('Stream not seekable'); |
314
|
|
|
} |
315
|
|
|
|
316
|
10 |
|
if (!is_resource($this->resource)) { |
317
|
2 |
|
throw new Exception\IOException('Invalid stream resource'); |
318
|
|
|
} |
319
|
|
|
|
320
|
8 |
|
if (fseek($this->resource, $offset, $whence) < 0) { |
321
|
2 |
|
throw new Exception\IOException('Unexpected result of operation'); |
322
|
|
|
} |
323
|
|
|
|
324
|
6 |
|
return $this->tell(); |
325
|
|
|
} |
326
|
|
|
|
327
|
|
|
/** |
328
|
|
|
* Rewind the position of the stream. |
329
|
|
|
* |
330
|
|
|
* @throws Exception\BadMethodCallException An exception will be thrown for non-seekable streams. |
331
|
|
|
* @throws Exception\IOException An exception will be thrown for invalid stream resources or when the |
332
|
|
|
* position could not be set. |
333
|
|
|
* |
334
|
|
|
* @return int |
335
|
|
|
*/ |
336
|
2 |
|
public function rewind() |
337
|
|
|
{ |
338
|
2 |
|
return $this->seek(0); |
339
|
|
|
} |
340
|
|
|
|
341
|
|
|
/** |
342
|
|
|
* Align the data in relation to the byte order. |
343
|
|
|
* |
344
|
|
|
* @param string $data |
345
|
|
|
* |
346
|
|
|
* @return string |
347
|
|
|
*/ |
348
|
276 |
|
protected function alignData($data) |
349
|
|
|
{ |
350
|
276 |
|
if ($this->getByteOrder() !== ByteOrder::MACHINE_ENDIAN |
351
|
276 |
|
&& $this->getByteOrder() !== $this->getMachineByteOrder() |
352
|
138 |
|
) { |
353
|
92 |
|
return strrev($data); |
354
|
|
|
} |
355
|
|
|
|
356
|
184 |
|
return $data; |
357
|
|
|
} |
358
|
|
|
|
359
|
|
|
/** |
360
|
|
|
* Read up to $length number of bytes of data from the stream. |
361
|
|
|
* |
362
|
|
|
* @param int $length The maximum number of bytes to read. |
363
|
|
|
* |
364
|
|
|
* @throws Exception\BadMethodCallException An exception will be thrown for non-readable streams. |
365
|
|
|
* @throws Exception\IOException An exception will be thrown for invalid stream resources or when the |
366
|
|
|
* data could not be read. |
367
|
|
|
* |
368
|
|
|
* @return string |
369
|
|
|
* @link http://www.php.net/manual/en/function.fread.php |
370
|
|
|
*/ |
371
|
8 |
View Code Duplication |
public function read($length) |
|
|
|
|
372
|
|
|
{ |
373
|
8 |
|
if (!$this->isReadable()) { |
374
|
2 |
|
throw new Exception\BadMethodCallException('Stream not readable'); |
375
|
|
|
} |
376
|
|
|
|
377
|
6 |
|
if (!is_resource($this->resource)) { |
378
|
2 |
|
throw new Exception\IOException('Invalid stream resource'); |
379
|
|
|
} |
380
|
|
|
|
381
|
4 |
|
$data = @fread($this->resource, $length); |
382
|
4 |
|
if (false === $data) { |
383
|
2 |
|
throw new Exception\IOException('Unexpected result of operation'); |
384
|
|
|
} |
385
|
|
|
|
386
|
2 |
|
return $data; |
387
|
|
|
} |
388
|
|
|
|
389
|
|
|
/** |
390
|
|
|
* Read signed 8-bit integer (char) data from the stream. |
391
|
|
|
* |
392
|
|
|
* @throws Exception\BadMethodCallException An exception will be thrown for non-readable streams. |
393
|
|
|
* @throws Exception\IOException An exception will be thrown for invalid stream resources or when the |
394
|
|
|
* data could not be read. |
395
|
|
|
* |
396
|
|
|
* @return int |
397
|
|
|
*/ |
398
|
6 |
|
public function readInt8() |
399
|
|
|
{ |
400
|
6 |
|
list(, $value) = @unpack('c', $this->read(1)); |
401
|
6 |
|
return $value; |
402
|
|
|
} |
403
|
|
|
|
404
|
|
|
/** |
405
|
|
|
* Read unsigned 8-bit integer (char) data from the stream. |
406
|
|
|
* |
407
|
|
|
* @throws Exception\BadMethodCallException An exception will be thrown for non-readable streams. |
408
|
|
|
* @throws Exception\IOException An exception will be thrown for invalid stream resources or when the |
409
|
|
|
* data could not be read. |
410
|
|
|
* |
411
|
|
|
* @return int |
412
|
|
|
*/ |
413
|
8 |
|
public function readUInt8() |
414
|
|
|
{ |
415
|
8 |
|
list(, $value) = @unpack('C', $this->read(1)); |
416
|
8 |
|
return $value; |
417
|
|
|
} |
418
|
|
|
|
419
|
|
|
/** |
420
|
|
|
* Read signed 16-bit integer (short) data from the stream. |
421
|
|
|
* |
422
|
|
|
* @throws Exception\BadMethodCallException An exception will be thrown for non-readable streams. |
423
|
|
|
* @throws Exception\IOException An exception will be thrown for invalid stream resources or when the |
424
|
|
|
* data could not be read. |
425
|
|
|
* |
426
|
|
|
* @return int |
427
|
|
|
*/ |
428
|
18 |
|
public function readInt16() |
429
|
|
|
{ |
430
|
18 |
|
list(, $value) = @unpack('s', $this->alignData($this->read(2))); |
431
|
18 |
|
return $value; |
432
|
|
|
} |
433
|
|
|
|
434
|
|
|
/** |
435
|
|
|
* Read unsigned 16-bit integer (short) data from the stream. |
436
|
|
|
* |
437
|
|
|
* @throws Exception\BadMethodCallException An exception will be thrown for non-readable streams. |
438
|
|
|
* @throws Exception\IOException An exception will be thrown for invalid stream resources or when the |
439
|
|
|
* data could not be read. |
440
|
|
|
* |
441
|
|
|
* @return int |
442
|
|
|
*/ |
443
|
30 |
View Code Duplication |
public function readUInt16() |
|
|
|
|
444
|
|
|
{ |
445
|
30 |
|
switch ($this->getByteOrder()) { |
446
|
30 |
|
case ByteOrder::BIG_ENDIAN: |
447
|
10 |
|
$format = 'n'; |
448
|
10 |
|
break; |
449
|
20 |
|
case ByteOrder::LITTLE_ENDIAN: |
450
|
10 |
|
$format = 'v'; |
451
|
10 |
|
break; |
452
|
5 |
|
default: |
453
|
10 |
|
$format = 'S'; |
454
|
15 |
|
} |
455
|
|
|
|
456
|
30 |
|
list(, $value) = @unpack($format, $this->read(2)); |
457
|
30 |
|
return $value; |
458
|
|
|
} |
459
|
|
|
|
460
|
|
|
/** |
461
|
|
|
* Read signed 24-bit integer data from the stream. |
462
|
|
|
* |
463
|
|
|
* @throws Exception\BadMethodCallException An exception will be thrown for non-readable streams. |
464
|
|
|
* @throws Exception\IOException An exception will be thrown for invalid stream resources or when the |
465
|
|
|
* data could not be read. |
466
|
|
|
* |
467
|
|
|
* @return int |
468
|
|
|
*/ |
469
|
18 |
|
public function readInt24() |
470
|
|
|
{ |
471
|
18 |
|
$value = $this->readUInt24(); |
472
|
|
|
|
473
|
18 |
|
if ($value & 0x800000) { |
474
|
6 |
|
$value -= 0x1000000; |
475
|
3 |
|
} |
476
|
|
|
|
477
|
18 |
|
return $value; |
478
|
|
|
} |
479
|
|
|
|
480
|
|
|
/** |
481
|
|
|
* Read unsigned 24-bit integer data from the stream. |
482
|
|
|
* |
483
|
|
|
* @throws Exception\BadMethodCallException An exception will be thrown for non-readable streams. |
484
|
|
|
* @throws Exception\IOException An exception will be thrown for invalid stream resources or when the |
485
|
|
|
* data could not be read. |
486
|
|
|
* |
487
|
|
|
* @return int |
488
|
|
|
*/ |
489
|
42 |
|
public function readUInt24() |
490
|
|
|
{ |
491
|
42 |
|
$values = @unpack('C3', $this->alignData($this->read(3))); |
492
|
42 |
|
return $values[1] | $values[2] << 8 | $values[3] << 16; |
493
|
|
|
} |
494
|
|
|
|
495
|
|
|
/** |
496
|
|
|
* Read signed 32-bit integer (long) data from the stream. |
497
|
|
|
* |
498
|
|
|
* @throws Exception\BadMethodCallException An exception will be thrown for non-readable streams. |
499
|
|
|
* @throws Exception\IOException An exception will be thrown for invalid stream resources or when the |
500
|
|
|
* data could not be read. |
501
|
|
|
* |
502
|
|
|
* @return int |
503
|
|
|
*/ |
504
|
18 |
|
public function readInt32() |
505
|
|
|
{ |
506
|
18 |
|
list(, $value) = @unpack('l', $this->alignData($this->read(4))); |
507
|
18 |
|
return $value; |
508
|
|
|
} |
509
|
|
|
|
510
|
|
|
/** |
511
|
|
|
* Read unsigned 32-bit integer (long) data from the stream. |
512
|
|
|
* |
513
|
|
|
* @throws Exception\BadMethodCallException An exception will be thrown for non-readable streams. |
514
|
|
|
* @throws Exception\IOException An exception will be thrown for invalid stream resources or when the |
515
|
|
|
* data could not be read. |
516
|
|
|
* |
517
|
|
|
* @return int |
518
|
|
|
*/ |
519
|
24 |
View Code Duplication |
public function readUInt32() |
|
|
|
|
520
|
|
|
{ |
521
|
24 |
|
switch ($this->getByteOrder()) { |
522
|
24 |
|
case ByteOrder::BIG_ENDIAN: |
523
|
8 |
|
$format = 'N'; |
524
|
8 |
|
break; |
525
|
16 |
|
case ByteOrder::LITTLE_ENDIAN: |
526
|
8 |
|
$format = 'V'; |
527
|
8 |
|
break; |
528
|
4 |
|
default: |
529
|
8 |
|
$format = 'L'; |
530
|
12 |
|
} |
531
|
|
|
|
532
|
24 |
|
list(, $value) = @unpack($format, $this->read(4)); |
533
|
24 |
|
return $value; |
534
|
|
|
} |
535
|
|
|
|
536
|
|
|
/** |
537
|
|
|
* Read signed 48-bit integer data from the stream. |
538
|
|
|
* |
539
|
|
|
* @throws Exception\BadMethodCallException An exception will be thrown for non-readable streams. |
540
|
|
|
* @throws Exception\IOException An exception will be thrown for invalid stream resources or when the |
541
|
|
|
* data could not be read. |
542
|
|
|
* |
543
|
|
|
* @return int |
544
|
|
|
*/ |
545
|
18 |
|
public function readInt48() |
546
|
|
|
{ |
547
|
18 |
|
$value = $this->readUInt48(); |
548
|
|
|
|
549
|
18 |
|
if ($value & 0x800000000000) { |
550
|
6 |
|
$value -= 0x1000000000000; |
551
|
3 |
|
} |
552
|
|
|
|
553
|
18 |
|
return $value; |
554
|
|
|
} |
555
|
|
|
|
556
|
|
|
/** |
557
|
|
|
* Read unsigned 48-bit integer data from the stream. |
558
|
|
|
* |
559
|
|
|
* @throws Exception\BadMethodCallException An exception will be thrown for non-readable streams. |
560
|
|
|
* @throws Exception\IOException An exception will be thrown for invalid stream resources or when the |
561
|
|
|
* data could not be read. |
562
|
|
|
* |
563
|
|
|
* @return int |
564
|
|
|
*/ |
565
|
42 |
|
public function readUInt48() |
566
|
|
|
{ |
567
|
42 |
|
$values = @unpack('C6', $this->alignData($this->read(6))); |
568
|
42 |
|
return $values[1] | $values[2] << 8 | $values[3] << 16 | $values[4] << 24 | $values[5] << 32 | $values[6] << 40; |
569
|
|
|
} |
570
|
|
|
|
571
|
|
|
/** |
572
|
|
|
* Read signed 64-bit integer (long long) data from the stream. |
573
|
|
|
* |
574
|
|
|
* @throws Exception\BadMethodCallException An exception will be thrown for non-readable streams. |
575
|
|
|
* @throws Exception\IOException An exception will be thrown for invalid stream resources or when the |
576
|
|
|
* data could not be read. |
577
|
|
|
* |
578
|
|
|
* @return int |
579
|
|
|
*/ |
580
|
18 |
|
public function readInt64() |
581
|
|
|
{ |
582
|
18 |
|
list(, $value) = @unpack('q', $this->alignData($this->read(8))); |
583
|
18 |
|
return $value; |
584
|
|
|
} |
585
|
|
|
|
586
|
|
|
/** |
587
|
|
|
* Read unsigned 64-bit integer (long long) data from the stream. |
588
|
|
|
* |
589
|
|
|
* @throws Exception\BadMethodCallException An exception will be thrown for non-readable streams. |
590
|
|
|
* @throws Exception\IOException An exception will be thrown for invalid stream resources or when the |
591
|
|
|
* data could not be read. |
592
|
|
|
* |
593
|
|
|
* @return int |
594
|
|
|
*/ |
595
|
24 |
View Code Duplication |
public function readUInt64() |
|
|
|
|
596
|
|
|
{ |
597
|
24 |
|
switch ($this->getByteOrder()) { |
598
|
24 |
|
case ByteOrder::BIG_ENDIAN: |
599
|
8 |
|
$format = 'J'; |
600
|
8 |
|
break; |
601
|
16 |
|
case ByteOrder::LITTLE_ENDIAN: |
602
|
8 |
|
$format = 'P'; |
603
|
8 |
|
break; |
604
|
4 |
|
default: |
605
|
8 |
|
$format = 'Q'; |
606
|
12 |
|
} |
607
|
|
|
|
608
|
24 |
|
list(, $value) = @unpack($format, $this->read(8)); |
609
|
24 |
|
return $value; |
610
|
|
|
} |
611
|
|
|
|
612
|
|
|
/** |
613
|
|
|
* Write data to the stream and return the number of bytes written. |
614
|
|
|
* |
615
|
|
|
* @param string $data The data |
616
|
|
|
* |
617
|
|
|
* @throws Exception\BadMethodCallException An exception will be thrown for non-writable streams. |
618
|
|
|
* @throws Exception\IOException An exception will be thrown for invalid stream resources or when the |
619
|
|
|
* data could not be written. |
620
|
|
|
* |
621
|
|
|
* @return int |
622
|
|
|
* @link http://www.php.net/manual/en/function.fwrite.php |
623
|
|
|
*/ |
624
|
8 |
View Code Duplication |
public function write($data) |
|
|
|
|
625
|
|
|
{ |
626
|
8 |
|
if (!$this->isWritable()) { |
627
|
2 |
|
throw new Exception\BadMethodCallException('Stream not writable'); |
628
|
|
|
} |
629
|
|
|
|
630
|
6 |
|
if (!is_resource($this->resource)) { |
631
|
2 |
|
throw new Exception\IOException('Invalid stream resource'); |
632
|
|
|
} |
633
|
|
|
|
634
|
4 |
|
$length = @fwrite($this->resource, $data); |
635
|
4 |
|
if (false === $length) { |
636
|
2 |
|
throw new Exception\IOException('Unexpected result of operation'); |
637
|
|
|
} |
638
|
|
|
|
639
|
2 |
|
return $length; |
640
|
|
|
} |
641
|
|
|
|
642
|
|
|
/** |
643
|
|
|
* Write signed 8-bit integer (char) data to the stream |
644
|
|
|
* |
645
|
|
|
* @param int $value The value |
646
|
|
|
* |
647
|
|
|
* @return int |
648
|
|
|
*/ |
649
|
6 |
|
public function writeInt8($value) |
650
|
|
|
{ |
651
|
6 |
|
return $this->write(pack('c', $value)); |
652
|
|
|
} |
653
|
|
|
|
654
|
|
|
/** |
655
|
|
|
* Write unsigned 8-bit integer (char) data to the stream |
656
|
|
|
* |
657
|
|
|
* @param int $value The value |
658
|
|
|
* |
659
|
|
|
* @return int |
660
|
|
|
*/ |
661
|
8 |
|
public function writeUInt8($value) |
662
|
|
|
{ |
663
|
8 |
|
return $this->write(pack('C', $value)); |
664
|
|
|
} |
665
|
|
|
|
666
|
|
|
/** |
667
|
|
|
* Write signed 16-bit integer (short) data to the stream |
668
|
|
|
* |
669
|
|
|
* @param int $value The value |
670
|
|
|
* |
671
|
|
|
* @return int |
672
|
|
|
*/ |
673
|
18 |
|
public function writeInt16($value) |
674
|
|
|
{ |
675
|
18 |
|
return $this->write($this->alignData(pack('s', $value))); |
676
|
|
|
} |
677
|
|
|
|
678
|
|
|
/** |
679
|
|
|
* Write unsigned 16-bit integer (short) data to the stream |
680
|
|
|
* |
681
|
|
|
* @param int $value The value |
682
|
|
|
* |
683
|
|
|
* @return int |
684
|
|
|
*/ |
685
|
30 |
|
public function writeUInt16($value) |
686
|
|
|
{ |
687
|
30 |
|
switch ($this->getByteOrder()) { |
688
|
30 |
|
case ByteOrder::BIG_ENDIAN: |
689
|
10 |
|
$format = 'n'; |
690
|
10 |
|
break; |
691
|
20 |
|
case ByteOrder::LITTLE_ENDIAN: |
692
|
10 |
|
$format = 'v'; |
693
|
10 |
|
break; |
694
|
5 |
|
default: |
695
|
10 |
|
$format = 'S'; |
696
|
15 |
|
} |
697
|
|
|
|
698
|
30 |
|
return $this->write(pack($format, $value)); |
699
|
|
|
} |
700
|
|
|
|
701
|
|
|
/** |
702
|
|
|
* Write signed 24-bit integer data to the stream |
703
|
|
|
* |
704
|
|
|
* @param int $value The value |
705
|
|
|
* |
706
|
|
|
* @return int |
707
|
|
|
*/ |
708
|
18 |
|
public function writeInt24($value) |
709
|
|
|
{ |
710
|
18 |
|
if ($value & 0x7fffff) { |
711
|
6 |
|
$value += 0x1000000; |
712
|
3 |
|
} |
713
|
|
|
|
714
|
18 |
|
return $this->writeUInt24($value); |
715
|
|
|
} |
716
|
|
|
|
717
|
|
|
/** |
718
|
|
|
* Write unsigned 24-bit integer data to the stream |
719
|
|
|
* |
720
|
|
|
* @param int $value The value |
721
|
|
|
* |
722
|
|
|
* @return int |
723
|
|
|
*/ |
724
|
42 |
|
public function writeUInt24($value) |
725
|
|
|
{ |
726
|
42 |
|
return $this->write($this->alignData(pack('C3', $value, $value >> 8, $value >> 16))); |
727
|
|
|
} |
728
|
|
|
|
729
|
|
|
/** |
730
|
|
|
* Write signed 32-bit integer (long) data to the stream |
731
|
|
|
* |
732
|
|
|
* @param int $value The value |
733
|
|
|
* |
734
|
|
|
* @return int |
735
|
|
|
*/ |
736
|
18 |
|
public function writeInt32($value) |
737
|
|
|
{ |
738
|
18 |
|
return $this->write($this->alignData(pack('l', $value))); |
739
|
|
|
} |
740
|
|
|
|
741
|
|
|
/** |
742
|
|
|
* Write unsigned 32-bit integer (long) data to the stream |
743
|
|
|
* |
744
|
|
|
* @param int $value The value |
745
|
|
|
* |
746
|
|
|
* @return int |
747
|
|
|
*/ |
748
|
24 |
|
public function writeUInt32($value) |
749
|
|
|
{ |
750
|
24 |
|
switch ($this->getByteOrder()) { |
751
|
24 |
|
case ByteOrder::BIG_ENDIAN: |
752
|
8 |
|
$format = 'N'; |
753
|
8 |
|
break; |
754
|
16 |
|
case ByteOrder::LITTLE_ENDIAN: |
755
|
8 |
|
$format = 'V'; |
756
|
8 |
|
break; |
757
|
4 |
|
default: |
758
|
8 |
|
$format = 'L'; |
759
|
12 |
|
} |
760
|
|
|
|
761
|
24 |
|
return $this->write(pack($format, $value)); |
762
|
|
|
} |
763
|
|
|
|
764
|
|
|
/** |
765
|
|
|
* Write signed 48-bit integer data to the stream |
766
|
|
|
* |
767
|
|
|
* @param int $value The value |
768
|
|
|
* |
769
|
|
|
* @return int |
770
|
|
|
*/ |
771
|
18 |
|
public function writeInt48($value) |
772
|
|
|
{ |
773
|
18 |
|
if ($value & 0x7fffffffffff) { |
774
|
6 |
|
$value += 0x1000000000000; |
775
|
3 |
|
} |
776
|
|
|
|
777
|
18 |
|
return $this->writeUInt48($value); |
778
|
|
|
} |
779
|
|
|
|
780
|
|
|
/** |
781
|
|
|
* Write unsigned 48-bit integer data to the stream |
782
|
|
|
* |
783
|
|
|
* @param int $value The value |
784
|
|
|
* |
785
|
|
|
* @return int |
786
|
|
|
*/ |
787
|
42 |
|
public function writeUInt48($value) |
788
|
|
|
{ |
789
|
42 |
|
return $this->write($this->alignData( |
790
|
42 |
|
pack('C6', $value, $value >> 8, $value >> 16, $value >> 24, $value >> 32, $value >> 40) |
791
|
21 |
|
)); |
792
|
|
|
} |
793
|
|
|
|
794
|
|
|
/** |
795
|
|
|
* Write signed 64-bit integer (long long) data to the stream |
796
|
|
|
* |
797
|
|
|
* @param int $value The value |
798
|
|
|
* |
799
|
|
|
* @return int |
800
|
|
|
*/ |
801
|
18 |
|
public function writeInt64($value) |
802
|
|
|
{ |
803
|
18 |
|
return $this->write($this->alignData(pack('q', $value))); |
804
|
|
|
} |
805
|
|
|
|
806
|
|
|
/** |
807
|
|
|
* Write unsigned 64-bit integer (long long) data to the stream |
808
|
|
|
* |
809
|
|
|
* @param int $value The value |
810
|
|
|
* |
811
|
|
|
* @return int |
812
|
|
|
*/ |
813
|
24 |
|
public function writeUInt64($value) |
814
|
|
|
{ |
815
|
24 |
|
switch ($this->getByteOrder()) { |
816
|
24 |
|
case ByteOrder::BIG_ENDIAN: |
817
|
8 |
|
$format = 'J'; |
818
|
8 |
|
break; |
819
|
16 |
|
case ByteOrder::LITTLE_ENDIAN: |
820
|
8 |
|
$format = 'P'; |
821
|
8 |
|
break; |
822
|
4 |
|
default: |
823
|
8 |
|
$format = 'Q'; |
824
|
12 |
|
} |
825
|
|
|
|
826
|
24 |
|
return $this->write(pack($format, $value)); |
827
|
|
|
} |
828
|
|
|
|
829
|
|
|
/** |
830
|
|
|
* Truncate the stream to a given length. |
831
|
|
|
* |
832
|
|
|
* @param int $size The size to truncate to. |
833
|
|
|
* |
834
|
|
|
* @throws Exception\BadMethodCallException An exception will be thrown for non-writable streams. |
835
|
|
|
* @throws Exception\IOException An exception will be thrown for invalid stream resources or when the |
836
|
|
|
* stream could not be truncated. |
837
|
|
|
* |
838
|
|
|
* @return bool |
839
|
|
|
* @link http://www.php.net/manual/en/function.ftruncate.php |
840
|
|
|
*/ |
841
|
6 |
|
public function truncate($size) |
842
|
|
|
{ |
843
|
6 |
|
if (!$this->isWritable()) { |
844
|
2 |
|
throw new Exception\BadMethodCallException('Stream not writable'); |
845
|
|
|
} |
846
|
|
|
|
847
|
4 |
|
if (!is_resource($this->resource)) { |
848
|
2 |
|
throw new Exception\IOException('Invalid stream resource'); |
849
|
|
|
} |
850
|
|
|
|
851
|
2 |
|
return @ftruncate($this->resource, $size); |
852
|
|
|
} |
853
|
|
|
|
854
|
|
|
/** |
855
|
|
|
* Close the stream. |
856
|
|
|
* |
857
|
|
|
* @return bool |
858
|
|
|
* @link http://www.php.net/manual/en/function.fclose.php |
859
|
|
|
*/ |
860
|
16 |
|
public function close() |
861
|
|
|
{ |
862
|
16 |
|
return @fclose($this->resource); |
863
|
|
|
} |
864
|
|
|
} |
865
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.