Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 37
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
RiffExtractor
0.00% covered (danger)
0.00%
0 / 37
0.00% covered (danger)
0.00%
0 / 3
240
0.00% covered (danger)
0.00%
0 / 1
 findChunksFromFile
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 findChunks
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 1
182
 extractUInt32
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * @license GPL-2.0-or-later
4 * @author Bryan Tong Minh
5 */
6
7/**
8 * Extractor for the Resource Interchange File Format
9 *
10 * @ingroup Media
11 */
12class RiffExtractor {
13    /**
14     * @param string $filename
15     * @param int $maxChunks
16     * @return array|false
17     */
18    public static function findChunksFromFile( $filename, $maxChunks = -1 ) {
19        $file = fopen( $filename, 'rb' );
20        $info = self::findChunks( $file, $maxChunks );
21        fclose( $file );
22        return $info;
23    }
24
25    /**
26     * @param resource $file
27     * @param int $maxChunks
28     * @return array|false
29     */
30    public static function findChunks( $file, $maxChunks = -1 ) {
31        $riff = fread( $file, 4 );
32        if ( $riff !== 'RIFF' ) {
33            return false;
34        }
35
36        // Next four bytes are fileSize
37        $fileSize = fread( $file, 4 );
38        if ( !$fileSize || strlen( $fileSize ) != 4 ) {
39            return false;
40        }
41
42        // Next four bytes are the FourCC
43        $fourCC = fread( $file, 4 );
44        if ( !$fourCC || strlen( $fourCC ) != 4 ) {
45            return false;
46        }
47
48        // Create basic info structure
49        $info = [
50            'fileSize' => self::extractUInt32( $fileSize ),
51            'fourCC' => $fourCC,
52            'chunks' => [],
53        ];
54        $numberOfChunks = 0;
55
56        // Find out the chunks
57        while ( !feof( $file ) && !( $numberOfChunks >= $maxChunks && $maxChunks >= 0 ) ) {
58            $chunkStart = ftell( $file );
59
60            $chunkFourCC = fread( $file, 4 );
61            if ( !$chunkFourCC || strlen( $chunkFourCC ) != 4 ) {
62                return $info;
63            }
64
65            $chunkSize = fread( $file, 4 );
66            if ( !$chunkSize || strlen( $chunkSize ) != 4 ) {
67                return $info;
68            }
69            $intChunkSize = self::extractUInt32( $chunkSize );
70
71            // Add chunk info to the info structure
72            $info['chunks'][] = [
73                'fourCC' => $chunkFourCC,
74                'start' => $chunkStart,
75                'size' => $intChunkSize
76            ];
77
78            // Uneven chunks have padding bytes
79            $padding = $intChunkSize % 2;
80            // Seek to the next chunk
81            fseek( $file, $intChunkSize + $padding, SEEK_CUR );
82
83        }
84
85        return $info;
86    }
87
88    /**
89     * Extract a little-endian uint32 from a 4 byte string
90     * @param string $string 4-byte string
91     * @return int
92     */
93    public static function extractUInt32( $string ) {
94        return unpack( 'V', $string )[1];
95    }
96}