getid3_wavpack::Analyze()   F
last analyzed

Complexity

Conditions 83
Paths 19

Size

Total Lines 318
Code Lines 217

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 83
eloc 217
c 1
b 0
f 0
nc 19
nop 0
dl 0
loc 318
rs 3.3333

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
// +----------------------------------------------------------------------+
3
// | PHP version 5                                                        |
4
// +----------------------------------------------------------------------+
5
// | Copyright (c) 2002-2006 James Heinrich, Allan Hansen                 |
6
// +----------------------------------------------------------------------+
7
// | This source file is subject to version 2 of the GPL license,         |
8
// | that is bundled with this package in the file license.txt and is     |
9
// | available through the world-wide-web at the following url:           |
10
// | http://www.gnu.org/copyleft/gpl.html                                 |
11
// +----------------------------------------------------------------------+
12
// | getID3() - http://getid3.sourceforge.net or http://www.getid3.org    |
13
// +----------------------------------------------------------------------+
14
// | Authors: James Heinrich <info�getid3*org>                            |
15
// |          Allan Hansen <ah�artemis*dk>                                |
16
// +----------------------------------------------------------------------+
17
// | module.audio.wavpack.php                                             |
18
// | module for analyzing WavPack v4.0+ Audio files                       |
19
// | dependencies: audio-video.riff                                       |
20
// +----------------------------------------------------------------------+
21
//
22
// $Id: module.audio.wavpack.php,v 1.2 2006/11/02 10:48:02 ah Exp $
23
24
class getid3_wavpack extends getid3_handler
25
{
26
27
    public function Analyze()
28
    {
29
        $getid3 = $this->getid3;
30
31
        $getid3->include_module('audio-video.riff');
32
33
        $getid3->info['wavpack'] = [];
34
        $info_wavpack            = &$getid3->info['wavpack'];
35
36
        fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET);
37
38
        while (true) {
39
            $wavpack_header = fread($getid3->fp, 32);
40
41
            if (ftell($getid3->fp) >= $getid3->info['avdataend']) {
42
                break;
43
            } elseif (feof($getid3->fp)) {
44
                break;
45
            } elseif ((@$info_wavpack_blockheader['total_samples'] > 0)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $info_wavpack_blockheader does not seem to be defined for all execution paths leading up to this point.
Loading history...
46
                      && (@$info_wavpack_blockheader['block_samples'] > 0)
47
                      && (!isset($info_wavpack['riff_trailer_size']) || ($info_wavpack['riff_trailer_size'] <= 0))
48
                      && ((false === @$info_wavpack['config_flags']['md5_checksum']) || !empty($getid3->info['md5_data_source']))) {
49
                break;
50
            }
51
52
            $block_header_offset = ftell($getid3->fp) - 32;
53
            $block_header_magic  = substr($wavpack_header, 0, 4);
54
            $block_header_size   = getid3_lib::LittleEndian2Int(substr($wavpack_header, 4, 4));
55
56
            if ('wvpk' != $block_header_magic) {
57
                throw new getid3_exception('Expecting "wvpk" at offset ' . $block_header_offset . ', found "' . $block_header_magic . '"');
58
            }
59
60
            if ((@$info_wavpack_blockheader['block_samples'] <= 0) || (@$info_wavpack_blockheader['total_samples'] <= 0)) {
61
                // Also, it is possible that the first block might not have
62
                // any samples (block_samples == 0) and in this case you should skip blocks
63
                // until you find one with samples because the other information (like
64
                // total_samples) are not guaranteed to be correct until (block_samples > 0)
65
66
                // Finally, I have defined a format for files in which the length is not known
67
                // (for example when raw files are created using pipes). In these cases
68
                // total_samples will be -1 and you must seek to the final block to determine
69
                // the total number of samples.
70
71
                $getid3->info['audio']['dataformat']   = 'wavpack';
72
                $getid3->info['fileformat']            = 'wavpack';
73
                $getid3->info['audio']['lossless']     = true;
74
                $getid3->info['audio']['bitrate_mode'] = 'vbr';
75
76
                $info_wavpack['blockheader']['offset'] = $block_header_offset;
77
                $info_wavpack['blockheader']['magic']  = $block_header_magic;
78
                $info_wavpack['blockheader']['size']   = $block_header_size;
79
                $info_wavpack_blockheader              = &$info_wavpack['blockheader'];
80
81
                if ($info_wavpack_blockheader['size'] >= 0x100000) {
82
                    throw new getid3_exception('Expecting WavPack block size less than "0x100000", found "' . $info_wavpack_blockheader['size'] . '" at offset ' . $info_wavpack_blockheader['offset']);
83
                }
84
85
                $info_wavpack_blockheader['minor_version'] = ord($wavpack_header{8});
86
                $info_wavpack_blockheader['major_version'] = ord($wavpack_header{9});
87
88
                if ((4 != $info_wavpack_blockheader['major_version'])
89
                    || (($info_wavpack_blockheader['minor_version'] < 4)
90
                        && ($info_wavpack_blockheader['minor_version'] > 16))) {
91
                    throw new getid3_exception('Expecting WavPack version between "4.2" and "4.16", found version "' . $info_wavpack_blockheader['major_version'] . '.' . $info_wavpack_blockheader['minor_version'] . '" at offset ' . $info_wavpack_blockheader['offset']);
92
                }
93
94
                $info_wavpack_blockheader['track_number'] = ord($wavpack_header{10}); // unused
95
                $info_wavpack_blockheader['index_number'] = ord($wavpack_header{11}); // unused
96
97
                getid3_lib::ReadSequence(
98
                    'LittleEndian2Int',
99
                    $info_wavpack_blockheader,
100
                    $wavpack_header,
101
                    12,
102
                    [
103
                        'total_samples' => 4,
104
                        'block_index'   => 4,
105
                        'block_samples' => 4,
106
                        'flags_raw'     => 4,
107
                        'crc'           => 4
108
                    ]
109
                );
110
111
                $info_wavpack_blockheader['flags']['bytes_per_sample']     = 1 + ($info_wavpack_blockheader['flags_raw'] & 0x00000003);
112
                $info_wavpack_blockheader['flags']['mono']                 = (bool)($info_wavpack_blockheader['flags_raw'] & 0x00000004);
113
                $info_wavpack_blockheader['flags']['hybrid']               = (bool)($info_wavpack_blockheader['flags_raw'] & 0x00000008);
114
                $info_wavpack_blockheader['flags']['joint_stereo']         = (bool)($info_wavpack_blockheader['flags_raw'] & 0x00000010);
115
                $info_wavpack_blockheader['flags']['cross_decorrelation']  = (bool)($info_wavpack_blockheader['flags_raw'] & 0x00000020);
116
                $info_wavpack_blockheader['flags']['hybrid_noiseshape']    = (bool)($info_wavpack_blockheader['flags_raw'] & 0x00000040);
117
                $info_wavpack_blockheader['flags']['ieee_32bit_float']     = (bool)($info_wavpack_blockheader['flags_raw'] & 0x00000080);
118
                $info_wavpack_blockheader['flags']['int_32bit']            = (bool)($info_wavpack_blockheader['flags_raw'] & 0x00000100);
119
                $info_wavpack_blockheader['flags']['hybrid_bitrate_noise'] = (bool)($info_wavpack_blockheader['flags_raw'] & 0x00000200);
120
                $info_wavpack_blockheader['flags']['hybrid_balance_noise'] = (bool)($info_wavpack_blockheader['flags_raw'] & 0x00000400);
121
                $info_wavpack_blockheader['flags']['multichannel_initial'] = (bool)($info_wavpack_blockheader['flags_raw'] & 0x00000800);
122
                $info_wavpack_blockheader['flags']['multichannel_final']   = (bool)($info_wavpack_blockheader['flags_raw'] & 0x00001000);
123
124
                $getid3->info['audio']['lossless'] = !$info_wavpack_blockheader['flags']['hybrid'];
125
            }
126
127
            while (!feof($getid3->fp) && (ftell($getid3->fp) < ($block_header_offset + $block_header_size + 8))) {
128
                $metablock       = ['offset' => ftell($getid3->fp)];
129
                $metablockheader = fread($getid3->fp, 2);
130
                if (feof($getid3->fp)) {
131
                    break;
132
                }
133
                $metablock['id']            = ord($metablockheader{0});
134
                $metablock['function_id']   = ($metablock['id'] & 0x3F);
135
                $metablock['function_name'] = $this->WavPackMetablockNameLookup($metablock['function_id']);
136
137
                // The 0x20 bit in the id of the meta subblocks (which is defined as
138
                // ID_OPTIONAL_DATA) is a permanent part of the id. The idea is that
139
                // if a decoder encounters an id that it does not know about, it uses
140
                // that "ID_OPTIONAL_DATA" flag to determine what to do. If it is set
141
                // then the decoder simply ignores the metadata, but if it is zero
142
                // then the decoder should quit because it means that an understanding
143
                // of the metadata is required to correctly decode the audio.
144
145
                $metablock['non_decoder'] = (bool)($metablock['id'] & 0x20);
146
                $metablock['padded_data'] = (bool)($metablock['id'] & 0x40);
147
                $metablock['large_block'] = (bool)($metablock['id'] & 0x80);
148
                if ($metablock['large_block']) {
149
                    $metablockheader .= fread($getid3->fp, 2);
150
                }
151
                $metablock['size'] = getid3_lib::LittleEndian2Int(substr($metablockheader, 1)) * 2; // size is stored in words
152
                $metablock['data'] = null;
153
154
                if ($metablock['size'] > 0) {
155
                    switch ($metablock['function_id']) {
156
                        case 0x21: // ID_RIFF_HEADER
157
                        case 0x22: // ID_RIFF_TRAILER
158
                        case 0x23: // ID_REPLAY_GAIN
159
                        case 0x24: // ID_CUESHEET
160
                        case 0x25: // ID_CONFIG_BLOCK
161
                        case 0x26: // ID_MD5_CHECKSUM
162
                            $metablock['data'] = fread($getid3->fp, $metablock['size']);
163
164
                            if ($metablock['padded_data']) {
165
                                // padded to the nearest even byte
166
                                $metablock['size']--;
167
                                $metablock['data'] = substr($metablock['data'], 0, -1);
168
                            }
169
                            break;
170
171
                        case 0x00: // ID_DUMMY
172
                        case 0x01: // ID_ENCODER_INFO
173
                        case 0x02: // ID_DECORR_TERMS
174
                        case 0x03: // ID_DECORR_WEIGHTS
175
                        case 0x04: // ID_DECORR_SAMPLES
176
                        case 0x05: // ID_ENTROPY_VARS
177
                        case 0x06: // ID_HYBRID_PROFILE
178
                        case 0x07: // ID_SHAPING_WEIGHTS
179
                        case 0x08: // ID_FLOAT_INFO
180
                        case 0x09: // ID_INT32_INFO
181
                        case 0x0A: // ID_WV_BITSTREAM
182
                        case 0x0B: // ID_WVC_BITSTREAM
183
                        case 0x0C: // ID_WVX_BITSTREAM
184
                        case 0x0D: // ID_CHANNEL_INFO
185
                            fseek($getid3->fp, $metablock['offset'] + ($metablock['large_block'] ? 4 : 2) + $metablock['size'], SEEK_SET);
186
                            break;
187
188
                        default:
189
                            $getid3->warning('Unexpected metablock type "0x' . str_pad(dechex($metablock['function_id']), 2, '0', STR_PAD_LEFT) . '" at offset ' . $metablock['offset']);
190
                            fseek($getid3->fp, $metablock['offset'] + ($metablock['large_block'] ? 4 : 2) + $metablock['size'], SEEK_SET);
191
                            break;
192
                    }
193
194
                    switch ($metablock['function_id']) {
195
                        case 0x21: // ID_RIFF_HEADER
196
197
                            $original_wav_filesize = getid3_lib::LittleEndian2Int(substr($metablock['data'], 4, 4));
198
199
                            // Clone getid3 
200
                            $clone = clone $getid3;
201
202
                            // Analyze clone by string
203
                            $riff = new getid3_riff($clone);
204
                            $riff->AnalyzeString($metablock['data']);
205
206
                            // Import from clone and destroy
207
                            $metablock['riff'] = $clone->info['riff'];
208
                            $getid3->warnings($clone->warnings());
0 ignored issues
show
Unused Code introduced by
The call to getid3::warnings() has too many arguments starting with $clone->warnings(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

208
                            $getid3->/** @scrutinizer ignore-call */ 
209
                                     warnings($clone->warnings());

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
209
                            unset($clone);
210
211
                            // Save RIFF header - we may need it later for RIFF footer parsing
212
                            $this->riff_header = $metablock['data'];
0 ignored issues
show
Bug Best Practice introduced by
The property riff_header does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
213
214
                            $metablock['riff']['original_filesize'] = $original_wav_filesize;
215
                            $info_wavpack['riff_trailer_size']      = $original_wav_filesize - $metablock['riff']['WAVE']['data'][0]['size'] - $metablock['riff']['header_size'];
216
217
                            $getid3->info['audio']['sample_rate'] = $metablock['riff']['raw']['fmt ']['nSamplesPerSec'];
218
                            $getid3->info['playtime_seconds']     = $info_wavpack_blockheader['total_samples'] / $getid3->info['audio']['sample_rate'];
219
220
                            // Safe RIFF header in case there's a RIFF footer later
221
                            $metablock_riff_header = $metablock['data'];
222
                            break;
223
224
                        case 0x22: // ID_RIFF_TRAILER
225
226
                            $metablock_riff_footer = $metablock_riff_header . $metablock['data'];
0 ignored issues
show
Unused Code introduced by
The assignment to $metablock_riff_footer is dead and can be removed.
Loading history...
Comprehensibility Best Practice introduced by
The variable $metablock_riff_header does not seem to be defined for all execution paths leading up to this point.
Loading history...
227
228
                            $start_offset = $metablock['offset'] + ($metablock['large_block'] ? 4 : 2);
229
230
                            $ftell_old = ftell($getid3->fp);
231
232
                            // Clone getid3 
233
                            $clone = clone $getid3;
234
235
                            // Call public method that really should be private
236
                            $riff              = new getid3_riff($clone);
237
                            $metablock['riff'] = $riff->ParseRIFF($start_offset, $start_offset + $metablock['size']);
238
                            unset($clone);
239
240
                            fseek($getid3->fp, $ftell_old, SEEK_SET);
241
242
                            if (!empty($metablock['riff']['INFO'])) {
243
                                getid3_riff::RIFFCommentsParse($metablock['riff']['INFO'], $metablock['comments']);
244
                                $getid3->info['tags']['riff'] = $metablock['comments'];
245
                            }
246
                            break;
247
248
                        case 0x23: // ID_REPLAY_GAIN
249
                            $getid3->warning('WavPack "Replay Gain" contents not yet handled by getID3() in metablock at offset ' . $metablock['offset']);
250
                            break;
251
252
                        case 0x24: // ID_CUESHEET
253
                            $getid3->warning('WavPack "Cuesheet" contents not yet handled by getID3() in metablock at offset ' . $metablock['offset']);
254
                            break;
255
256
                        case 0x25: // ID_CONFIG_BLOCK
257
                            $metablock['flags_raw'] = getid3_lib::LittleEndian2Int(substr($metablock['data'], 0, 3));
258
259
                            $metablock['flags']['adobe_mode']     = (bool)($metablock['flags_raw'] & 0x000001); // "adobe" mode for 32-bit floats
260
                            $metablock['flags']['fast_flag']      = (bool)($metablock['flags_raw'] & 0x000002); // fast mode
261
                            $metablock['flags']['very_fast_flag'] = (bool)($metablock['flags_raw'] & 0x000004); // double fast
262
                            $metablock['flags']['high_flag']      = (bool)($metablock['flags_raw'] & 0x000008); // high quality mode
263
                            $metablock['flags']['very_high_flag'] = (bool)($metablock['flags_raw'] & 0x000010); // double high (not used yet)
264
                            $metablock['flags']['bitrate_kbps']   = (bool)($metablock['flags_raw'] & 0x000020); // bitrate is kbps, not bits / sample
265
                            $metablock['flags']['auto_shaping']   = (bool)($metablock['flags_raw'] & 0x000040); // automatic noise shaping
266
                            $metablock['flags']['shape_override'] = (bool)($metablock['flags_raw'] & 0x000080); // shaping mode specified
267
                            $metablock['flags']['joint_override'] = (bool)($metablock['flags_raw'] & 0x000100); // joint-stereo mode specified
268
                            $metablock['flags']['copy_time']      = (bool)($metablock['flags_raw'] & 0x000200); // copy file-time from source
269
                            $metablock['flags']['create_exe']     = (bool)($metablock['flags_raw'] & 0x000400); // create executable
270
                            $metablock['flags']['create_wvc']     = (bool)($metablock['flags_raw'] & 0x000800); // create correction file
271
                            $metablock['flags']['optimize_wvc']   = (bool)($metablock['flags_raw'] & 0x001000); // maximize bybrid compression
272
                            $metablock['flags']['quality_mode']   = (bool)($metablock['flags_raw'] & 0x002000); // psychoacoustic quality mode
273
                            $metablock['flags']['raw_flag']       = (bool)($metablock['flags_raw'] & 0x004000); // raw mode (not implemented yet)
274
                            $metablock['flags']['calc_noise']     = (bool)($metablock['flags_raw'] & 0x008000); // calc noise in hybrid mode
275
                            $metablock['flags']['lossy_mode']     = (bool)($metablock['flags_raw'] & 0x010000); // obsolete (for information)
276
                            $metablock['flags']['extra_mode']     = (bool)($metablock['flags_raw'] & 0x020000); // extra processing mode
277
                            $metablock['flags']['skip_wvx']       = (bool)($metablock['flags_raw'] & 0x040000); // no wvx stream w/ floats & big ints
278
                            $metablock['flags']['md5_checksum']   = (bool)($metablock['flags_raw'] & 0x080000); // compute & store MD5 signature
279
                            $metablock['flags']['quiet_mode']     = (bool)($metablock['flags_raw'] & 0x100000); // don't report progress %
280
281
                            $info_wavpack['config_flags'] = $metablock['flags'];
282
283
                            $getid3->info['audio']['encoder_options'] = trim(
284
                                ($info_wavpack_blockheader['flags']['hybrid'] ? ' -b???' : '')
285
                                . ($metablock['flags']['adobe_mode'] ? ' -a' : '')
286
                                . ($metablock['flags']['optimize_wvc'] ? ' -cc' : '')
287
                                . ($metablock['flags']['create_exe'] ? ' -e' : '')
288
                                . ($metablock['flags']['fast_flag'] ? ' -f' : '')
289
                                . ($metablock['flags']['joint_override'] ? ' -j?' : '')
290
                                . ($metablock['flags']['high_flag'] ? ' -h' : '')
291
                                . ($metablock['flags']['md5_checksum'] ? ' -m' : '')
292
                                . ($metablock['flags']['calc_noise'] ? ' -n' : '')
293
                                . ($metablock['flags']['shape_override'] ? ' -s?' : '')
294
                                . ($metablock['flags']['extra_mode'] ? ' -x?' : '')
295
                            );
296
                            if (!$getid3->info['audio']['encoder_options']) {
297
                                unset($getid3->info['audio']['encoder_options']);
298
                            }
299
                            break;
300
301
                        case 0x26: // ID_MD5_CHECKSUM
302
                            if (16 == strlen($metablock['data'])) {
303
                                $getid3->info['md5_data_source'] = strtolower(getid3_lib::PrintHexBytes($metablock['data'], true, false, false));
304
                            } else {
305
                                $getid3->warning('Expecting 16 bytes of WavPack "MD5 Checksum" in metablock at offset ' . $metablock['offset'] . ', but found ' . strlen($metablock['data']) . ' bytes');
306
                            }
307
                            break;
308
309
                        case 0x00: // ID_DUMMY
310
                        case 0x01: // ID_ENCODER_INFO
311
                        case 0x02: // ID_DECORR_TERMS
312
                        case 0x03: // ID_DECORR_WEIGHTS
313
                        case 0x04: // ID_DECORR_SAMPLES
314
                        case 0x05: // ID_ENTROPY_VARS
315
                        case 0x06: // ID_HYBRID_PROFILE
316
                        case 0x07: // ID_SHAPING_WEIGHTS
317
                        case 0x08: // ID_FLOAT_INFO
318
                        case 0x09: // ID_INT32_INFO
319
                        case 0x0A: // ID_WV_BITSTREAM
320
                        case 0x0B: // ID_WVC_BITSTREAM
321
                        case 0x0C: // ID_WVX_BITSTREAM
322
                        case 0x0D: // ID_CHANNEL_INFO
323
                            unset($metablock);
324
                            break;
325
                    }
326
                }
327
328
                if (!empty($metablock)) {
329
                    $info_wavpack['metablocks'][] = $metablock;
330
                }
331
            }
332
        }
333
334
        $getid3->info['audio']['encoder']         = 'WavPack v' . $info_wavpack_blockheader['major_version'] . '.' . str_pad($info_wavpack_blockheader['minor_version'], 2, '0', STR_PAD_LEFT);
335
        $getid3->info['audio']['bits_per_sample'] = $info_wavpack_blockheader['flags']['bytes_per_sample'] * 8;
336
        $getid3->info['audio']['channels']        = ($info_wavpack_blockheader['flags']['mono'] ? 1 : 2);
337
338
        if (@$getid3->info['playtime_seconds']) {
339
            $getid3->info['audio']['bitrate'] = (($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8) / $getid3->info['playtime_seconds'];
340
        } else {
341
            $getid3->info['audio']['dataformat'] = 'wvc';
342
        }
343
344
        return true;
345
    }
346
347
    public static function WavPackMetablockNameLookup($id)
348
    {
349
        static $lookup = [
350
            0x00 => 'Dummy',
351
            0x01 => 'Encoder Info',
352
            0x02 => 'Decorrelation Terms',
353
            0x03 => 'Decorrelation Weights',
354
            0x04 => 'Decorrelation Samples',
355
            0x05 => 'Entropy Variables',
356
            0x06 => 'Hybrid Profile',
357
            0x07 => 'Shaping Weights',
358
            0x08 => 'Float Info',
359
            0x09 => 'Int32 Info',
360
            0x0A => 'WV Bitstream',
361
            0x0B => 'WVC Bitstream',
362
            0x0C => 'WVX Bitstream',
363
            0x0D => 'Channel Info',
364
            0x21 => 'RIFF header',
365
            0x22 => 'RIFF trailer',
366
            0x23 => 'Replay Gain',
367
            0x24 => 'Cuesheet',
368
            0x25 => 'Config Block',
369
            0x26 => 'MD5 Checksum',
370
        ];
371
372
        return (@$lookup[$id]);
373
    }
374
375
}
376
377
378