Stream   D
last analyzed

Complexity

Total Complexity 85

Size/Duplication

Total Lines 848
Duplicated Lines 9.67 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 100%

Importance

Changes 14
Bugs 1 Features 6
Metric Value
wmc 85
c 14
b 1
f 6
lcom 1
cbo 4
dl 82
loc 848
ccs 241
cts 241
cp 1
rs 4

45 Methods

Rating   Name   Duplication   Size   Complexity  
A fromResource() 0 10 2
A bindResource() 0 17 2
A isLocal() 0 4 1
A isReadable() 0 4 1
A isWritable() 0 4 1
A isSeekable() 0 4 1
A getUri() 0 4 1
A getStat() 0 15 3
A getSize() 0 8 2
A eof() 0 8 2
A tell() 0 8 2
A seek() 0 16 4
A rewind() 0 4 1
A alignData() 0 10 3
A read() 17 17 4
A readUInt8() 0 5 1
A readInt16() 0 5 1
A readUInt16() 16 16 3
A readUInt24() 0 5 1
A readInt32() 0 5 1
A readInt48() 0 10 2
A readUInt48() 0 5 1
A readInt64() 0 5 1
A write() 17 17 4
A writeUInt8() 0 4 1
A writeInt16() 0 4 1
A writeUInt16() 0 15 3
A writeUInt24() 0 4 1
A writeInt48() 0 8 2
A writeUInt48() 0 6 1
A writeInt64() 0 4 1
A truncate() 0 12 3
A close() 0 4 1
A getByteOrder() 0 8 2
A setByteOrder() 0 10 2
A getMachineByteOrder() 0 13 3
A readInt8() 0 5 1
A readInt24() 0 10 2
A readUInt32() 16 16 3
A readUInt64() 16 16 3
A writeInt8() 0 4 1
A writeInt24() 0 8 2
A writeInt32() 0 4 1
A writeUInt32() 0 15 3
A writeUInt64() 0 15 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Stream often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Stream, and based on these observations, apply Extract Interface, too.

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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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