Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
StreamReader
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 6
182
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 tell
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 pos
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 seek
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 read
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 write
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2/**
3 * Base class for streaming media segment readers
4 *
5 * @file
6 * @ingroup HLS
7 */
8
9namespace MediaWiki\TimedMediaHandler\HLS;
10
11use InvalidArgumentException;
12use RuntimeException;
13
14/**
15 * Base class for reading/writing a media file with wrappers
16 * for exception handling and possible multi usage.
17 */
18class StreamReader {
19    /**
20     * @var resource
21     */
22    protected $file;
23
24    protected int $pos;
25
26    /**
27     * @param resource $file
28     */
29    public function __construct( $file ) {
30        if ( get_resource_type( $file ) !== 'stream' ) {
31            throw new InvalidArgumentException( 'Invalid file stream' );
32        }
33        $this->file = $file;
34        $this->pos = $this->tell();
35    }
36
37    private function tell(): int {
38        return ftell( $this->file );
39    }
40
41    public function pos(): int {
42        return $this->pos;
43    }
44
45    /**
46     * Seek to given absolute file position.
47     */
48    public function seek( int $pos ): void {
49        $this->pos = $pos;
50
51        if ( $this->pos === $this->tell() ) {
52            return;
53        }
54        $retval = fseek( $this->file, $this->pos, SEEK_SET );
55
56        if ( $retval < 0 ) {
57            throw new RuntimeException( "Failed to seek to $this->pos bytes" );
58        }
59    }
60
61    /**
62     * Read $len bytes or throw on EOF/short read.
63     * @throws ShortReadException on end of file
64     */
65    public function read( int $len ): string {
66        $this->seek( $this->pos );
67        $bytes = fread( $this->file, $len );
68        if ( $bytes === false ) {
69            throw new RuntimeException( "Read error for $len bytes at $this->pos" );
70        }
71        if ( strlen( $bytes ) < $len ) {
72            throw new ShortReadException( $bytes );
73        }
74        $this->pos += strlen( $bytes );
75        return $bytes;
76    }
77
78    /**
79     * Write the given data to the stream.
80     */
81    public function write( string $bytes ) {
82        $this->seek( $this->pos );
83        $len = strlen( $bytes );
84        $nbytes = fwrite( $this->file, $bytes );
85        if ( $nbytes === false ) {
86            throw new RuntimeException( "Write error for $len bytes at $this->pos" );
87        }
88        if ( $nbytes < $len ) {
89            throw new RuntimeException( "Short write; unexpected filesystem error" );
90        }
91        $this->pos += $nbytes;
92    }
93}