Completed
Push — vendor/getid3 ( 69b815...49c253 )
by Pauli
04:26 queued 01:37
created

CopyToAppropriateCommentsSection()   F

Complexity

Conditions 18
Paths 120

Size

Total Lines 138

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 18
nc 120
nop 3
dl 0
loc 138
rs 3.76
c 0
b 0
f 0

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
/////////////////////////////////////////////////////////////////
4
/// getID3() by James Heinrich <[email protected]>               //
5
//  available at https://github.com/JamesHeinrich/getID3       //
6
//            or https://www.getid3.org                        //
7
//            or http://getid3.sourceforge.net                 //
8
//  see readme.txt for more details                            //
9
/////////////////////////////////////////////////////////////////
10
//                                                             //
11
// module.audio-video.quicktime.php                            //
12
// module for analyzing Quicktime and MP3-in-MP4 files         //
13
// dependencies: module.audio.mp3.php                          //
14
// dependencies: module.tag.id3v2.php                          //
15
//                                                            ///
16
/////////////////////////////////////////////////////////////////
17
18
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
19
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); // needed for ISO 639-2 language code lookup
20
21
class getid3_quicktime extends getid3_handler
22
{
23
24
	public $ReturnAtomData        = true;
25
	public $ParseAllPossibleAtoms = false;
26
27
	/**
28
	 * @return bool
29
	 */
30
	public function Analyze() {
31
		$info = &$this->getid3->info;
32
33
		$info['fileformat'] = 'quicktime';
34
		$info['quicktime']['hinting']    = false;
35
		$info['quicktime']['controller'] = 'standard'; // may be overridden if 'ctyp' atom is present
36
37
		$this->fseek($info['avdataoffset']);
38
39
		$offset      = 0;
40
		$atomcounter = 0;
41
		$atom_data_read_buffer_size = $info['php_memory_limit'] ? round($info['php_memory_limit'] / 4) : $this->getid3->option_fread_buffer_size * 1024; // set read buffer to 25% of PHP memory limit (if one is specified), otherwise use option_fread_buffer_size [default: 32MB]
42
		while ($offset < $info['avdataend']) {
43
			if (!getid3_lib::intValueSupported($offset)) {
44
				$this->error('Unable to parse atom at offset '.$offset.' because beyond '.round(PHP_INT_MAX / 1073741824).'GB limit of PHP filesystem functions');
45
				break;
46
			}
47
			$this->fseek($offset);
48
			$AtomHeader = $this->fread(8);
49
50
			$atomsize = getid3_lib::BigEndian2Int(substr($AtomHeader, 0, 4));
51
			$atomname = substr($AtomHeader, 4, 4);
52
53
			// 64-bit MOV patch by jlegateØktnc*com
54
			if ($atomsize == 1) {
55
				$atomsize = getid3_lib::BigEndian2Int($this->fread(8));
0 ignored issues
show
Security Bug introduced by
It seems like $this->fread(8) targeting getid3_handler::fread() can also be of type false; however, getid3_lib::BigEndian2Int() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
56
			}
57
58
			$info['quicktime'][$atomname]['name']   = $atomname;
59
			$info['quicktime'][$atomname]['size']   = $atomsize;
60
			$info['quicktime'][$atomname]['offset'] = $offset;
61
62
			if (($offset + $atomsize) > $info['avdataend']) {
63
				$this->error('Atom at offset '.$offset.' claims to go beyond end-of-file (length: '.$atomsize.' bytes)');
64
				return false;
65
			}
66
67
			if ($atomsize == 0) {
68
				// Furthermore, for historical reasons the list of atoms is optionally
69
				// terminated by a 32-bit integer set to 0. If you are writing a program
70
				// to read user data atoms, you should allow for the terminating 0.
71
				break;
72
			}
73
			$atomHierarchy = array();
74
			$info['quicktime'][$atomname] = $this->QuicktimeParseAtom($atomname, $atomsize, $this->fread(min($atomsize, $atom_data_read_buffer_size)), $offset, $atomHierarchy, $this->ParseAllPossibleAtoms);
0 ignored issues
show
Bug introduced by
It seems like min($atomsize, $atom_data_read_buffer_size) targeting min() can also be of type double or false; however, getid3_handler::fread() does only seem to accept integer, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
Bug introduced by
It seems like $atomsize can also be of type double or false; however, getid3_quicktime::QuicktimeParseAtom() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Security Bug introduced by
It seems like $this->fread(min($atomsi...data_read_buffer_size)) targeting getid3_handler::fread() can also be of type false; however, getid3_quicktime::QuicktimeParseAtom() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
75
76
			$offset += $atomsize;
77
			$atomcounter++;
78
		}
79
80
		if (!empty($info['avdataend_tmp'])) {
81
			// this value is assigned to a temp value and then erased because
82
			// otherwise any atoms beyond the 'mdat' atom would not get parsed
83
			$info['avdataend'] = $info['avdataend_tmp'];
84
			unset($info['avdataend_tmp']);
85
		}
86
87
		if (!empty($info['quicktime']['comments']['chapters']) && is_array($info['quicktime']['comments']['chapters']) && (count($info['quicktime']['comments']['chapters']) > 0)) {
88
			$durations = $this->quicktime_time_to_sample_table($info);
89
			for ($i = 0; $i < count($info['quicktime']['comments']['chapters']); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
90
				$bookmark = array();
91
				$bookmark['title'] = $info['quicktime']['comments']['chapters'][$i];
92
				if (isset($durations[$i])) {
93
					$bookmark['duration_sample'] = $durations[$i]['sample_duration'];
94
					if ($i > 0) {
95
						$bookmark['start_sample'] = $info['quicktime']['bookmarks'][($i - 1)]['start_sample'] + $info['quicktime']['bookmarks'][($i - 1)]['duration_sample'];
96
					} else {
97
						$bookmark['start_sample'] = 0;
98
					}
99
					if ($time_scale = $this->quicktime_bookmark_time_scale($info)) {
100
						$bookmark['duration_seconds'] = $bookmark['duration_sample'] / $time_scale;
101
						$bookmark['start_seconds']    = $bookmark['start_sample']    / $time_scale;
102
					}
103
				}
104
				$info['quicktime']['bookmarks'][] = $bookmark;
105
			}
106
		}
107
108
		if (isset($info['quicktime']['temp_meta_key_names'])) {
109
			unset($info['quicktime']['temp_meta_key_names']);
110
		}
111
112
		if (!empty($info['quicktime']['comments']['location.ISO6709'])) {
113
			// https://en.wikipedia.org/wiki/ISO_6709
114
			foreach ($info['quicktime']['comments']['location.ISO6709'] as $ISO6709string) {
115
				$ISO6709parsed = array('latitude'=>false, 'longitude'=>false, 'altitude'=>false);
116
				if (preg_match('#^([\\+\\-])([0-9]{2}|[0-9]{4}|[0-9]{6})(\\.[0-9]+)?([\\+\\-])([0-9]{3}|[0-9]{5}|[0-9]{7})(\\.[0-9]+)?(([\\+\\-])([0-9]{3}|[0-9]{5}|[0-9]{7})(\\.[0-9]+)?)?/$#', $ISO6709string, $matches)) {
117
					@list($dummy, $lat_sign, $lat_deg, $lat_deg_dec, $lon_sign, $lon_deg, $lon_deg_dec, $dummy, $alt_sign, $alt_deg, $alt_deg_dec) = $matches;
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
118
119 View Code Duplication
					if (strlen($lat_deg) == 2) {        // [+-]DD.D
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
120
						$ISO6709parsed['latitude'] = (($lat_sign == '-') ? -1 : 1) * floatval(ltrim($lat_deg, '0').$lat_deg_dec);
121
					} elseif (strlen($lat_deg) == 4) {  // [+-]DDMM.M
122
						$ISO6709parsed['latitude'] = (($lat_sign == '-') ? -1 : 1) * floatval(ltrim(substr($lat_deg, 0, 2), '0')) + floatval(ltrim(substr($lat_deg, 2, 2), '0').$lat_deg_dec / 60);
123
					} elseif (strlen($lat_deg) == 6) {  // [+-]DDMMSS.S
124
						$ISO6709parsed['latitude'] = (($lat_sign == '-') ? -1 : 1) * floatval(ltrim(substr($lat_deg, 0, 2), '0')) + floatval(ltrim(substr($lat_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($lat_deg, 4, 2), '0').$lat_deg_dec / 3600);
125
					}
126
127 View Code Duplication
					if (strlen($lon_deg) == 3) {        // [+-]DDD.D
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
128
						$ISO6709parsed['longitude'] = (($lon_sign == '-') ? -1 : 1) * floatval(ltrim($lon_deg, '0').$lon_deg_dec);
129
					} elseif (strlen($lon_deg) == 5) {  // [+-]DDDMM.M
130
						$ISO6709parsed['longitude'] = (($lon_sign == '-') ? -1 : 1) * floatval(ltrim(substr($lon_deg, 0, 2), '0')) + floatval(ltrim(substr($lon_deg, 2, 2), '0').$lon_deg_dec / 60);
131
					} elseif (strlen($lon_deg) == 7) {  // [+-]DDDMMSS.S
132
						$ISO6709parsed['longitude'] = (($lon_sign == '-') ? -1 : 1) * floatval(ltrim(substr($lon_deg, 0, 2), '0')) + floatval(ltrim(substr($lon_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($lon_deg, 4, 2), '0').$lon_deg_dec / 3600);
133
					}
134
135 View Code Duplication
					if (strlen($alt_deg) == 3) {        // [+-]DDD.D
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
136
						$ISO6709parsed['altitude'] = (($alt_sign == '-') ? -1 : 1) * floatval(ltrim($alt_deg, '0').$alt_deg_dec);
137
					} elseif (strlen($alt_deg) == 5) {  // [+-]DDDMM.M
138
						$ISO6709parsed['altitude'] = (($alt_sign == '-') ? -1 : 1) * floatval(ltrim(substr($alt_deg, 0, 2), '0')) + floatval(ltrim(substr($alt_deg, 2, 2), '0').$alt_deg_dec / 60);
139
					} elseif (strlen($alt_deg) == 7) {  // [+-]DDDMMSS.S
140
						$ISO6709parsed['altitude'] = (($alt_sign == '-') ? -1 : 1) * floatval(ltrim(substr($alt_deg, 0, 2), '0')) + floatval(ltrim(substr($alt_deg, 2, 2), '0') / 60) + floatval(ltrim(substr($alt_deg, 4, 2), '0').$alt_deg_dec / 3600);
141
					}
142
143
					foreach (array('latitude', 'longitude', 'altitude') as $key) {
144
						if ($ISO6709parsed[$key] !== false) {
145
							$value = (($lat_sign == '-') ? -1 : 1) * floatval($ISO6709parsed[$key]);
146
							if (!in_array($value, $info['quicktime']['comments']['gps_'.$key])) {
147
								$info['quicktime']['comments']['gps_'.$key][]  = (($lat_sign == '-') ? -1 : 1) * floatval($ISO6709parsed[$key]);
148
							}
149
						}
150
					}
151
				}
152
				if ($ISO6709parsed['latitude'] === false) {
153
					$this->warning('location.ISO6709 string not parsed correctly: "'.$ISO6709string.'", please submit as a bug');
154
				}
155
				break;
156
			}
157
		}
158
159 View Code Duplication
		if (!isset($info['bitrate']) && isset($info['playtime_seconds'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
160
			$info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
161
		}
162
		if (isset($info['bitrate']) && !isset($info['audio']['bitrate']) && !isset($info['quicktime']['video'])) {
163
			$info['audio']['bitrate'] = $info['bitrate'];
164
		}
165
		if (!empty($info['bitrate']) && !empty($info['audio']['bitrate']) && empty($info['video']['bitrate']) && !empty($info['video']['frame_rate']) && !empty($info['video']['resolution_x']) && ($info['bitrate'] > $info['audio']['bitrate'])) {
166
			$info['video']['bitrate'] = $info['bitrate'] - $info['audio']['bitrate'];
167
		}
168
		if (!empty($info['playtime_seconds']) && !isset($info['video']['frame_rate']) && !empty($info['quicktime']['stts_framecount'])) {
169
			foreach ($info['quicktime']['stts_framecount'] as $key => $samples_count) {
170
				$samples_per_second = $samples_count / $info['playtime_seconds'];
171
				if ($samples_per_second > 240) {
172
					// has to be audio samples
173
				} else {
174
					$info['video']['frame_rate'] = $samples_per_second;
175
					break;
176
				}
177
			}
178
		}
179
		if ($info['audio']['dataformat'] == 'mp4') {
180
			$info['fileformat'] = 'mp4';
181
			if (empty($info['video']['resolution_x'])) {
182
				$info['mime_type']  = 'audio/mp4';
183
				unset($info['video']['dataformat']);
184
			} else {
185
				$info['mime_type']  = 'video/mp4';
186
			}
187
		}
188
189
		if (!$this->ReturnAtomData) {
190
			unset($info['quicktime']['moov']);
191
		}
192
193 View Code Duplication
		if (empty($info['audio']['dataformat']) && !empty($info['quicktime']['audio'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
194
			$info['audio']['dataformat'] = 'quicktime';
195
		}
196 View Code Duplication
		if (empty($info['video']['dataformat']) && !empty($info['quicktime']['video'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
197
			$info['video']['dataformat'] = 'quicktime';
198
		}
199
		if (isset($info['video']) && ($info['mime_type'] == 'audio/mp4') && empty($info['video']['resolution_x']) && empty($info['video']['resolution_y']))  {
200
			unset($info['video']);
201
		}
202
203
		return true;
204
	}
205
206
	/**
207
	 * @param string $atomname
208
	 * @param int    $atomsize
209
	 * @param string $atom_data
210
	 * @param int    $baseoffset
211
	 * @param array  $atomHierarchy
212
	 * @param bool   $ParseAllPossibleAtoms
213
	 *
214
	 * @return array|false
215
	 */
216
	public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
217
		// http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm
218
		// https://code.google.com/p/mp4v2/wiki/iTunesMetadata
219
220
		$info = &$this->getid3->info;
221
222
		$atom_parent = end($atomHierarchy); // not array_pop($atomHierarchy); see https://www.getid3.org/phpBB3/viewtopic.php?t=1717
223
		array_push($atomHierarchy, $atomname);
224
		$atom_structure              = array();
225
		$atom_structure['hierarchy'] = implode(' ', $atomHierarchy);
226
		$atom_structure['name']      = $atomname;
227
		$atom_structure['size']      = $atomsize;
228
		$atom_structure['offset']    = $baseoffset;
229
		if (substr($atomname, 0, 3) == "\x00\x00\x00") {
230
			// https://github.com/JamesHeinrich/getID3/issues/139
231
			$atomname = getid3_lib::BigEndian2Int($atomname);
232
			$atom_structure['name'] = $atomname;
233
			$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
234
		} else {
235
			switch ($atomname) {
236
				case 'moov': // MOVie container atom
237
				case 'trak': // TRAcK container atom
238
				case 'clip': // CLIPping container atom
239
				case 'matt': // track MATTe container atom
240
				case 'edts': // EDiTS container atom
241
				case 'tref': // Track REFerence container atom
242
				case 'mdia': // MeDIA container atom
243
				case 'minf': // Media INFormation container atom
244
				case 'dinf': // Data INFormation container atom
245
				case 'nmhd': // Null Media HeaDer container atom
246
				case 'udta': // User DaTA container atom
247
				case 'cmov': // Compressed MOVie container atom
248
				case 'rmra': // Reference Movie Record Atom
249
				case 'rmda': // Reference Movie Descriptor Atom
250
				case 'gmhd': // Generic Media info HeaDer atom (seen on QTVR)
251
					$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
252
					break;
253
254
				case 'ilst': // Item LiST container atom
255
					if ($atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms)) {
256
						// some "ilst" atoms contain data atoms that have a numeric name, and the data is far more accessible if the returned array is compacted
257
						$allnumericnames = true;
258
						foreach ($atom_structure['subatoms'] as $subatomarray) {
0 ignored issues
show
Bug introduced by
The expression $atom_structure['subatoms'] of type array|false is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
259
							if (!is_integer($subatomarray['name']) || (count($subatomarray['subatoms']) != 1)) {
260
								$allnumericnames = false;
261
								break;
262
							}
263
						}
264
						if ($allnumericnames) {
265
							$newData = array();
266
							foreach ($atom_structure['subatoms'] as $subatomarray) {
0 ignored issues
show
Bug introduced by
The expression $atom_structure['subatoms'] of type array|false is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
267
								foreach ($subatomarray['subatoms'] as $newData_subatomarray) {
268
									unset($newData_subatomarray['hierarchy'], $newData_subatomarray['name']);
269
									$newData[$subatomarray['name']] = $newData_subatomarray;
270
									break;
271
								}
272
							}
273
							$atom_structure['data'] = $newData;
274
							unset($atom_structure['subatoms']);
275
						}
276
					}
277
					break;
278
279
				case 'stbl': // Sample TaBLe container atom
280
					$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
281
					$isVideo = false;
282
					$framerate  = 0;
283
					$framecount = 0;
284
					foreach ($atom_structure['subatoms'] as $key => $value_array) {
0 ignored issues
show
Bug introduced by
The expression $atom_structure['subatoms'] of type array|false is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
285
						if (isset($value_array['sample_description_table'])) {
286
							foreach ($value_array['sample_description_table'] as $key2 => $value_array2) {
287
								if (isset($value_array2['data_format'])) {
288
									switch ($value_array2['data_format']) {
289
										case 'avc1':
290
										case 'mp4v':
291
											// video data
292
											$isVideo = true;
293
											break;
294
										case 'mp4a':
295
											// audio data
296
											break;
297
									}
298
								}
299
							}
300
						} elseif (isset($value_array['time_to_sample_table'])) {
301
							foreach ($value_array['time_to_sample_table'] as $key2 => $value_array2) {
302
								if (isset($value_array2['sample_count']) && isset($value_array2['sample_duration']) && ($value_array2['sample_duration'] > 0)) {
303
									$framerate  = round($info['quicktime']['time_scale'] / $value_array2['sample_duration'], 3);
304
									$framecount = $value_array2['sample_count'];
305
								}
306
							}
307
						}
308
					}
309
					if ($isVideo && $framerate) {
310
						$info['quicktime']['video']['frame_rate'] = $framerate;
311
						$info['video']['frame_rate'] = $info['quicktime']['video']['frame_rate'];
312
					}
313
					if ($isVideo && $framecount) {
314
						$info['quicktime']['video']['frame_count'] = $framecount;
315
					}
316
					break;
317
318
319
				case "\xA9".'alb': // ALBum
320
				case "\xA9".'ART': //
321
				case "\xA9".'art': // ARTist
322
				case "\xA9".'aut': //
323
				case "\xA9".'cmt': // CoMmenT
324
				case "\xA9".'com': // COMposer
325
				case "\xA9".'cpy': //
326
				case "\xA9".'day': // content created year
327
				case "\xA9".'dir': //
328
				case "\xA9".'ed1': //
329
				case "\xA9".'ed2': //
330
				case "\xA9".'ed3': //
331
				case "\xA9".'ed4': //
332
				case "\xA9".'ed5': //
333
				case "\xA9".'ed6': //
334
				case "\xA9".'ed7': //
335
				case "\xA9".'ed8': //
336
				case "\xA9".'ed9': //
337
				case "\xA9".'enc': //
338
				case "\xA9".'fmt': //
339
				case "\xA9".'gen': // GENre
340
				case "\xA9".'grp': // GRouPing
341
				case "\xA9".'hst': //
342
				case "\xA9".'inf': //
343
				case "\xA9".'lyr': // LYRics
344
				case "\xA9".'mak': //
345
				case "\xA9".'mod': //
346
				case "\xA9".'nam': // full NAMe
347
				case "\xA9".'ope': //
348
				case "\xA9".'PRD': //
349
				case "\xA9".'prf': //
350
				case "\xA9".'req': //
351
				case "\xA9".'src': //
352
				case "\xA9".'swr': //
353
				case "\xA9".'too': // encoder
354
				case "\xA9".'trk': // TRacK
355
				case "\xA9".'url': //
356
				case "\xA9".'wrn': //
357
				case "\xA9".'wrt': // WRiTer
358
				case '----': // itunes specific
359
				case 'aART': // Album ARTist
360
				case 'akID': // iTunes store account type
361
				case 'apID': // Purchase Account
362
				case 'atID': //
363
				case 'catg': // CaTeGory
364
				case 'cmID': //
365
				case 'cnID': //
366
				case 'covr': // COVeR artwork
367
				case 'cpil': // ComPILation
368
				case 'cprt': // CoPyRighT
369
				case 'desc': // DESCription
370
				case 'disk': // DISK number
371
				case 'egid': // Episode Global ID
372
				case 'geID': //
373
				case 'gnre': // GeNRE
374
				case 'hdvd': // HD ViDeo
375
				case 'keyw': // KEYWord
376
				case 'ldes': // Long DEScription
377
				case 'pcst': // PodCaST
378
				case 'pgap': // GAPless Playback
379
				case 'plID': //
380
				case 'purd': // PURchase Date
381
				case 'purl': // Podcast URL
382
				case 'rati': //
383
				case 'rndu': //
384
				case 'rpdu': //
385
				case 'rtng': // RaTiNG
386
				case 'sfID': // iTunes store country
387
				case 'soaa': // SOrt Album Artist
388
				case 'soal': // SOrt ALbum
389
				case 'soar': // SOrt ARtist
390
				case 'soco': // SOrt COmposer
391
				case 'sonm': // SOrt NaMe
392
				case 'sosn': // SOrt Show Name
393
				case 'stik': //
394
				case 'tmpo': // TeMPO (BPM)
395
				case 'trkn': // TRacK Number
396
				case 'tven': // tvEpisodeID
397
				case 'tves': // TV EpiSode
398
				case 'tvnn': // TV Network Name
399
				case 'tvsh': // TV SHow Name
400
				case 'tvsn': // TV SeasoN
401
					if ($atom_parent == 'udta') {
402
						// User data atom handler
403
						$atom_structure['data_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
404
						$atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2));
405
						$atom_structure['data']        =                           substr($atom_data, 4);
406
407
						$atom_structure['language']    = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
408 View Code Duplication
						if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
409
							$info['comments']['language'][] = $atom_structure['language'];
410
						}
411
					} else {
412
						// Apple item list box atom handler
413
						$atomoffset = 0;
414
						if (substr($atom_data, 2, 2) == "\x10\xB5") {
415
							// not sure what it means, but observed on iPhone4 data.
416
							// Each $atom_data has 2 bytes of datasize, plus 0x10B5, then data
417
							while ($atomoffset < strlen($atom_data)) {
418
								$boxsmallsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset,     2));
419
								$boxsmalltype =                           substr($atom_data, $atomoffset + 2, 2);
420
								$boxsmalldata =                           substr($atom_data, $atomoffset + 4, $boxsmallsize);
421 View Code Duplication
								if ($boxsmallsize <= 1) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
422
									$this->warning('Invalid QuickTime atom smallbox size "'.$boxsmallsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset));
423
									$atom_structure['data'] = null;
424
									$atomoffset = strlen($atom_data);
0 ignored issues
show
Unused Code introduced by
$atomoffset is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
425
									break;
426
								}
427
								switch ($boxsmalltype) {
428
									case "\x10\xB5":
429
										$atom_structure['data'] = $boxsmalldata;
430
										break;
431 View Code Duplication
									default:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
432
										$this->warning('Unknown QuickTime smallbox type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxsmalltype).'" ('.trim(getid3_lib::PrintHexBytes($boxsmalltype)).') at offset '.$baseoffset);
433
										$atom_structure['data'] = $atom_data;
434
										break;
435
								}
436
								$atomoffset += (4 + $boxsmallsize);
437
							}
438
						} else {
439
							while ($atomoffset < strlen($atom_data)) {
440
								$boxsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset, 4));
441
								$boxtype =                           substr($atom_data, $atomoffset + 4, 4);
442
								$boxdata =                           substr($atom_data, $atomoffset + 8, $boxsize - 8);
443 View Code Duplication
								if ($boxsize <= 1) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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
									$this->warning('Invalid QuickTime atom box size "'.$boxsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset));
445
									$atom_structure['data'] = null;
446
									$atomoffset = strlen($atom_data);
0 ignored issues
show
Unused Code introduced by
$atomoffset is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
447
									break;
448
								}
449
								$atomoffset += $boxsize;
450
451
								switch ($boxtype) {
452
									case 'mean':
453
									case 'name':
454
										$atom_structure[$boxtype] = substr($boxdata, 4);
455
										break;
456
457
									case 'data':
458
										$atom_structure['version']   = getid3_lib::BigEndian2Int(substr($boxdata,  0, 1));
459
										$atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($boxdata,  1, 3));
460
										switch ($atom_structure['flags_raw']) {
461
											case  0: // data flag
462
											case 21: // tmpo/cpil flag
463
												switch ($atomname) {
464
													case 'cpil':
465
													case 'hdvd':
466
													case 'pcst':
467
													case 'pgap':
468
														// 8-bit integer (boolean)
469
														$atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
470
														break;
471
472
													case 'tmpo':
473
														// 16-bit integer
474
														$atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 2));
475
														break;
476
477
													case 'disk':
478
													case 'trkn':
479
														// binary
480
														$num       = getid3_lib::BigEndian2Int(substr($boxdata, 10, 2));
481
														$num_total = getid3_lib::BigEndian2Int(substr($boxdata, 12, 2));
482
														$atom_structure['data']  = empty($num) ? '' : $num;
483
														$atom_structure['data'] .= empty($num_total) ? '' : '/'.$num_total;
484
														break;
485
486
													case 'gnre':
487
														// enum
488
														$GenreID = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
489
														$atom_structure['data']    = getid3_id3v1::LookupGenreName($GenreID - 1);
490
														break;
491
492 View Code Duplication
													case 'rtng':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
493
														// 8-bit integer
494
														$atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
495
														$atom_structure['data']    = $this->QuicktimeContentRatingLookup($atom_structure[$atomname]);
496
														break;
497
498 View Code Duplication
													case 'stik':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
499
														// 8-bit integer (enum)
500
														$atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
501
														$atom_structure['data']    = $this->QuicktimeSTIKLookup($atom_structure[$atomname]);
502
														break;
503
504 View Code Duplication
													case 'sfID':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
505
														// 32-bit integer
506
														$atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
507
														$atom_structure['data']    = $this->QuicktimeStoreFrontCodeLookup($atom_structure[$atomname]);
508
														break;
509
510
													case 'egid':
511
													case 'purl':
512
														$atom_structure['data'] = substr($boxdata, 8);
513
														break;
514
515
													case 'plID':
516
														// 64-bit integer
517
														$atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 8));
518
														break;
519
520 View Code Duplication
													case 'covr':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
521
														$atom_structure['data'] = substr($boxdata, 8);
522
														// not a foolproof check, but better than nothing
523
														if (preg_match('#^\\xFF\\xD8\\xFF#', $atom_structure['data'])) {
524
															$atom_structure['image_mime'] = 'image/jpeg';
525
														} elseif (preg_match('#^\\x89\\x50\\x4E\\x47\\x0D\\x0A\\x1A\\x0A#', $atom_structure['data'])) {
526
															$atom_structure['image_mime'] = 'image/png';
527
														} elseif (preg_match('#^GIF#', $atom_structure['data'])) {
528
															$atom_structure['image_mime'] = 'image/gif';
529
														}
530
														break;
531
532
													case 'atID':
533
													case 'cnID':
534
													case 'geID':
535
													case 'tves':
536
													case 'tvsn':
537
													default:
538
														// 32-bit integer
539
														$atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
540
												}
541
												break;
542
543
											case  1: // text flag
544
											case 13: // image flag
545 View Code Duplication
											default:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
546
												$atom_structure['data'] = substr($boxdata, 8);
547
												if ($atomname == 'covr') {
548
													// not a foolproof check, but better than nothing
549
													if (preg_match('#^\\xFF\\xD8\\xFF#', $atom_structure['data'])) {
550
														$atom_structure['image_mime'] = 'image/jpeg';
551
													} elseif (preg_match('#^\\x89\\x50\\x4E\\x47\\x0D\\x0A\\x1A\\x0A#', $atom_structure['data'])) {
552
														$atom_structure['image_mime'] = 'image/png';
553
													} elseif (preg_match('#^GIF#', $atom_structure['data'])) {
554
														$atom_structure['image_mime'] = 'image/gif';
555
													}
556
												}
557
												break;
558
559
										}
560
										break;
561
562 View Code Duplication
									default:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
563
										$this->warning('Unknown QuickTime box type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxtype).'" ('.trim(getid3_lib::PrintHexBytes($boxtype)).') at offset '.$baseoffset);
564
										$atom_structure['data'] = $atom_data;
565
566
								}
567
							}
568
						}
569
					}
570
					$this->CopyToAppropriateCommentsSection($atomname, $atom_structure['data'], $atom_structure['name']);
571
					break;
572
573
574
				case 'play': // auto-PLAY atom
575
					$atom_structure['autoplay'] = (bool) getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
576
577
					$info['quicktime']['autoplay'] = $atom_structure['autoplay'];
578
					break;
579
580
581 View Code Duplication
				case 'WLOC': // Window LOCation atom
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
582
					$atom_structure['location_x']  = getid3_lib::BigEndian2Int(substr($atom_data,  0, 2));
583
					$atom_structure['location_y']  = getid3_lib::BigEndian2Int(substr($atom_data,  2, 2));
584
					break;
585
586
587
				case 'LOOP': // LOOPing atom
588
				case 'SelO': // play SELection Only atom
589
				case 'AllF': // play ALL Frames atom
590
					$atom_structure['data'] = getid3_lib::BigEndian2Int($atom_data);
591
					break;
592
593
594
				case 'name': //
595
				case 'MCPS': // Media Cleaner PRo
596
				case '@PRM': // adobe PReMiere version
597
				case '@PRQ': // adobe PRemiere Quicktime version
598
					$atom_structure['data'] = $atom_data;
599
					break;
600
601
602
				case 'cmvd': // Compressed MooV Data atom
603
					// Code by ubergeekØubergeek*tv based on information from
604
					// http://developer.apple.com/quicktime/icefloe/dispatch012.html
605
					$atom_structure['unCompressedSize'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4));
606
607
					$CompressedFileData = substr($atom_data, 4);
608
					if ($UncompressedHeader = @gzuncompress($CompressedFileData)) {
609
						$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($UncompressedHeader, 0, $atomHierarchy, $ParseAllPossibleAtoms);
610
					} else {
611
						$this->warning('Error decompressing compressed MOV atom at offset '.$atom_structure['offset']);
612
					}
613
					break;
614
615
616
				case 'dcom': // Data COMpression atom
617
					$atom_structure['compression_id']   = $atom_data;
618
					$atom_structure['compression_text'] = $this->QuicktimeDCOMLookup($atom_data);
619
					break;
620
621
622
				case 'rdrf': // Reference movie Data ReFerence atom
623
					$atom_structure['version']                = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
624
					$atom_structure['flags_raw']              = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3));
625
					$atom_structure['flags']['internal_data'] = (bool) ($atom_structure['flags_raw'] & 0x000001);
626
627
					$atom_structure['reference_type_name']    =                           substr($atom_data,  4, 4);
628
					$atom_structure['reference_length']       = getid3_lib::BigEndian2Int(substr($atom_data,  8, 4));
629
					switch ($atom_structure['reference_type_name']) {
630
						case 'url ':
631
							$atom_structure['url']            =       $this->NoNullString(substr($atom_data, 12));
632
							break;
633
634
						case 'alis':
635
							$atom_structure['file_alias']     =                           substr($atom_data, 12);
636
							break;
637
638
						case 'rsrc':
639
							$atom_structure['resource_alias'] =                           substr($atom_data, 12);
640
							break;
641
642
						default:
643
							$atom_structure['data']           =                           substr($atom_data, 12);
644
							break;
645
					}
646
					break;
647
648
649
				case 'rmqu': // Reference Movie QUality atom
650
					$atom_structure['movie_quality'] = getid3_lib::BigEndian2Int($atom_data);
651
					break;
652
653
654 View Code Duplication
				case 'rmcs': // Reference Movie Cpu Speed atom
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
655
					$atom_structure['version']          = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
656
					$atom_structure['flags_raw']        = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
657
					$atom_structure['cpu_speed_rating'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 2));
658
					break;
659
660
661
				case 'rmvc': // Reference Movie Version Check atom
662
					$atom_structure['version']            = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
663
					$atom_structure['flags_raw']          = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
664
					$atom_structure['gestalt_selector']   =                           substr($atom_data,  4, 4);
665
					$atom_structure['gestalt_value_mask'] = getid3_lib::BigEndian2Int(substr($atom_data,  8, 4));
666
					$atom_structure['gestalt_value']      = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
667
					$atom_structure['gestalt_check_type'] = getid3_lib::BigEndian2Int(substr($atom_data, 14, 2));
668
					break;
669
670
671
				case 'rmcd': // Reference Movie Component check atom
672
					$atom_structure['version']                = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
673
					$atom_structure['flags_raw']              = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
674
					$atom_structure['component_type']         =                           substr($atom_data,  4, 4);
675
					$atom_structure['component_subtype']      =                           substr($atom_data,  8, 4);
676
					$atom_structure['component_manufacturer'] =                           substr($atom_data, 12, 4);
677
					$atom_structure['component_flags_raw']    = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
678
					$atom_structure['component_flags_mask']   = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));
679
					$atom_structure['component_min_version']  = getid3_lib::BigEndian2Int(substr($atom_data, 24, 4));
680
					break;
681
682
683 View Code Duplication
				case 'rmdr': // Reference Movie Data Rate atom
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
684
					$atom_structure['version']       = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
685
					$atom_structure['flags_raw']     = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
686
					$atom_structure['data_rate']     = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
687
688
					$atom_structure['data_rate_bps'] = $atom_structure['data_rate'] * 10;
689
					break;
690
691
692
				case 'rmla': // Reference Movie Language Atom
693
					$atom_structure['version']     = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
694
					$atom_structure['flags_raw']   = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
695
					$atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 2));
696
697
					$atom_structure['language']    = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
0 ignored issues
show
Bug introduced by
It seems like $atom_structure['language_id'] can also be of type double or false; however, getid3_quicktime::QuicktimeLanguageLookup() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
698 View Code Duplication
					if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
699
						$info['comments']['language'][] = $atom_structure['language'];
700
					}
701
					break;
702
703
704
				case 'ptv ': // Print To Video - defines a movie's full screen mode
705
					// http://developer.apple.com/documentation/QuickTime/APIREF/SOURCESIV/at_ptv-_pg.htm
706
					$atom_structure['display_size_raw']  = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
707
					$atom_structure['reserved_1']        = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2)); // hardcoded: 0x0000
708
					$atom_structure['reserved_2']        = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x0000
709
					$atom_structure['slide_show_flag']   = getid3_lib::BigEndian2Int(substr($atom_data, 6, 1));
710
					$atom_structure['play_on_open_flag'] = getid3_lib::BigEndian2Int(substr($atom_data, 7, 1));
711
712
					$atom_structure['flags']['play_on_open'] = (bool) $atom_structure['play_on_open_flag'];
713
					$atom_structure['flags']['slide_show']   = (bool) $atom_structure['slide_show_flag'];
714
715
					$ptv_lookup[0] = 'normal';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$ptv_lookup was never initialized. Although not strictly required by PHP, it is generally a good practice to add $ptv_lookup = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
716
					$ptv_lookup[1] = 'double';
717
					$ptv_lookup[2] = 'half';
718
					$ptv_lookup[3] = 'full';
719
					$ptv_lookup[4] = 'current';
720
					if (isset($ptv_lookup[$atom_structure['display_size_raw']])) {
721
						$atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']];
722
					} else {
723
						$this->warning('unknown "ptv " display constant ('.$atom_structure['display_size_raw'].')');
724
					}
725
					break;
726
727
728
				case 'stsd': // Sample Table Sample Description atom
729
					$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
730
					$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
731
					$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
732
733
					// see: https://github.com/JamesHeinrich/getID3/issues/111
734
					// Some corrupt files have been known to have high bits set in the number_entries field
735
					// This field shouldn't really need to be 32-bits, values stores are likely in the range 1-100000
736
					// Workaround: mask off the upper byte and throw a warning if it's nonzero
737
					if ($atom_structure['number_entries'] > 0x000FFFFF) {
738
						if ($atom_structure['number_entries'] > 0x00FFFFFF) {
739
							$this->warning('"stsd" atom contains improbably large number_entries (0x'.getid3_lib::PrintHexBytes(substr($atom_data, 4, 4), true, false).' = '.$atom_structure['number_entries'].'), probably in error. Ignoring upper byte and interpreting this as 0x'.getid3_lib::PrintHexBytes(substr($atom_data, 5, 3), true, false).' = '.($atom_structure['number_entries'] & 0x00FFFFFF));
740
							$atom_structure['number_entries'] = ($atom_structure['number_entries'] & 0x00FFFFFF);
741 View Code Duplication
						} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
742
							$this->warning('"stsd" atom contains improbably large number_entries (0x'.getid3_lib::PrintHexBytes(substr($atom_data, 4, 4), true, false).' = '.$atom_structure['number_entries'].'), probably in error. Please report this to [email protected] referencing bug report #111');
743
						}
744
					}
745
746
					$stsdEntriesDataOffset = 8;
747
					for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
748
						$atom_structure['sample_description_table'][$i]['size']             = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 4));
749
						$stsdEntriesDataOffset += 4;
750
						$atom_structure['sample_description_table'][$i]['data_format']      =                           substr($atom_data, $stsdEntriesDataOffset, 4);
751
						$stsdEntriesDataOffset += 4;
752
						$atom_structure['sample_description_table'][$i]['reserved']         = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 6));
753
						$stsdEntriesDataOffset += 6;
754
						$atom_structure['sample_description_table'][$i]['reference_index']  = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 2));
755
						$stsdEntriesDataOffset += 2;
756
						$atom_structure['sample_description_table'][$i]['data']             =                           substr($atom_data, $stsdEntriesDataOffset, ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2));
757
						$stsdEntriesDataOffset += ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2);
758
759
						$atom_structure['sample_description_table'][$i]['encoder_version']  = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'],  0, 2));
760
						$atom_structure['sample_description_table'][$i]['encoder_revision'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'],  2, 2));
761
						$atom_structure['sample_description_table'][$i]['encoder_vendor']   =                           substr($atom_structure['sample_description_table'][$i]['data'],  4, 4);
762
763
						switch ($atom_structure['sample_description_table'][$i]['encoder_vendor']) {
764
765
							case "\x00\x00\x00\x00":
766
								// audio tracks
767
								$atom_structure['sample_description_table'][$i]['audio_channels']       =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'],  8,  2));
768
								$atom_structure['sample_description_table'][$i]['audio_bit_depth']      =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 10,  2));
769
								$atom_structure['sample_description_table'][$i]['audio_compression_id'] =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12,  2));
770
								$atom_structure['sample_description_table'][$i]['audio_packet_size']    =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 14,  2));
771
								$atom_structure['sample_description_table'][$i]['audio_sample_rate']    = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 16,  4));
772
773
								// video tracks
774
								// http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap3/qtff3.html
775
								$atom_structure['sample_description_table'][$i]['temporal_quality'] =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'],  8,  4));
776
								$atom_structure['sample_description_table'][$i]['spatial_quality']  =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12,  4));
777
								$atom_structure['sample_description_table'][$i]['width']            =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16,  2));
778
								$atom_structure['sample_description_table'][$i]['height']           =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18,  2));
779
								$atom_structure['sample_description_table'][$i]['resolution_x']     = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24,  4));
780
								$atom_structure['sample_description_table'][$i]['resolution_y']     = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 28,  4));
781
								$atom_structure['sample_description_table'][$i]['data_size']        =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32,  4));
782
								$atom_structure['sample_description_table'][$i]['frame_count']      =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 36,  2));
783
								$atom_structure['sample_description_table'][$i]['compressor_name']  =                             substr($atom_structure['sample_description_table'][$i]['data'], 38,  4);
784
								$atom_structure['sample_description_table'][$i]['pixel_depth']      =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 42,  2));
785
								$atom_structure['sample_description_table'][$i]['color_table_id']   =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 44,  2));
786
787
								switch ($atom_structure['sample_description_table'][$i]['data_format']) {
788
									case '2vuY':
789
									case 'avc1':
790
									case 'cvid':
791
									case 'dvc ':
792
									case 'dvcp':
793
									case 'gif ':
794
									case 'h263':
795
									case 'jpeg':
796
									case 'kpcd':
797
									case 'mjpa':
798
									case 'mjpb':
799
									case 'mp4v':
800
									case 'png ':
801
									case 'raw ':
802
									case 'rle ':
803
									case 'rpza':
804
									case 'smc ':
805
									case 'SVQ1':
806
									case 'SVQ3':
807
									case 'tiff':
808
									case 'v210':
809
									case 'v216':
810
									case 'v308':
811
									case 'v408':
812
									case 'v410':
813
									case 'yuv2':
814
										$info['fileformat'] = 'mp4';
815
										$info['video']['fourcc'] = $atom_structure['sample_description_table'][$i]['data_format'];
816
										if ($this->QuicktimeVideoCodecLookup($info['video']['fourcc'])) {
817
											$info['video']['fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($info['video']['fourcc']);
818
										}
819
820
										// https://www.getid3.org/phpBB3/viewtopic.php?t=1550
821
										//if ((!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($atom_structure['sample_description_table'][$i]['width'])) && (empty($info['video']['resolution_x']) || empty($info['video']['resolution_y']) || (number_format($info['video']['resolution_x'], 6) != number_format(round($info['video']['resolution_x']), 6)) || (number_format($info['video']['resolution_y'], 6) != number_format(round($info['video']['resolution_y']), 6)))) { // ugly check for floating point numbers
822
										if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($atom_structure['sample_description_table'][$i]['height'])) {
823
											// assume that values stored here are more important than values stored in [tkhd] atom
824
											$info['video']['resolution_x'] = $atom_structure['sample_description_table'][$i]['width'];
825
											$info['video']['resolution_y'] = $atom_structure['sample_description_table'][$i]['height'];
826
											$info['quicktime']['video']['resolution_x'] = $info['video']['resolution_x'];
827
											$info['quicktime']['video']['resolution_y'] = $info['video']['resolution_y'];
828
										}
829
										break;
830
831
									case 'qtvr':
832
										$info['video']['dataformat'] = 'quicktimevr';
833
										break;
834
835
									case 'mp4a':
836
									default:
837
										$info['quicktime']['audio']['codec']       = $this->QuicktimeAudioCodecLookup($atom_structure['sample_description_table'][$i]['data_format']);
838
										$info['quicktime']['audio']['sample_rate'] = $atom_structure['sample_description_table'][$i]['audio_sample_rate'];
839
										$info['quicktime']['audio']['channels']    = $atom_structure['sample_description_table'][$i]['audio_channels'];
840
										$info['quicktime']['audio']['bit_depth']   = $atom_structure['sample_description_table'][$i]['audio_bit_depth'];
841
										$info['audio']['codec']                    = $info['quicktime']['audio']['codec'];
842
										$info['audio']['sample_rate']              = $info['quicktime']['audio']['sample_rate'];
843
										$info['audio']['channels']                 = $info['quicktime']['audio']['channels'];
844
										$info['audio']['bits_per_sample']          = $info['quicktime']['audio']['bit_depth'];
845
										switch ($atom_structure['sample_description_table'][$i]['data_format']) {
846
											case 'raw ': // PCM
847
											case 'alac': // Apple Lossless Audio Codec
848
											case 'sowt': // signed/two's complement (Little Endian)
849
											case 'twos': // signed/two's complement (Big Endian)
850
											case 'in24': // 24-bit Integer
851
											case 'in32': // 32-bit Integer
852
											case 'fl32': // 32-bit Floating Point
853
											case 'fl64': // 64-bit Floating Point
854
												$info['audio']['lossless'] = $info['quicktime']['audio']['lossless'] = true;
855
												$info['audio']['bitrate']  = $info['quicktime']['audio']['bitrate']  = $info['audio']['channels'] * $info['audio']['bits_per_sample'] * $info['audio']['sample_rate'];
856
												break;
857
											default:
858
												$info['audio']['lossless'] = false;
859
												break;
860
										}
861
										break;
862
								}
863
								break;
864
865
							default:
866
								switch ($atom_structure['sample_description_table'][$i]['data_format']) {
867
									case 'mp4s':
868
										$info['fileformat'] = 'mp4';
869
										break;
870
871
									default:
872
										// video atom
873
										$atom_structure['sample_description_table'][$i]['video_temporal_quality']  =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'],  8,  4));
874
										$atom_structure['sample_description_table'][$i]['video_spatial_quality']   =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12,  4));
875
										$atom_structure['sample_description_table'][$i]['video_frame_width']       =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16,  2));
876
										$atom_structure['sample_description_table'][$i]['video_frame_height']      =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18,  2));
877
										$atom_structure['sample_description_table'][$i]['video_resolution_x']      = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 20,  4));
878
										$atom_structure['sample_description_table'][$i]['video_resolution_y']      = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24,  4));
879
										$atom_structure['sample_description_table'][$i]['video_data_size']         =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 28,  4));
880
										$atom_structure['sample_description_table'][$i]['video_frame_count']       =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32,  2));
881
										$atom_structure['sample_description_table'][$i]['video_encoder_name_len']  =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 34,  1));
882
										$atom_structure['sample_description_table'][$i]['video_encoder_name']      =                             substr($atom_structure['sample_description_table'][$i]['data'], 35, $atom_structure['sample_description_table'][$i]['video_encoder_name_len']);
883
										$atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 66,  2));
884
										$atom_structure['sample_description_table'][$i]['video_color_table_id']    =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 68,  2));
885
886
										$atom_structure['sample_description_table'][$i]['video_pixel_color_type']  = (($atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color');
887
										$atom_structure['sample_description_table'][$i]['video_pixel_color_name']  = $this->QuicktimeColorNameLookup($atom_structure['sample_description_table'][$i]['video_pixel_color_depth']);
888
889
										if ($atom_structure['sample_description_table'][$i]['video_pixel_color_name'] != 'invalid') {
890
											$info['quicktime']['video']['codec_fourcc']        = $atom_structure['sample_description_table'][$i]['data_format'];
891
											$info['quicktime']['video']['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($atom_structure['sample_description_table'][$i]['data_format']);
892
											$info['quicktime']['video']['codec']               = (($atom_structure['sample_description_table'][$i]['video_encoder_name_len'] > 0) ? $atom_structure['sample_description_table'][$i]['video_encoder_name'] : $atom_structure['sample_description_table'][$i]['data_format']);
893
											$info['quicktime']['video']['color_depth']         = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'];
894
											$info['quicktime']['video']['color_depth_name']    = $atom_structure['sample_description_table'][$i]['video_pixel_color_name'];
895
896
											$info['video']['codec']           = $info['quicktime']['video']['codec'];
897
											$info['video']['bits_per_sample'] = $info['quicktime']['video']['color_depth'];
898
										}
899
										$info['video']['lossless']           = false;
900
										$info['video']['pixel_aspect_ratio'] = (float) 1;
901
										break;
902
								}
903
								break;
904
						}
905
						switch (strtolower($atom_structure['sample_description_table'][$i]['data_format'])) {
906
							case 'mp4a':
907
								$info['audio']['dataformat']         = 'mp4';
908
								$info['quicktime']['audio']['codec'] = 'mp4';
909
								break;
910
911
							case '3ivx':
912
							case '3iv1':
913
							case '3iv2':
914
								$info['video']['dataformat'] = '3ivx';
915
								break;
916
917
							case 'xvid':
918
								$info['video']['dataformat'] = 'xvid';
919
								break;
920
921
							case 'mp4v':
922
								$info['video']['dataformat'] = 'mpeg4';
923
								break;
924
925
							case 'divx':
926
							case 'div1':
927
							case 'div2':
928
							case 'div3':
929
							case 'div4':
930
							case 'div5':
931
							case 'div6':
932
								$info['video']['dataformat'] = 'divx';
933
								break;
934
935
							default:
936
								// do nothing
937
								break;
938
						}
939
						unset($atom_structure['sample_description_table'][$i]['data']);
940
					}
941
					break;
942
943
944
				case 'stts': // Sample Table Time-to-Sample atom
945
					$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
946
					$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
947
					$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
948
					$sttsEntriesDataOffset = 8;
949
					//$FrameRateCalculatorArray = array();
950
					$frames_count = 0;
951
952
					$max_stts_entries_to_scan = ($info['php_memory_limit'] ? min(floor($this->getid3->memory_limit / 10000), $atom_structure['number_entries']) : $atom_structure['number_entries']);
953
					if ($max_stts_entries_to_scan < $atom_structure['number_entries']) {
954
						$this->warning('QuickTime atom "stts" has '.$atom_structure['number_entries'].' but only scanning the first '.$max_stts_entries_to_scan.' entries due to limited PHP memory available ('.floor($this->getid3->memory_limit / 1048576).'MB).');
955
					}
956 View Code Duplication
					for ($i = 0; $i < $max_stts_entries_to_scan; $i++) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
957
						$atom_structure['time_to_sample_table'][$i]['sample_count']    = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4));
958
						$sttsEntriesDataOffset += 4;
959
						$atom_structure['time_to_sample_table'][$i]['sample_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4));
960
						$sttsEntriesDataOffset += 4;
961
962
						$frames_count += $atom_structure['time_to_sample_table'][$i]['sample_count'];
963
964
						// THIS SECTION REPLACED WITH CODE IN "stbl" ATOM
965
						//if (!empty($info['quicktime']['time_scale']) && ($atom_structure['time_to_sample_table'][$i]['sample_duration'] > 0)) {
966
						//	$stts_new_framerate = $info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'];
967
						//	if ($stts_new_framerate <= 60) {
968
						//		// some atoms have durations of "1" giving a very large framerate, which probably is not right
969
						//		$info['video']['frame_rate'] = max($info['video']['frame_rate'], $stts_new_framerate);
970
						//	}
971
						//}
972
						//
973
						//$FrameRateCalculatorArray[($info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'])] += $atom_structure['time_to_sample_table'][$i]['sample_count'];
974
					}
975
					$info['quicktime']['stts_framecount'][] = $frames_count;
976
					//$sttsFramesTotal  = 0;
977
					//$sttsSecondsTotal = 0;
978
					//foreach ($FrameRateCalculatorArray as $frames_per_second => $frame_count) {
979
					//	if (($frames_per_second > 60) || ($frames_per_second < 1)) {
980
					//		// not video FPS information, probably audio information
981
					//		$sttsFramesTotal  = 0;
982
					//		$sttsSecondsTotal = 0;
983
					//		break;
984
					//	}
985
					//	$sttsFramesTotal  += $frame_count;
986
					//	$sttsSecondsTotal += $frame_count / $frames_per_second;
987
					//}
988
					//if (($sttsFramesTotal > 0) && ($sttsSecondsTotal > 0)) {
989
					//	if (($sttsFramesTotal / $sttsSecondsTotal) > $info['video']['frame_rate']) {
990
					//		$info['video']['frame_rate'] = $sttsFramesTotal / $sttsSecondsTotal;
991
					//	}
992
					//}
993
					break;
994
995
996 View Code Duplication
				case 'stss': // Sample Table Sync Sample (key frames) atom
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
997
					if ($ParseAllPossibleAtoms) {
998
						$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
999
						$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1000
						$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1001
						$stssEntriesDataOffset = 8;
1002
						for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
1003
							$atom_structure['time_to_sample_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stssEntriesDataOffset, 4));
1004
							$stssEntriesDataOffset += 4;
1005
						}
1006
					}
1007
					break;
1008
1009
1010
				case 'stsc': // Sample Table Sample-to-Chunk atom
1011
					if ($ParseAllPossibleAtoms) {
1012
						$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1013
						$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1014
						$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1015
						$stscEntriesDataOffset = 8;
1016 View Code Duplication
						for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1017
							$atom_structure['sample_to_chunk_table'][$i]['first_chunk']        = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
1018
							$stscEntriesDataOffset += 4;
1019
							$atom_structure['sample_to_chunk_table'][$i]['samples_per_chunk']  = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
1020
							$stscEntriesDataOffset += 4;
1021
							$atom_structure['sample_to_chunk_table'][$i]['sample_description'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
1022
							$stscEntriesDataOffset += 4;
1023
						}
1024
					}
1025
					break;
1026
1027
1028
				case 'stsz': // Sample Table SiZe atom
1029
					if ($ParseAllPossibleAtoms) {
1030
						$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1031
						$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1032
						$atom_structure['sample_size']    = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1033
						$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  8, 4));
1034
						$stszEntriesDataOffset = 12;
1035
						if ($atom_structure['sample_size'] == 0) {
1036
							for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
1037
								$atom_structure['sample_size_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stszEntriesDataOffset, 4));
1038
								$stszEntriesDataOffset += 4;
1039
							}
1040
						}
1041
					}
1042
					break;
1043
1044
1045 View Code Duplication
				case 'stco': // Sample Table Chunk Offset atom
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1046
//					if (true) {
1047
					if ($ParseAllPossibleAtoms) {
1048
						$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1049
						$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1050
						$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1051
						$stcoEntriesDataOffset = 8;
1052
						for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
1053
							$atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 4));
1054
							$stcoEntriesDataOffset += 4;
1055
						}
1056
					}
1057
					break;
1058
1059
1060 View Code Duplication
				case 'co64': // Chunk Offset 64-bit (version of "stco" that supports > 2GB files)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1061
					if ($ParseAllPossibleAtoms) {
1062
						$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1063
						$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1064
						$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1065
						$stcoEntriesDataOffset = 8;
1066
						for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
1067
							$atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 8));
1068
							$stcoEntriesDataOffset += 8;
1069
						}
1070
					}
1071
					break;
1072
1073
1074
				case 'dref': // Data REFerence atom
1075
					$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1076
					$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1077
					$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1078
					$drefDataOffset = 8;
1079
					for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
1080
						$atom_structure['data_references'][$i]['size']                    = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 4));
1081
						$drefDataOffset += 4;
1082
						$atom_structure['data_references'][$i]['type']                    =                           substr($atom_data, $drefDataOffset, 4);
1083
						$drefDataOffset += 4;
1084
						$atom_structure['data_references'][$i]['version']                 = getid3_lib::BigEndian2Int(substr($atom_data,  $drefDataOffset, 1));
1085
						$drefDataOffset += 1;
1086
						$atom_structure['data_references'][$i]['flags_raw']               = getid3_lib::BigEndian2Int(substr($atom_data,  $drefDataOffset, 3)); // hardcoded: 0x0000
1087
						$drefDataOffset += 3;
1088
						$atom_structure['data_references'][$i]['data']                    =                           substr($atom_data, $drefDataOffset, ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3));
1089
						$drefDataOffset += ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3);
1090
1091
						$atom_structure['data_references'][$i]['flags']['self_reference'] = (bool) ($atom_structure['data_references'][$i]['flags_raw'] & 0x001);
1092
					}
1093
					break;
1094
1095
1096
				case 'gmin': // base Media INformation atom
1097
					$atom_structure['version']                = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1098
					$atom_structure['flags_raw']              = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1099
					$atom_structure['graphics_mode']          = getid3_lib::BigEndian2Int(substr($atom_data,  4, 2));
1100
					$atom_structure['opcolor_red']            = getid3_lib::BigEndian2Int(substr($atom_data,  6, 2));
1101
					$atom_structure['opcolor_green']          = getid3_lib::BigEndian2Int(substr($atom_data,  8, 2));
1102
					$atom_structure['opcolor_blue']           = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2));
1103
					$atom_structure['balance']                = getid3_lib::BigEndian2Int(substr($atom_data, 12, 2));
1104
					$atom_structure['reserved']               = getid3_lib::BigEndian2Int(substr($atom_data, 14, 2));
1105
					break;
1106
1107
1108 View Code Duplication
				case 'smhd': // Sound Media information HeaDer atom
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1109
					$atom_structure['version']                = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1110
					$atom_structure['flags_raw']              = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1111
					$atom_structure['balance']                = getid3_lib::BigEndian2Int(substr($atom_data,  4, 2));
1112
					$atom_structure['reserved']               = getid3_lib::BigEndian2Int(substr($atom_data,  6, 2));
1113
					break;
1114
1115
1116
				case 'vmhd': // Video Media information HeaDer atom
1117
					$atom_structure['version']                = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1118
					$atom_structure['flags_raw']              = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3));
1119
					$atom_structure['graphics_mode']          = getid3_lib::BigEndian2Int(substr($atom_data,  4, 2));
1120
					$atom_structure['opcolor_red']            = getid3_lib::BigEndian2Int(substr($atom_data,  6, 2));
1121
					$atom_structure['opcolor_green']          = getid3_lib::BigEndian2Int(substr($atom_data,  8, 2));
1122
					$atom_structure['opcolor_blue']           = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2));
1123
1124
					$atom_structure['flags']['no_lean_ahead'] = (bool) ($atom_structure['flags_raw'] & 0x001);
1125
					break;
1126
1127
1128
				case 'hdlr': // HanDLeR reference atom
1129
					$atom_structure['version']                = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1130
					$atom_structure['flags_raw']              = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1131
					$atom_structure['component_type']         =                           substr($atom_data,  4, 4);
1132
					$atom_structure['component_subtype']      =                           substr($atom_data,  8, 4);
1133
					$atom_structure['component_manufacturer'] =                           substr($atom_data, 12, 4);
1134
					$atom_structure['component_flags_raw']    = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
1135
					$atom_structure['component_flags_mask']   = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));
1136
					$atom_structure['component_name']         =      $this->Pascal2String(substr($atom_data, 24));
1137
1138
					if (($atom_structure['component_subtype'] == 'STpn') && ($atom_structure['component_manufacturer'] == 'zzzz')) {
1139
						$info['video']['dataformat'] = 'quicktimevr';
1140
					}
1141
					break;
1142
1143
1144
				case 'mdhd': // MeDia HeaDer atom
1145
					$atom_structure['version']               = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1146
					$atom_structure['flags_raw']             = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1147
					$atom_structure['creation_time']         = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1148
					$atom_structure['modify_time']           = getid3_lib::BigEndian2Int(substr($atom_data,  8, 4));
1149
					$atom_structure['time_scale']            = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
1150
					$atom_structure['duration']              = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
1151
					$atom_structure['language_id']           = getid3_lib::BigEndian2Int(substr($atom_data, 20, 2));
1152
					$atom_structure['quality']               = getid3_lib::BigEndian2Int(substr($atom_data, 22, 2));
1153
1154
					if ($atom_structure['time_scale'] == 0) {
1155
						$this->error('Corrupt Quicktime file: mdhd.time_scale == zero');
1156
						return false;
1157
					}
1158
					$info['quicktime']['time_scale'] = ((isset($info['quicktime']['time_scale']) && ($info['quicktime']['time_scale'] < 1000)) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']);
1159
1160
					$atom_structure['creation_time_unix']    = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
1161
					$atom_structure['modify_time_unix']      = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
1162
					$atom_structure['playtime_seconds']      = $atom_structure['duration'] / $atom_structure['time_scale'];
1163
					$atom_structure['language']              = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
1164 View Code Duplication
					if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1165
						$info['comments']['language'][] = $atom_structure['language'];
1166
					}
1167
					break;
1168
1169
1170
				case 'pnot': // Preview atom
1171
					$atom_structure['modification_date']      = getid3_lib::BigEndian2Int(substr($atom_data,  0, 4)); // "standard Macintosh format"
1172
					$atom_structure['version_number']         = getid3_lib::BigEndian2Int(substr($atom_data,  4, 2)); // hardcoded: 0x00
1173
					$atom_structure['atom_type']              =                           substr($atom_data,  6, 4);        // usually: 'PICT'
1174
					$atom_structure['atom_index']             = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2)); // usually: 0x01
1175
1176
					$atom_structure['modification_date_unix'] = getid3_lib::DateMac2Unix($atom_structure['modification_date']);
1177
					break;
1178
1179
1180 View Code Duplication
				case 'crgn': // Clipping ReGioN atom
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1181
					$atom_structure['region_size']   = getid3_lib::BigEndian2Int(substr($atom_data,  0, 2)); // The Region size, Region boundary box,
1182
					$atom_structure['boundary_box']  = getid3_lib::BigEndian2Int(substr($atom_data,  2, 8)); // and Clipping region data fields
1183
					$atom_structure['clipping_data'] =                           substr($atom_data, 10);           // constitute a QuickDraw region.
1184
					break;
1185
1186
1187
				case 'load': // track LOAD settings atom
1188
					$atom_structure['preload_start_time'] = getid3_lib::BigEndian2Int(substr($atom_data,  0, 4));
1189
					$atom_structure['preload_duration']   = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1190
					$atom_structure['preload_flags_raw']  = getid3_lib::BigEndian2Int(substr($atom_data,  8, 4));
1191
					$atom_structure['default_hints_raw']  = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
1192
1193
					$atom_structure['default_hints']['double_buffer'] = (bool) ($atom_structure['default_hints_raw'] & 0x0020);
1194
					$atom_structure['default_hints']['high_quality']  = (bool) ($atom_structure['default_hints_raw'] & 0x0100);
1195
					break;
1196
1197
1198
				case 'tmcd': // TiMe CoDe atom
1199
				case 'chap': // CHAPter list atom
1200
				case 'sync': // SYNChronization atom
1201
				case 'scpt': // tranSCriPT atom
1202 View Code Duplication
				case 'ssrc': // non-primary SouRCe atom
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1203
					for ($i = 0; $i < strlen($atom_data); $i += 4) {
1204
						@$atom_structure['track_id'][] = getid3_lib::BigEndian2Int(substr($atom_data, $i, 4));
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1205
					}
1206
					break;
1207
1208
1209
				case 'elst': // Edit LiST atom
1210
					$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1211
					$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1212
					$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1213
					for ($i = 0; $i < $atom_structure['number_entries']; $i++ ) {
1214
						$atom_structure['edit_list'][$i]['track_duration'] =   getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 0, 4));
1215
						$atom_structure['edit_list'][$i]['media_time']     =   getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 4, 4));
1216
						$atom_structure['edit_list'][$i]['media_rate']     = getid3_lib::FixedPoint16_16(substr($atom_data, 8 + ($i * 12) + 8, 4));
1217
					}
1218
					break;
1219
1220
1221 View Code Duplication
				case 'kmat': // compressed MATte atom
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1222
					$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1223
					$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1224
					$atom_structure['matte_data_raw'] =               substr($atom_data,  4);
1225
					break;
1226
1227
1228
				case 'ctab': // Color TABle atom
1229
					$atom_structure['color_table_seed']   = getid3_lib::BigEndian2Int(substr($atom_data,  0, 4)); // hardcoded: 0x00000000
1230
					$atom_structure['color_table_flags']  = getid3_lib::BigEndian2Int(substr($atom_data,  4, 2)); // hardcoded: 0x8000
1231
					$atom_structure['color_table_size']   = getid3_lib::BigEndian2Int(substr($atom_data,  6, 2)) + 1;
1232
					for ($colortableentry = 0; $colortableentry < $atom_structure['color_table_size']; $colortableentry++) {
1233
						$atom_structure['color_table'][$colortableentry]['alpha'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 0, 2));
1234
						$atom_structure['color_table'][$colortableentry]['red']   = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 2, 2));
1235
						$atom_structure['color_table'][$colortableentry]['green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 4, 2));
1236
						$atom_structure['color_table'][$colortableentry]['blue']  = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 6, 2));
1237
					}
1238
					break;
1239
1240
1241
				case 'mvhd': // MoVie HeaDer atom
1242
					$atom_structure['version']            =   getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1243
					$atom_structure['flags_raw']          =   getid3_lib::BigEndian2Int(substr($atom_data,  1, 3));
1244
					$atom_structure['creation_time']      =   getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1245
					$atom_structure['modify_time']        =   getid3_lib::BigEndian2Int(substr($atom_data,  8, 4));
1246
					$atom_structure['time_scale']         =   getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
1247
					$atom_structure['duration']           =   getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
1248
					$atom_structure['preferred_rate']     = getid3_lib::FixedPoint16_16(substr($atom_data, 20, 4));
1249
					$atom_structure['preferred_volume']   =   getid3_lib::FixedPoint8_8(substr($atom_data, 24, 2));
1250
					$atom_structure['reserved']           =                             substr($atom_data, 26, 10);
1251
					$atom_structure['matrix_a']           = getid3_lib::FixedPoint16_16(substr($atom_data, 36, 4));
1252
					$atom_structure['matrix_b']           = getid3_lib::FixedPoint16_16(substr($atom_data, 40, 4));
1253
					$atom_structure['matrix_u']           =  getid3_lib::FixedPoint2_30(substr($atom_data, 44, 4));
1254
					$atom_structure['matrix_c']           = getid3_lib::FixedPoint16_16(substr($atom_data, 48, 4));
1255
					$atom_structure['matrix_d']           = getid3_lib::FixedPoint16_16(substr($atom_data, 52, 4));
1256
					$atom_structure['matrix_v']           =  getid3_lib::FixedPoint2_30(substr($atom_data, 56, 4));
1257
					$atom_structure['matrix_x']           = getid3_lib::FixedPoint16_16(substr($atom_data, 60, 4));
1258
					$atom_structure['matrix_y']           = getid3_lib::FixedPoint16_16(substr($atom_data, 64, 4));
1259
					$atom_structure['matrix_w']           =  getid3_lib::FixedPoint2_30(substr($atom_data, 68, 4));
1260
					$atom_structure['preview_time']       =   getid3_lib::BigEndian2Int(substr($atom_data, 72, 4));
1261
					$atom_structure['preview_duration']   =   getid3_lib::BigEndian2Int(substr($atom_data, 76, 4));
1262
					$atom_structure['poster_time']        =   getid3_lib::BigEndian2Int(substr($atom_data, 80, 4));
1263
					$atom_structure['selection_time']     =   getid3_lib::BigEndian2Int(substr($atom_data, 84, 4));
1264
					$atom_structure['selection_duration'] =   getid3_lib::BigEndian2Int(substr($atom_data, 88, 4));
1265
					$atom_structure['current_time']       =   getid3_lib::BigEndian2Int(substr($atom_data, 92, 4));
1266
					$atom_structure['next_track_id']      =   getid3_lib::BigEndian2Int(substr($atom_data, 96, 4));
1267
1268
					if ($atom_structure['time_scale'] == 0) {
1269
						$this->error('Corrupt Quicktime file: mvhd.time_scale == zero');
1270
						return false;
1271
					}
1272
					$atom_structure['creation_time_unix']        = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
1273
					$atom_structure['modify_time_unix']          = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
1274
					$info['quicktime']['time_scale']    = ((isset($info['quicktime']['time_scale']) && ($info['quicktime']['time_scale'] < 1000)) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']);
1275
					$info['quicktime']['display_scale'] = $atom_structure['matrix_a'];
1276
					$info['playtime_seconds']           = $atom_structure['duration'] / $atom_structure['time_scale'];
1277
					break;
1278
1279
1280
				case 'tkhd': // TracK HeaDer atom
1281
					$atom_structure['version']             =   getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1282
					$atom_structure['flags_raw']           =   getid3_lib::BigEndian2Int(substr($atom_data,  1, 3));
1283
					$atom_structure['creation_time']       =   getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1284
					$atom_structure['modify_time']         =   getid3_lib::BigEndian2Int(substr($atom_data,  8, 4));
1285
					$atom_structure['trackid']             =   getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
1286
					$atom_structure['reserved1']           =   getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
1287
					$atom_structure['duration']            =   getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));
1288
					$atom_structure['reserved2']           =   getid3_lib::BigEndian2Int(substr($atom_data, 24, 8));
1289
					$atom_structure['layer']               =   getid3_lib::BigEndian2Int(substr($atom_data, 32, 2));
1290
					$atom_structure['alternate_group']     =   getid3_lib::BigEndian2Int(substr($atom_data, 34, 2));
1291
					$atom_structure['volume']              =   getid3_lib::FixedPoint8_8(substr($atom_data, 36, 2));
1292
					$atom_structure['reserved3']           =   getid3_lib::BigEndian2Int(substr($atom_data, 38, 2));
1293
					// http://developer.apple.com/library/mac/#documentation/QuickTime/RM/MovieBasics/MTEditing/K-Chapter/11MatrixFunctions.html
1294
					// http://developer.apple.com/library/mac/#documentation/QuickTime/qtff/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-18737
1295
					$atom_structure['matrix_a']            = getid3_lib::FixedPoint16_16(substr($atom_data, 40, 4));
1296
					$atom_structure['matrix_b']            = getid3_lib::FixedPoint16_16(substr($atom_data, 44, 4));
1297
					$atom_structure['matrix_u']            =  getid3_lib::FixedPoint2_30(substr($atom_data, 48, 4));
1298
					$atom_structure['matrix_c']            = getid3_lib::FixedPoint16_16(substr($atom_data, 52, 4));
1299
					$atom_structure['matrix_d']            = getid3_lib::FixedPoint16_16(substr($atom_data, 56, 4));
1300
					$atom_structure['matrix_v']            =  getid3_lib::FixedPoint2_30(substr($atom_data, 60, 4));
1301
					$atom_structure['matrix_x']            = getid3_lib::FixedPoint16_16(substr($atom_data, 64, 4));
1302
					$atom_structure['matrix_y']            = getid3_lib::FixedPoint16_16(substr($atom_data, 68, 4));
1303
					$atom_structure['matrix_w']            =  getid3_lib::FixedPoint2_30(substr($atom_data, 72, 4));
1304
					$atom_structure['width']               = getid3_lib::FixedPoint16_16(substr($atom_data, 76, 4));
1305
					$atom_structure['height']              = getid3_lib::FixedPoint16_16(substr($atom_data, 80, 4));
1306
					$atom_structure['flags']['enabled']    = (bool) ($atom_structure['flags_raw'] & 0x0001);
1307
					$atom_structure['flags']['in_movie']   = (bool) ($atom_structure['flags_raw'] & 0x0002);
1308
					$atom_structure['flags']['in_preview'] = (bool) ($atom_structure['flags_raw'] & 0x0004);
1309
					$atom_structure['flags']['in_poster']  = (bool) ($atom_structure['flags_raw'] & 0x0008);
1310
					$atom_structure['creation_time_unix']  = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
1311
					$atom_structure['modify_time_unix']    = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
1312
1313
					// https://www.getid3.org/phpBB3/viewtopic.php?t=1908
1314
					// attempt to compute rotation from matrix values
1315
					// 2017-Dec-28: uncertain if 90/270 are correctly oriented; values returned by FixedPoint16_16 should perhaps be -1 instead of 65535(?)
1316
					$matrixRotation = 0;
1317
					switch ($atom_structure['matrix_a'].':'.$atom_structure['matrix_b'].':'.$atom_structure['matrix_c'].':'.$atom_structure['matrix_d']) {
1318
						case '1:0:0:1':         $matrixRotation =   0; break;
1319
						case '0:1:65535:0':     $matrixRotation =  90; break;
1320
						case '65535:0:0:65535': $matrixRotation = 180; break;
1321
						case '0:65535:1:0':     $matrixRotation = 270; break;
1322
						default: break;
1323
					}
1324
1325
					// https://www.getid3.org/phpBB3/viewtopic.php?t=2468
1326
					// The rotation matrix can appear in the Quicktime file multiple times, at least once for each track,
1327
					// and it's possible that only the video track (or, in theory, one of the video tracks) is flagged as
1328
					// rotated while the other tracks (e.g. audio) is tagged as rotation=0 (behavior noted on iPhone 8 Plus)
1329
					// The correct solution would be to check if the TrackID associated with the rotation matrix is indeed
1330
					// a video track (or the main video track) and only set the rotation then, but since information about
1331
					// what track is what is not trivially there to be examined, the lazy solution is to set the rotation
1332
					// if it is found to be nonzero, on the assumption that tracks that don't need it will have rotation set
1333
					// to zero (and be effectively ignored) and the video track will have rotation set correctly, which will
1334
					// either be zero and automatically correct, or nonzero and be set correctly.
1335
					if (!isset($info['video']['rotate']) || (($info['video']['rotate'] == 0) && ($matrixRotation > 0))) {
1336
						$info['quicktime']['video']['rotate'] = $info['video']['rotate'] = $matrixRotation;
1337
					}
1338
1339
					if ($atom_structure['flags']['enabled'] == 1) {
1340
						if (!isset($info['video']['resolution_x']) || !isset($info['video']['resolution_y'])) {
1341
							$info['video']['resolution_x'] = $atom_structure['width'];
1342
							$info['video']['resolution_y'] = $atom_structure['height'];
1343
						}
1344
						$info['video']['resolution_x'] = max($info['video']['resolution_x'], $atom_structure['width']);
1345
						$info['video']['resolution_y'] = max($info['video']['resolution_y'], $atom_structure['height']);
1346
						$info['quicktime']['video']['resolution_x'] = $info['video']['resolution_x'];
1347
						$info['quicktime']['video']['resolution_y'] = $info['video']['resolution_y'];
1348
					} else {
1349
						// see: https://www.getid3.org/phpBB3/viewtopic.php?t=1295
1350
						//if (isset($info['video']['resolution_x'])) { unset($info['video']['resolution_x']); }
1351
						//if (isset($info['video']['resolution_y'])) { unset($info['video']['resolution_y']); }
1352
						//if (isset($info['quicktime']['video']))    { unset($info['quicktime']['video']);    }
1353
					}
1354
					break;
1355
1356
1357
				case 'iods': // Initial Object DeScriptor atom
1358
					// http://www.koders.com/c/fid1FAB3E762903DC482D8A246D4A4BF9F28E049594.aspx?s=windows.h
1359
					// http://libquicktime.sourcearchive.com/documentation/1.0.2plus-pdebian/iods_8c-source.html
1360
					$offset = 0;
1361
					$atom_structure['version']                =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1362
					$offset += 1;
1363
					$atom_structure['flags_raw']              =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 3));
1364
					$offset += 3;
1365
					$atom_structure['mp4_iod_tag']            =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1366
					$offset += 1;
1367
					$atom_structure['length']                 = $this->quicktime_read_mp4_descr_length($atom_data, $offset);
1368
					//$offset already adjusted by quicktime_read_mp4_descr_length()
1369
					$atom_structure['object_descriptor_id']   =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2));
1370
					$offset += 2;
1371
					$atom_structure['od_profile_level']       =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1372
					$offset += 1;
1373
					$atom_structure['scene_profile_level']    =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1374
					$offset += 1;
1375
					$atom_structure['audio_profile_id']       =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1376
					$offset += 1;
1377
					$atom_structure['video_profile_id']       =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1378
					$offset += 1;
1379
					$atom_structure['graphics_profile_level'] =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1380
					$offset += 1;
1381
1382
					$atom_structure['num_iods_tracks'] = ($atom_structure['length'] - 7) / 6; // 6 bytes would only be right if all tracks use 1-byte length fields
1383 View Code Duplication
					for ($i = 0; $i < $atom_structure['num_iods_tracks']; $i++) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1384
						$atom_structure['track'][$i]['ES_ID_IncTag'] =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1385
						$offset += 1;
1386
						$atom_structure['track'][$i]['length']       = $this->quicktime_read_mp4_descr_length($atom_data, $offset);
1387
						//$offset already adjusted by quicktime_read_mp4_descr_length()
1388
						$atom_structure['track'][$i]['track_id']     =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4));
1389
						$offset += 4;
1390
					}
1391
1392
					$atom_structure['audio_profile_name'] = $this->QuicktimeIODSaudioProfileName($atom_structure['audio_profile_id']);
1393
					$atom_structure['video_profile_name'] = $this->QuicktimeIODSvideoProfileName($atom_structure['video_profile_id']);
1394
					break;
1395
1396 View Code Duplication
				case 'ftyp': // FileTYPe (?) atom (for MP4 it seems)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1397
					$atom_structure['signature'] =                           substr($atom_data,  0, 4);
1398
					$atom_structure['unknown_1'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1399
					$atom_structure['fourcc']    =                           substr($atom_data,  8, 4);
1400
					break;
1401
1402
				case 'mdat': // Media DATa atom
1403
					// 'mdat' contains the actual data for the audio/video, possibly also subtitles
1404
1405
	/* due to lack of known documentation, this is a kludge implementation. If you know of documentation on how mdat is properly structed, please send it to [email protected] */
1406
1407
					// first, skip any 'wide' padding, and second 'mdat' header (with specified size of zero?)
1408
					$mdat_offset = 0;
1409
					while (true) {
1410
						if (substr($atom_data, $mdat_offset, 8) == "\x00\x00\x00\x08".'wide') {
1411
							$mdat_offset += 8;
1412
						} elseif (substr($atom_data, $mdat_offset, 8) == "\x00\x00\x00\x00".'mdat') {
1413
							$mdat_offset += 8;
1414
						} else {
1415
							break;
1416
						}
1417
					}
1418
					if (substr($atom_data, $mdat_offset, 4) == 'GPRO') {
1419
						$GOPRO_chunk_length = getid3_lib::LittleEndian2Int(substr($atom_data, $mdat_offset + 4, 4));
1420
						$GOPRO_offset = 8;
0 ignored issues
show
Unused Code introduced by
$GOPRO_offset is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1421
						$atom_structure['GPRO']['raw'] = substr($atom_data, $mdat_offset + 8, $GOPRO_chunk_length - 8);
1422
						$atom_structure['GPRO']['firmware'] = substr($atom_structure['GPRO']['raw'],  0, 15);
1423
						$atom_structure['GPRO']['unknown1'] = substr($atom_structure['GPRO']['raw'], 15, 16);
1424
						$atom_structure['GPRO']['unknown2'] = substr($atom_structure['GPRO']['raw'], 31, 32);
1425
						$atom_structure['GPRO']['unknown3'] = substr($atom_structure['GPRO']['raw'], 63, 16);
1426
						$atom_structure['GPRO']['camera']   = substr($atom_structure['GPRO']['raw'], 79, 32);
1427
						$info['quicktime']['camera']['model'] = rtrim($atom_structure['GPRO']['camera'], "\x00");
1428
					}
1429
1430
					// check to see if it looks like chapter titles, in the form of unterminated strings with a leading 16-bit size field
1431
					while (($mdat_offset < (strlen($atom_data) - 8))
1432
						&& ($chapter_string_length = getid3_lib::BigEndian2Int(substr($atom_data, $mdat_offset, 2)))
1433
						&& ($chapter_string_length < 1000)
1434
						&& ($chapter_string_length <= (strlen($atom_data) - $mdat_offset - 2))
1435
						&& preg_match('#^([\x00-\xFF]{2})([\x20-\xFF]+)$#', substr($atom_data, $mdat_offset, $chapter_string_length + 2), $chapter_matches)) {
1436
							list($dummy, $chapter_string_length_hex, $chapter_string) = $chapter_matches;
0 ignored issues
show
Unused Code introduced by
The assignment to $dummy is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
Unused Code introduced by
The assignment to $chapter_string_length_hex is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
1437
							$mdat_offset += (2 + $chapter_string_length);
1438
							@$info['quicktime']['comments']['chapters'][] = $chapter_string;
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1439
1440
							// "encd" atom specifies encoding. In theory could be anything, almost always UTF-8, but may be UTF-16 with BOM (not currently handled)
1441
							if (substr($atom_data, $mdat_offset, 12) == "\x00\x00\x00\x0C\x65\x6E\x63\x64\x00\x00\x01\x00") { // UTF-8
1442
								$mdat_offset += 12;
1443
							}
1444
					}
1445
1446
					if (($atomsize > 8) && (!isset($info['avdataend_tmp']) || ($info['quicktime'][$atomname]['size'] > ($info['avdataend_tmp'] - $info['avdataoffset'])))) {
1447
1448
						$info['avdataoffset'] = $atom_structure['offset'] + 8;                       // $info['quicktime'][$atomname]['offset'] + 8;
1449
						$OldAVDataEnd         = $info['avdataend'];
1450
						$info['avdataend']    = $atom_structure['offset'] + $atom_structure['size']; // $info['quicktime'][$atomname]['offset'] + $info['quicktime'][$atomname]['size'];
1451
1452
						$getid3_temp = new getID3();
1453
						$getid3_temp->openfile($this->getid3->filename);
1454
						$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
1455
						$getid3_temp->info['avdataend']    = $info['avdataend'];
1456
						$getid3_mp3 = new getid3_mp3($getid3_temp);
1457
						if ($getid3_mp3->MPEGaudioHeaderValid($getid3_mp3->MPEGaudioHeaderDecode($this->fread(4)))) {
0 ignored issues
show
Security Bug introduced by
It seems like $this->fread(4) targeting getid3_handler::fread() can also be of type false; however, getid3_mp3::MPEGaudioHeaderDecode() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
Security Bug introduced by
It seems like $getid3_mp3->MPEGaudioHe...Decode($this->fread(4)) targeting getid3_mp3::MPEGaudioHeaderDecode() can also be of type false; however, getid3_mp3::MPEGaudioHeaderValid() does only seem to accept array, did you maybe forget to handle an error condition?
Loading history...
1458
							$getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false);
1459
							if (!empty($getid3_temp->info['warning'])) {
1460
								foreach ($getid3_temp->info['warning'] as $value) {
1461
									$this->warning($value);
1462
								}
1463
							}
1464
							if (!empty($getid3_temp->info['mpeg'])) {
1465
								$info['mpeg'] = $getid3_temp->info['mpeg'];
1466
								if (isset($info['mpeg']['audio'])) {
1467
									$info['audio']['dataformat']   = 'mp3';
1468
									$info['audio']['codec']        = (!empty($info['mpeg']['audio']['encoder']) ? $info['mpeg']['audio']['encoder'] : (!empty($info['mpeg']['audio']['codec']) ? $info['mpeg']['audio']['codec'] : (!empty($info['mpeg']['audio']['LAME']) ? 'LAME' :'mp3')));
1469
									$info['audio']['sample_rate']  = $info['mpeg']['audio']['sample_rate'];
1470
									$info['audio']['channels']     = $info['mpeg']['audio']['channels'];
1471
									$info['audio']['bitrate']      = $info['mpeg']['audio']['bitrate'];
1472
									$info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
1473
									$info['bitrate']               = $info['audio']['bitrate'];
1474
								}
1475
							}
1476
						}
1477
						unset($getid3_mp3, $getid3_temp);
1478
						$info['avdataend'] = $OldAVDataEnd;
1479
						unset($OldAVDataEnd);
1480
1481
					}
1482
1483
					unset($mdat_offset, $chapter_string_length, $chapter_matches);
1484
					break;
1485
1486
				case 'free': // FREE space atom
1487
				case 'skip': // SKIP atom
1488
				case 'wide': // 64-bit expansion placeholder atom
1489
					// 'free', 'skip' and 'wide' are just padding, contains no useful data at all
1490
1491
					// When writing QuickTime files, it is sometimes necessary to update an atom's size.
1492
					// It is impossible to update a 32-bit atom to a 64-bit atom since the 32-bit atom
1493
					// is only 8 bytes in size, and the 64-bit atom requires 16 bytes. Therefore, QuickTime
1494
					// puts an 8-byte placeholder atom before any atoms it may have to update the size of.
1495
					// In this way, if the atom needs to be converted from a 32-bit to a 64-bit atom, the
1496
					// placeholder atom can be overwritten to obtain the necessary 8 extra bytes.
1497
					// The placeholder atom has a type of kWideAtomPlaceholderType ( 'wide' ).
1498
					break;
1499
1500
1501
				case 'nsav': // NoSAVe atom
1502
					// http://developer.apple.com/technotes/tn/tn2038.html
1503
					$atom_structure['data'] = getid3_lib::BigEndian2Int(substr($atom_data,  0, 4));
1504
					break;
1505
1506
				case 'ctyp': // Controller TYPe atom (seen on QTVR)
1507
					// http://homepages.slingshot.co.nz/~helmboy/quicktime/formats/qtm-layout.txt
1508
					// some controller names are:
1509
					//   0x00 + 'std' for linear movie
1510
					//   'none' for no controls
1511
					$atom_structure['ctyp'] = substr($atom_data, 0, 4);
1512
					$info['quicktime']['controller'] = $atom_structure['ctyp'];
1513
					switch ($atom_structure['ctyp']) {
1514
						case 'qtvr':
1515
							$info['video']['dataformat'] = 'quicktimevr';
1516
							break;
1517
					}
1518
					break;
1519
1520
				case 'pano': // PANOrama track (seen on QTVR)
1521
					$atom_structure['pano'] = getid3_lib::BigEndian2Int(substr($atom_data,  0, 4));
1522
					break;
1523
1524
				case 'hint': // HINT track
1525
				case 'hinf': //
1526
				case 'hinv': //
1527
				case 'hnti': //
1528
					$info['quicktime']['hinting'] = true;
1529
					break;
1530
1531
				case 'imgt': // IMaGe Track reference (kQTVRImageTrackRefType) (seen on QTVR)
1532
					for ($i = 0; $i < ($atom_structure['size'] - 8); $i += 4) {
1533
						$atom_structure['imgt'][] = getid3_lib::BigEndian2Int(substr($atom_data, $i, 4));
1534
					}
1535
					break;
1536
1537
1538
				// Observed-but-not-handled atom types are just listed here to prevent warnings being generated
1539
				case 'FXTC': // Something to do with Adobe After Effects (?)
1540
				case 'PrmA':
1541
				case 'code':
1542
				case 'FIEL': // this is NOT "fiel" (Field Ordering) as describe here: http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap3/chapter_4_section_2.html
1543
				case 'tapt': // TrackApertureModeDimensionsAID - http://developer.apple.com/documentation/QuickTime/Reference/QT7-1_Update_Reference/Constants/Constants.html
1544
							// tapt seems to be used to compute the video size [https://www.getid3.org/phpBB3/viewtopic.php?t=838]
1545
							// * http://lists.apple.com/archives/quicktime-api/2006/Aug/msg00014.html
1546
							// * http://handbrake.fr/irclogs/handbrake-dev/handbrake-dev20080128_pg2.html
1547
				case 'ctts'://  STCompositionOffsetAID             - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
1548
				case 'cslg'://  STCompositionShiftLeastGreatestAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
1549
				case 'sdtp'://  STSampleDependencyAID              - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
1550
				case 'stps'://  STPartialSyncSampleAID             - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
1551
					//$atom_structure['data'] = $atom_data;
1552
					break;
1553
1554
				case "\xA9".'xyz':  // GPS latitude+longitude+altitude
1555
					$atom_structure['data'] = $atom_data;
1556
					if (preg_match('#([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)?/$#i', $atom_data, $matches)) {
1557
						@list($all, $latitude, $longitude, $altitude) = $matches;
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1558
						$info['quicktime']['comments']['gps_latitude'][]  = floatval($latitude);
1559
						$info['quicktime']['comments']['gps_longitude'][] = floatval($longitude);
1560
						if (!empty($altitude)) {
1561
							$info['quicktime']['comments']['gps_altitude'][] = floatval($altitude);
1562
						}
1563
					} else {
1564
						$this->warning('QuickTime atom "©xyz" data does not match expected data pattern at offset '.$baseoffset.'. Please report as getID3() bug.');
1565
					}
1566
					break;
1567
1568
				case 'NCDT':
1569
					// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
1570
					// Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
1571
					$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms);
1572
					break;
1573
				case 'NCTH': // Nikon Camera THumbnail image
1574
				case 'NCVW': // Nikon Camera preVieW image
1575
					// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
1576
					if (preg_match('/^\xFF\xD8\xFF/', $atom_data)) {
1577
						$atom_structure['data'] = $atom_data;
1578
						$atom_structure['image_mime'] = 'image/jpeg';
1579
						$atom_structure['description'] = (($atomname == 'NCTH') ? 'Nikon Camera Thumbnail Image' : (($atomname == 'NCVW') ? 'Nikon Camera Preview Image' : 'Nikon preview image'));
1580
						$info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_data, 'description'=>$atom_structure['description']);
1581
					}
1582
					break;
1583
				case 'NCTG': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
1584
					$atom_structure['data'] = $this->QuicktimeParseNikonNCTG($atom_data);
1585
					break;
1586
				case 'NCHD': // Nikon:MakerNoteVersion  - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
1587
				case 'NCDB': // Nikon                   - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
1588
				case 'CNCV': // Canon:CompressorVersion - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Canon.html
1589
					$atom_structure['data'] = $atom_data;
1590
					break;
1591
1592 View Code Duplication
				case "\x00\x00\x00\x00":
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1593
					// some kind of metacontainer, may contain a big data dump such as:
1594
					// mdta keys \005 mdtacom.apple.quicktime.make (mdtacom.apple.quicktime.creationdate ,mdtacom.apple.quicktime.location.ISO6709 $mdtacom.apple.quicktime.software !mdtacom.apple.quicktime.model ilst \01D \001 \015data \001DE\010Apple 0 \002 (data \001DE\0102011-05-11T17:54:04+0200 2 \003 *data \001DE\010+52.4936+013.3897+040.247/ \01D \004 \015data \001DE\0104.3.1 \005 \018data \001DE\010iPhone 4
1595
					// http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt
1596
1597
					$atom_structure['version']   =          getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1598
					$atom_structure['flags_raw'] =          getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
1599
					$atom_structure['subatoms']  = $this->QuicktimeParseContainerAtom(substr($atom_data, 4), $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
1600
					//$atom_structure['subatoms']  = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
1601
					break;
1602
1603 View Code Duplication
				case 'meta': // METAdata atom
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1604
					// https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/Metadata/Metadata.html
1605
1606
					$atom_structure['version']   =          getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1607
					$atom_structure['flags_raw'] =          getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
1608
					$atom_structure['subatoms']  = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
1609
					break;
1610
1611
				case 'data': // metaDATA atom
1612
					static $metaDATAkey = 1; // real ugly, but so is the QuickTime structure that stores keys and values in different multinested locations that are hard to relate to each other
1613
					// seems to be 2 bytes language code (ASCII), 2 bytes unknown (set to 0x10B5 in sample I have), remainder is useful data
1614
					$atom_structure['language'] =                           substr($atom_data, 4 + 0, 2);
1615
					$atom_structure['unknown']  = getid3_lib::BigEndian2Int(substr($atom_data, 4 + 2, 2));
1616
					$atom_structure['data']     =                           substr($atom_data, 4 + 4);
1617
					$atom_structure['key_name'] = @$info['quicktime']['temp_meta_key_names'][$metaDATAkey++];
1618
1619
					if ($atom_structure['key_name'] && $atom_structure['data']) {
1620
						@$info['quicktime']['comments'][str_replace('com.apple.quicktime.', '', $atom_structure['key_name'])][] = $atom_structure['data'];
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1621
					}
1622
					break;
1623
1624
				case 'keys': // KEYS that may be present in the metadata atom.
1625
					// https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW21
1626
					// The metadata item keys atom holds a list of the metadata keys that may be present in the metadata atom.
1627
					// This list is indexed starting with 1; 0 is a reserved index value. The metadata item keys atom is a full atom with an atom type of "keys".
1628
					$atom_structure['version']       = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1629
					$atom_structure['flags_raw']     = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3));
1630
					$atom_structure['entry_count']   = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1631
					$keys_atom_offset = 8;
1632
					for ($i = 1; $i <= $atom_structure['entry_count']; $i++) {
1633
						$atom_structure['keys'][$i]['key_size']      = getid3_lib::BigEndian2Int(substr($atom_data, $keys_atom_offset + 0, 4));
1634
						$atom_structure['keys'][$i]['key_namespace'] =                           substr($atom_data, $keys_atom_offset + 4, 4);
1635
						$atom_structure['keys'][$i]['key_value']     =                           substr($atom_data, $keys_atom_offset + 8, $atom_structure['keys'][$i]['key_size'] - 8);
1636
						$keys_atom_offset += $atom_structure['keys'][$i]['key_size']; // key_size includes the 4+4 bytes for key_size and key_namespace
1637
1638
						$info['quicktime']['temp_meta_key_names'][$i] = $atom_structure['keys'][$i]['key_value'];
1639
					}
1640
					break;
1641
1642
				case 'uuid': // Atom holding 360fly spatial data??
1643
					/* code in this block by Paul Lewis 2019-Oct-31 */
1644
					/*	Sensor Timestamps need to be calculated using the recordings base time at ['quicktime']['moov']['subatoms'][0]['creation_time_unix']. */
1645
					$atom_structure['title'] = '360Fly Sensor Data';
1646
1647
					//Get the UUID ID in first 16 bytes
1648
					$uuid_bytes_read = unpack('H8time_low/H4time_mid/H4time_hi/H4clock_seq_hi/H12clock_seq_low', substr($atom_data, 0, 16));
1649
					$atom_structure['uuid_field_id'] = print_r(implode('-', $uuid_bytes_read), true);
1650
1651
					//Get the UUID HEADER data
1652
					$uuid_bytes_read = unpack('Sheader_size/Sheader_version/Stimescale/Shardware_version/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/', substr($atom_data, 16, 32));
1653
					$atom_structure['uuid_header'] = json_encode($uuid_bytes_read, true);
1654
1655
					$start_byte = 48;
1656
					$atom_SENSOR_data = substr($atom_data, $start_byte);
1657
					$atom_structure['sensor_data']['data_type'] = array(
1658
							'fusion_count'   => 0,       // ID 250
1659
							'fusion_data'    => array(),
1660
							'accel_count'    => 0,       // ID 1
1661
							'accel_data'     => array(),
1662
							'gyro_count'     => 0,       // ID 2
1663
							'gyro_data'      => array(),
1664
							'magno_count'    => 0,       // ID 3
1665
							'magno_data'     => array(),
1666
							'gps_count'      => 0,       // ID 5
1667
							'gps_data'       => array(),
1668
							'rotation_count' => 0,       // ID 6
1669
							'rotation_data'  => array(),
1670
							'unknown_count'  => 0,       // ID ??
1671
							'unknown_data'   => array(),
1672
							'debug_list'     => '',      // Used to debug variables stored as comma delimited strings
1673
					);
1674
					$debug_structure['debug_items'] = array();
0 ignored issues
show
Coding Style Comprehensibility introduced by
$debug_structure was never initialized. Although not strictly required by PHP, it is generally a good practice to add $debug_structure = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1675
					// Can start loop here to decode all sensor data in 32 Byte chunks:
1676
					foreach (str_split($atom_SENSOR_data, 32) as $sensor_key => $sensor_data) {
1677
						// This gets me a data_type code to work out what data is in the next 31 bytes.
1678
						$sensor_data_type = substr($sensor_data, 0, 1);
1679
						$sensor_data_content = substr($sensor_data, 1);
1680
						$uuid_bytes_read = unpack('C*', $sensor_data_type);
1681
						$sensor_data_array = array();
1682
						switch ($uuid_bytes_read[1]) {
1683 View Code Duplication
							case 250:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1684
								$atom_structure['sensor_data']['data_type']['fusion_count']++;
1685
								$uuid_bytes_read = unpack('cmode/Jtimestamp/Gyaw/Gpitch/Groll/x*', $sensor_data_content);
1686
								$sensor_data_array['mode']      = $uuid_bytes_read['mode'];
1687
								$sensor_data_array['timestamp'] = $uuid_bytes_read['timestamp'];
1688
								$sensor_data_array['yaw']       = $uuid_bytes_read['yaw'];
1689
								$sensor_data_array['pitch']     = $uuid_bytes_read['pitch'];
1690
								$sensor_data_array['roll']      = $uuid_bytes_read['roll'];
1691
								array_push($atom_structure['sensor_data']['data_type']['fusion_data'], $sensor_data_array);
1692
								break;
1693 View Code Duplication
							case 1:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1694
								$atom_structure['sensor_data']['data_type']['accel_count']++;
1695
								$uuid_bytes_read = unpack('cmode/Jtimestamp/Gyaw/Gpitch/Groll/x*', $sensor_data_content);
1696
								$sensor_data_array['mode']      = $uuid_bytes_read['mode'];
1697
								$sensor_data_array['timestamp'] = $uuid_bytes_read['timestamp'];
1698
								$sensor_data_array['yaw']       = $uuid_bytes_read['yaw'];
1699
								$sensor_data_array['pitch']     = $uuid_bytes_read['pitch'];
1700
								$sensor_data_array['roll']      = $uuid_bytes_read['roll'];
1701
								array_push($atom_structure['sensor_data']['data_type']['accel_data'], $sensor_data_array);
1702
								break;
1703 View Code Duplication
							case 2:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1704
								$atom_structure['sensor_data']['data_type']['gyro_count']++;
1705
								$uuid_bytes_read = unpack('cmode/Jtimestamp/Gyaw/Gpitch/Groll/x*', $sensor_data_content);
1706
								$sensor_data_array['mode']      = $uuid_bytes_read['mode'];
1707
								$sensor_data_array['timestamp'] = $uuid_bytes_read['timestamp'];
1708
								$sensor_data_array['yaw']       = $uuid_bytes_read['yaw'];
1709
								$sensor_data_array['pitch']     = $uuid_bytes_read['pitch'];
1710
								$sensor_data_array['roll']      = $uuid_bytes_read['roll'];
1711
								array_push($atom_structure['sensor_data']['data_type']['gyro_data'], $sensor_data_array);
1712
								break;
1713 View Code Duplication
							case 3:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1714
								$atom_structure['sensor_data']['data_type']['magno_count']++;
1715
								$uuid_bytes_read = unpack('cmode/Jtimestamp/Gmagx/Gmagy/Gmagz/x*', $sensor_data_content);
1716
								$sensor_data_array['mode']      = $uuid_bytes_read['mode'];
1717
								$sensor_data_array['timestamp'] = $uuid_bytes_read['timestamp'];
1718
								$sensor_data_array['magx']      = $uuid_bytes_read['magx'];
1719
								$sensor_data_array['magy']      = $uuid_bytes_read['magy'];
1720
								$sensor_data_array['magz']      = $uuid_bytes_read['magz'];
1721
								array_push($atom_structure['sensor_data']['data_type']['magno_data'], $sensor_data_array);
1722
								break;
1723
							case 5:
1724
								$atom_structure['sensor_data']['data_type']['gps_count']++;
1725
								$uuid_bytes_read = unpack('cmode/Jtimestamp/Glat/Glon/Galt/Gspeed/nbearing/nacc/x*', $sensor_data_content);
1726
								$sensor_data_array['mode']      = $uuid_bytes_read['mode'];
1727
								$sensor_data_array['timestamp'] = $uuid_bytes_read['timestamp'];
1728
								$sensor_data_array['lat']       = $uuid_bytes_read['lat'];
1729
								$sensor_data_array['lon']       = $uuid_bytes_read['lon'];
1730
								$sensor_data_array['alt']       = $uuid_bytes_read['alt'];
1731
								$sensor_data_array['speed']     = $uuid_bytes_read['speed'];
1732
								$sensor_data_array['bearing']   = $uuid_bytes_read['bearing'];
1733
								$sensor_data_array['acc']       = $uuid_bytes_read['acc'];
1734
								//$sensor_data_array = print_r($uuid_bytes_read, true);
1735
								array_push($atom_structure['sensor_data']['data_type']['gps_data'], $sensor_data_array);
1736
								//array_push($debug_structure['debug_items'], $uuid_bytes_read['timestamp']);
1737
								break;
1738 View Code Duplication
							case 6:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1739
								$atom_structure['sensor_data']['data_type']['rotation_count']++;
1740
								$uuid_bytes_read = unpack('cmode/Jtimestamp/Grotx/Groty/Grotz/x*', $sensor_data_content);
1741
								$sensor_data_array['mode']      = $uuid_bytes_read['mode'];
1742
								$sensor_data_array['timestamp'] = $uuid_bytes_read['timestamp'];
1743
								$sensor_data_array['rotx']      = $uuid_bytes_read['rotx'];
1744
								$sensor_data_array['roty']      = $uuid_bytes_read['roty'];
1745
								$sensor_data_array['rotz']      = $uuid_bytes_read['rotz'];
1746
								array_push($atom_structure['sensor_data']['data_type']['rotation_data'], $sensor_data_array);
1747
								break;
1748
							default:
1749
								$atom_structure['sensor_data']['data_type']['unknown_count']++;
1750
								break;
1751
						}
1752
					}
1753
//					if (isset($debug_structure['debug_items']) && count($debug_structure['debug_items']) > 0) {
1754
//						$atom_structure['sensor_data']['data_type']['debug_list'] = implode(',', $debug_structure['debug_items']);
1755
//					} else {
1756
						$atom_structure['sensor_data']['data_type']['debug_list'] = 'No debug items in list!';
1757
//					}
1758
					break;
1759
1760
				case 'gps ':
1761
					// https://dashcamtalk.com/forum/threads/script-to-extract-gps-data-from-novatek-mp4.20808/page-2#post-291730
1762
					// The 'gps ' contains simple look up table made up of 8byte rows, that point to the 'free' atoms that contains the actual GPS data.
1763
					// The first row is version/metadata/notsure, I skip that.
1764
					// The following rows consist of 4byte address (absolute) and 4byte size (0x1000), these point to the GPS data in the file.
1765
1766
					$GPS_rowsize = 8; // 4 bytes for offset, 4 bytes for size
1767
					if (strlen($atom_data) > 0) {
1768
						if ((strlen($atom_data) % $GPS_rowsize) == 0) {
1769
							$atom_structure['gps_toc'] = array();
1770
							foreach (str_split($atom_data, $GPS_rowsize) as $counter => $datapair) {
1771
								$atom_structure['gps_toc'][] = unpack('Noffset/Nsize', substr($atom_data, $counter * $GPS_rowsize, $GPS_rowsize));
1772
							}
1773
1774
							$atom_structure['gps_entries'] = array();
1775
							$previous_offset = $this->ftell();
1776
							foreach ($atom_structure['gps_toc'] as $key => $gps_pointer) {
1777
								if ($key == 0) {
1778
									// "The first row is version/metadata/notsure, I skip that."
1779
									continue;
1780
								}
1781
								$this->fseek($gps_pointer['offset']);
1782
								$GPS_free_data = $this->fread($gps_pointer['size']);
1783
1784
								/*
1785
								// 2017-05-10: I see some of the data, notably the Hour-Minute-Second, but cannot reconcile the rest of the data. However, the NMEA "GPRMC" line is there and relatively easy to parse, so I'm using that instead
1786
1787
								// https://dashcamtalk.com/forum/threads/script-to-extract-gps-data-from-novatek-mp4.20808/page-2#post-291730
1788
								// The structure of the GPS data atom (the 'free' atoms mentioned above) is following:
1789
								// hour,minute,second,year,month,day,active,latitude_b,longitude_b,unknown2,latitude,longitude,speed = struct.unpack_from('<IIIIIIssssfff',data, 48)
1790
								// For those unfamiliar with python struct:
1791
								// I = int
1792
								// s = is string (size 1, in this case)
1793
								// f = float
1794
1795
								//$atom_structure['gps_entries'][$key] = unpack('Vhour/Vminute/Vsecond/Vyear/Vmonth/Vday/Vactive/Vlatitude_b/Vlongitude_b/Vunknown2/flatitude/flongitude/fspeed', substr($GPS_free_data, 48));
1796
								*/
1797
1798
								// $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62
1799
								// $GPRMC,183731,A,3907.482,N,12102.436,W,000.0,360.0,080301,015.5,E*67
1800
								// $GPRMC,002454,A,3553.5295,N,13938.6570,E,0.0,43.1,180700,7.1,W,A*3F
1801
								// $GPRMC,094347.000,A,5342.0061,N,00737.9908,W,0.01,156.75,140217,,,A*7D
1802
								if (preg_match('#\\$GPRMC,([0-9\\.]*),([AV]),([0-9\\.]*),([NS]),([0-9\\.]*),([EW]),([0-9\\.]*),([0-9\\.]*),([0-9]*),([0-9\\.]*),([EW]?)(,[A])?(\\*[0-9A-F]{2})#', $GPS_free_data, $matches)) {
1803
									$GPS_this_GPRMC = array();
1804
									$GPS_this_GPRMC_raw = array();
1805
									list(
1806
										$GPS_this_GPRMC_raw['gprmc'],
1807
										$GPS_this_GPRMC_raw['timestamp'],
1808
										$GPS_this_GPRMC_raw['status'],
1809
										$GPS_this_GPRMC_raw['latitude'],
1810
										$GPS_this_GPRMC_raw['latitude_direction'],
1811
										$GPS_this_GPRMC_raw['longitude'],
1812
										$GPS_this_GPRMC_raw['longitude_direction'],
1813
										$GPS_this_GPRMC_raw['knots'],
1814
										$GPS_this_GPRMC_raw['angle'],
1815
										$GPS_this_GPRMC_raw['datestamp'],
1816
										$GPS_this_GPRMC_raw['variation'],
1817
										$GPS_this_GPRMC_raw['variation_direction'],
1818
										$dummy,
0 ignored issues
show
Unused Code introduced by
The assignment to $dummy is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
1819
										$GPS_this_GPRMC_raw['checksum'],
1820
									) = $matches;
1821
									$GPS_this_GPRMC['raw'] = $GPS_this_GPRMC_raw;
1822
1823
									$hour   = substr($GPS_this_GPRMC['raw']['timestamp'], 0, 2);
1824
									$minute = substr($GPS_this_GPRMC['raw']['timestamp'], 2, 2);
1825
									$second = substr($GPS_this_GPRMC['raw']['timestamp'], 4, 2);
1826
									$ms     = substr($GPS_this_GPRMC['raw']['timestamp'], 6);    // may contain decimal seconds
1827
									$day    = substr($GPS_this_GPRMC['raw']['datestamp'], 0, 2);
1828
									$month  = substr($GPS_this_GPRMC['raw']['datestamp'], 2, 2);
1829
									$year   = (int) substr($GPS_this_GPRMC['raw']['datestamp'], 4, 2);
1830
									$year += (($year > 90) ? 1900 : 2000); // complete lack of foresight: datestamps are stored with 2-digit years, take best guess
1831
									$GPS_this_GPRMC['timestamp'] = $year.'-'.$month.'-'.$day.' '.$hour.':'.$minute.':'.$second.$ms;
1832
1833
									$GPS_this_GPRMC['active'] = ($GPS_this_GPRMC['raw']['status'] == 'A'); // A=Active,V=Void
1834
1835
									foreach (array('latitude','longitude') as $latlon) {
1836
										preg_match('#^([0-9]{1,3})([0-9]{2}\\.[0-9]+)$#', $GPS_this_GPRMC['raw'][$latlon], $matches);
1837
										list($dummy, $deg, $min) = $matches;
0 ignored issues
show
Unused Code introduced by
The assignment to $dummy is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
1838
										$GPS_this_GPRMC[$latlon] = $deg + ($min / 60);
1839
									}
1840
									$GPS_this_GPRMC['latitude']  *= (($GPS_this_GPRMC['raw']['latitude_direction']  == 'S') ? -1 : 1);
1841
									$GPS_this_GPRMC['longitude'] *= (($GPS_this_GPRMC['raw']['longitude_direction'] == 'W') ? -1 : 1);
1842
1843
									$GPS_this_GPRMC['heading']    = $GPS_this_GPRMC['raw']['angle'];
1844
									$GPS_this_GPRMC['speed_knot'] = $GPS_this_GPRMC['raw']['knots'];
1845
									$GPS_this_GPRMC['speed_kmh']  = $GPS_this_GPRMC['raw']['knots'] * 1.852;
1846
									if ($GPS_this_GPRMC['raw']['variation']) {
1847
										$GPS_this_GPRMC['variation']  = $GPS_this_GPRMC['raw']['variation'];
1848
										$GPS_this_GPRMC['variation'] *= (($GPS_this_GPRMC['raw']['variation_direction'] == 'W') ? -1 : 1);
1849
									}
1850
1851
									$atom_structure['gps_entries'][$key] = $GPS_this_GPRMC;
1852
1853
									@$info['quicktime']['gps_track'][$GPS_this_GPRMC['timestamp']] = array(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1854
										'latitude'  => (float) $GPS_this_GPRMC['latitude'],
1855
										'longitude' => (float) $GPS_this_GPRMC['longitude'],
1856
										'speed_kmh' => (float) $GPS_this_GPRMC['speed_kmh'],
1857
										'heading'   => (float) $GPS_this_GPRMC['heading'],
1858
									);
1859
1860
								} else {
1861
									$this->warning('Unhandled GPS format in "free" atom at offset '.$gps_pointer['offset']);
1862
								}
1863
							}
1864
							$this->fseek($previous_offset);
0 ignored issues
show
Bug introduced by
It seems like $previous_offset defined by $this->ftell() on line 1775 can also be of type boolean; however, getid3_handler::fseek() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1865
1866
						} else {
1867
							$this->warning('QuickTime atom "'.$atomname.'" is not mod-8 bytes long ('.$atomsize.' bytes) at offset '.$baseoffset);
1868
						}
1869
					} else {
1870
						$this->warning('QuickTime atom "'.$atomname.'" is zero bytes long at offset '.$baseoffset);
1871
					}
1872
					break;
1873
1874
				case 'loci':// 3GP location (El Loco)
1875
					$loffset = 0;
1876
					$info['quicktime']['comments']['gps_flags']     = array(  getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)));
1877
					$info['quicktime']['comments']['gps_lang']      = array(  getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)));
1878
					$info['quicktime']['comments']['gps_location']  = array(          $this->LociString(substr($atom_data, 6), $loffset));
1879
					$loci_data = substr($atom_data, 6 + $loffset);
1880
					$info['quicktime']['comments']['gps_role']      = array(  getid3_lib::BigEndian2Int(substr($loci_data, 0, 1)));
1881
					$info['quicktime']['comments']['gps_longitude'] = array(getid3_lib::FixedPoint16_16(substr($loci_data, 1, 4)));
1882
					$info['quicktime']['comments']['gps_latitude']  = array(getid3_lib::FixedPoint16_16(substr($loci_data, 5, 4)));
1883
					$info['quicktime']['comments']['gps_altitude']  = array(getid3_lib::FixedPoint16_16(substr($loci_data, 9, 4)));
1884
					$info['quicktime']['comments']['gps_body']      = array(          $this->LociString(substr($loci_data, 13           ), $loffset));
1885
					$info['quicktime']['comments']['gps_notes']     = array(          $this->LociString(substr($loci_data, 13 + $loffset), $loffset));
1886
					break;
1887
1888
				case 'chpl': // CHaPter List
1889
					// https://www.adobe.com/content/dam/Adobe/en/devnet/flv/pdfs/video_file_format_spec_v10.pdf
1890
					$chpl_version = getid3_lib::BigEndian2Int(substr($atom_data, 4, 1)); // Expected to be 0
0 ignored issues
show
Unused Code introduced by
$chpl_version is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1891
					$chpl_flags   = getid3_lib::BigEndian2Int(substr($atom_data, 5, 3)); // Reserved, set to 0
0 ignored issues
show
Unused Code introduced by
$chpl_flags is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1892
					$chpl_count   = getid3_lib::BigEndian2Int(substr($atom_data, 8, 1));
1893
					$chpl_offset = 9;
1894
					for ($i = 0; $i < $chpl_count; $i++) {
1895
						if (($chpl_offset + 9) >= strlen($atom_data)) {
1896
							$this->warning('QuickTime chapter '.$i.' extends beyond end of "chpl" atom');
1897
							break;
1898
						}
1899
						$info['quicktime']['chapters'][$i]['timestamp'] = getid3_lib::BigEndian2Int(substr($atom_data, $chpl_offset, 8)) / 10000000; // timestamps are stored as 100-nanosecond units
1900
						$chpl_offset += 8;
1901
						$chpl_title_size = getid3_lib::BigEndian2Int(substr($atom_data, $chpl_offset, 1));
1902
						$chpl_offset += 1;
1903
						$info['quicktime']['chapters'][$i]['title']     =                           substr($atom_data, $chpl_offset, $chpl_title_size);
1904
						$chpl_offset += $chpl_title_size;
1905
					}
1906
					break;
1907
1908
				case 'FIRM': // FIRMware version(?), seen on GoPro Hero4
1909
					$info['quicktime']['camera']['firmware'] = $atom_data;
1910
					break;
1911
1912
				case 'CAME': // FIRMware version(?), seen on GoPro Hero4
1913
					$info['quicktime']['camera']['serial_hash'] = unpack('H*', $atom_data);
1914
					break;
1915
1916
				case 'dscp':
1917
				case 'rcif':
1918
					// https://www.getid3.org/phpBB3/viewtopic.php?t=1908
1919
					if (substr($atom_data, 0, 7) == "\x00\x00\x00\x00\x55\xC4".'{') {
1920
						if ($json_decoded = @json_decode(rtrim(substr($atom_data, 6), "\x00"), true)) {
1921
							$info['quicktime']['camera'][$atomname] = $json_decoded;
1922
							if (($atomname == 'rcif') && isset($info['quicktime']['camera']['rcif']['wxcamera']['rotate'])) {
1923
								$info['video']['rotate'] = $info['quicktime']['video']['rotate'] = $info['quicktime']['camera']['rcif']['wxcamera']['rotate'];
1924
							}
1925
						} else {
1926
							$this->warning('Failed to JSON decode atom "'.$atomname.'"');
1927
							$atom_structure['data'] = $atom_data;
1928
						}
1929
						unset($json_decoded);
1930
					} else {
1931
						$this->warning('Expecting 55 C4 7B at start of atom "'.$atomname.'", found '.getid3_lib::PrintHexBytes(substr($atom_data, 4, 3)).' instead');
1932
						$atom_structure['data'] = $atom_data;
1933
					}
1934
					break;
1935
1936
				case 'frea':
1937
					// https://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Kodak.html#frea
1938
					// may contain "scra" (PreviewImage) and/or "thma" (ThumbnailImage)
1939
					$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms);
1940
					break;
1941
				case 'tima': // subatom to "frea"
1942
					// no idea what this does, the one sample file I've seen has a value of 0x00000027
1943
					$atom_structure['data'] = $atom_data;
1944
					break;
1945
				case 'ver ': // subatom to "frea"
1946
					// some kind of version number, the one sample file I've seen has a value of "3.00.073"
1947
					$atom_structure['data'] = $atom_data;
1948
					break;
1949 View Code Duplication
				case 'thma': // subatom to "frea" -- "ThumbnailImage"
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1950
					// https://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Kodak.html#frea
1951
					if (strlen($atom_data) > 0) {
1952
						$info['quicktime']['comments']['picture'][] = array('data'=>$atom_data, 'image_mime'=>'image/jpeg');
1953
					}
1954
					break;
1955 View Code Duplication
				case 'scra': // subatom to "frea" -- "PreviewImage"
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1956
					// https://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Kodak.html#frea
1957
					// but the only sample file I've seen has no useful data here
1958
					if (strlen($atom_data) > 0) {
1959
						$info['quicktime']['comments']['picture'][] = array('data'=>$atom_data, 'image_mime'=>'image/jpeg');
1960
					}
1961
					break;
1962
1963
1964 View Code Duplication
				default:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1965
					$this->warning('Unknown QuickTime atom type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" ('.trim(getid3_lib::PrintHexBytes($atomname)).'), '.$atomsize.' bytes at offset '.$baseoffset);
1966
					$atom_structure['data'] = $atom_data;
1967
					break;
1968
			}
1969
		}
1970
		array_pop($atomHierarchy);
1971
		return $atom_structure;
1972
	}
1973
1974
	/**
1975
	 * @param string $atom_data
1976
	 * @param int    $baseoffset
1977
	 * @param array  $atomHierarchy
1978
	 * @param bool   $ParseAllPossibleAtoms
1979
	 *
1980
	 * @return array|false
1981
	 */
1982
	public function QuicktimeParseContainerAtom($atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
1983
		$atom_structure  = false;
1984
		$subatomoffset  = 0;
1985
		$subatomcounter = 0;
1986
		if ((strlen($atom_data) == 4) && (getid3_lib::BigEndian2Int($atom_data) == 0x00000000)) {
1987
			return false;
1988
		}
1989
		while ($subatomoffset < strlen($atom_data)) {
1990
			$subatomsize = getid3_lib::BigEndian2Int(substr($atom_data, $subatomoffset + 0, 4));
1991
			$subatomname =                           substr($atom_data, $subatomoffset + 4, 4);
1992
			$subatomdata =                           substr($atom_data, $subatomoffset + 8, $subatomsize - 8);
1993
			if ($subatomsize == 0) {
1994
				// Furthermore, for historical reasons the list of atoms is optionally
1995
				// terminated by a 32-bit integer set to 0. If you are writing a program
1996
				// to read user data atoms, you should allow for the terminating 0.
1997
				if (strlen($atom_data) > 12) {
1998
					$subatomoffset += 4;
1999
					continue;
2000
				}
2001
				return $atom_structure;
2002
			}
2003
			$atom_structure[$subatomcounter++] = $this->QuicktimeParseAtom($subatomname, $subatomsize, $subatomdata, $baseoffset + $subatomoffset, $atomHierarchy, $ParseAllPossibleAtoms);
2004
			$subatomoffset += $subatomsize;
2005
		}
2006
		return $atom_structure;
2007
	}
2008
2009
	/**
2010
	 * @param string $data
2011
	 * @param int    $offset
2012
	 *
2013
	 * @return int
2014
	 */
2015
	public function quicktime_read_mp4_descr_length($data, &$offset) {
2016
		// http://libquicktime.sourcearchive.com/documentation/2:1.0.2plus-pdebian-2build1/esds_8c-source.html
2017
		$num_bytes = 0;
2018
		$length    = 0;
2019
		do {
2020
			$b = ord(substr($data, $offset++, 1));
2021
			$length = ($length << 7) | ($b & 0x7F);
2022
		} while (($b & 0x80) && ($num_bytes++ < 4));
2023
		return $length;
2024
	}
2025
2026
	/**
2027
	 * @param int $languageid
2028
	 *
2029
	 * @return string
2030
	 */
2031
	public function QuicktimeLanguageLookup($languageid) {
2032
		// http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-34353
2033
		static $QuicktimeLanguageLookup = array();
2034
		if (empty($QuicktimeLanguageLookup)) {
2035
			$QuicktimeLanguageLookup[0]     = 'English';
2036
			$QuicktimeLanguageLookup[1]     = 'French';
2037
			$QuicktimeLanguageLookup[2]     = 'German';
2038
			$QuicktimeLanguageLookup[3]     = 'Italian';
2039
			$QuicktimeLanguageLookup[4]     = 'Dutch';
2040
			$QuicktimeLanguageLookup[5]     = 'Swedish';
2041
			$QuicktimeLanguageLookup[6]     = 'Spanish';
2042
			$QuicktimeLanguageLookup[7]     = 'Danish';
2043
			$QuicktimeLanguageLookup[8]     = 'Portuguese';
2044
			$QuicktimeLanguageLookup[9]     = 'Norwegian';
2045
			$QuicktimeLanguageLookup[10]    = 'Hebrew';
2046
			$QuicktimeLanguageLookup[11]    = 'Japanese';
2047
			$QuicktimeLanguageLookup[12]    = 'Arabic';
2048
			$QuicktimeLanguageLookup[13]    = 'Finnish';
2049
			$QuicktimeLanguageLookup[14]    = 'Greek';
2050
			$QuicktimeLanguageLookup[15]    = 'Icelandic';
2051
			$QuicktimeLanguageLookup[16]    = 'Maltese';
2052
			$QuicktimeLanguageLookup[17]    = 'Turkish';
2053
			$QuicktimeLanguageLookup[18]    = 'Croatian';
2054
			$QuicktimeLanguageLookup[19]    = 'Chinese (Traditional)';
2055
			$QuicktimeLanguageLookup[20]    = 'Urdu';
2056
			$QuicktimeLanguageLookup[21]    = 'Hindi';
2057
			$QuicktimeLanguageLookup[22]    = 'Thai';
2058
			$QuicktimeLanguageLookup[23]    = 'Korean';
2059
			$QuicktimeLanguageLookup[24]    = 'Lithuanian';
2060
			$QuicktimeLanguageLookup[25]    = 'Polish';
2061
			$QuicktimeLanguageLookup[26]    = 'Hungarian';
2062
			$QuicktimeLanguageLookup[27]    = 'Estonian';
2063
			$QuicktimeLanguageLookup[28]    = 'Lettish';
2064
			$QuicktimeLanguageLookup[28]    = 'Latvian';
2065
			$QuicktimeLanguageLookup[29]    = 'Saamisk';
2066
			$QuicktimeLanguageLookup[29]    = 'Lappish';
2067
			$QuicktimeLanguageLookup[30]    = 'Faeroese';
2068
			$QuicktimeLanguageLookup[31]    = 'Farsi';
2069
			$QuicktimeLanguageLookup[31]    = 'Persian';
2070
			$QuicktimeLanguageLookup[32]    = 'Russian';
2071
			$QuicktimeLanguageLookup[33]    = 'Chinese (Simplified)';
2072
			$QuicktimeLanguageLookup[34]    = 'Flemish';
2073
			$QuicktimeLanguageLookup[35]    = 'Irish';
2074
			$QuicktimeLanguageLookup[36]    = 'Albanian';
2075
			$QuicktimeLanguageLookup[37]    = 'Romanian';
2076
			$QuicktimeLanguageLookup[38]    = 'Czech';
2077
			$QuicktimeLanguageLookup[39]    = 'Slovak';
2078
			$QuicktimeLanguageLookup[40]    = 'Slovenian';
2079
			$QuicktimeLanguageLookup[41]    = 'Yiddish';
2080
			$QuicktimeLanguageLookup[42]    = 'Serbian';
2081
			$QuicktimeLanguageLookup[43]    = 'Macedonian';
2082
			$QuicktimeLanguageLookup[44]    = 'Bulgarian';
2083
			$QuicktimeLanguageLookup[45]    = 'Ukrainian';
2084
			$QuicktimeLanguageLookup[46]    = 'Byelorussian';
2085
			$QuicktimeLanguageLookup[47]    = 'Uzbek';
2086
			$QuicktimeLanguageLookup[48]    = 'Kazakh';
2087
			$QuicktimeLanguageLookup[49]    = 'Azerbaijani';
2088
			$QuicktimeLanguageLookup[50]    = 'AzerbaijanAr';
2089
			$QuicktimeLanguageLookup[51]    = 'Armenian';
2090
			$QuicktimeLanguageLookup[52]    = 'Georgian';
2091
			$QuicktimeLanguageLookup[53]    = 'Moldavian';
2092
			$QuicktimeLanguageLookup[54]    = 'Kirghiz';
2093
			$QuicktimeLanguageLookup[55]    = 'Tajiki';
2094
			$QuicktimeLanguageLookup[56]    = 'Turkmen';
2095
			$QuicktimeLanguageLookup[57]    = 'Mongolian';
2096
			$QuicktimeLanguageLookup[58]    = 'MongolianCyr';
2097
			$QuicktimeLanguageLookup[59]    = 'Pashto';
2098
			$QuicktimeLanguageLookup[60]    = 'Kurdish';
2099
			$QuicktimeLanguageLookup[61]    = 'Kashmiri';
2100
			$QuicktimeLanguageLookup[62]    = 'Sindhi';
2101
			$QuicktimeLanguageLookup[63]    = 'Tibetan';
2102
			$QuicktimeLanguageLookup[64]    = 'Nepali';
2103
			$QuicktimeLanguageLookup[65]    = 'Sanskrit';
2104
			$QuicktimeLanguageLookup[66]    = 'Marathi';
2105
			$QuicktimeLanguageLookup[67]    = 'Bengali';
2106
			$QuicktimeLanguageLookup[68]    = 'Assamese';
2107
			$QuicktimeLanguageLookup[69]    = 'Gujarati';
2108
			$QuicktimeLanguageLookup[70]    = 'Punjabi';
2109
			$QuicktimeLanguageLookup[71]    = 'Oriya';
2110
			$QuicktimeLanguageLookup[72]    = 'Malayalam';
2111
			$QuicktimeLanguageLookup[73]    = 'Kannada';
2112
			$QuicktimeLanguageLookup[74]    = 'Tamil';
2113
			$QuicktimeLanguageLookup[75]    = 'Telugu';
2114
			$QuicktimeLanguageLookup[76]    = 'Sinhalese';
2115
			$QuicktimeLanguageLookup[77]    = 'Burmese';
2116
			$QuicktimeLanguageLookup[78]    = 'Khmer';
2117
			$QuicktimeLanguageLookup[79]    = 'Lao';
2118
			$QuicktimeLanguageLookup[80]    = 'Vietnamese';
2119
			$QuicktimeLanguageLookup[81]    = 'Indonesian';
2120
			$QuicktimeLanguageLookup[82]    = 'Tagalog';
2121
			$QuicktimeLanguageLookup[83]    = 'MalayRoman';
2122
			$QuicktimeLanguageLookup[84]    = 'MalayArabic';
2123
			$QuicktimeLanguageLookup[85]    = 'Amharic';
2124
			$QuicktimeLanguageLookup[86]    = 'Tigrinya';
2125
			$QuicktimeLanguageLookup[87]    = 'Galla';
2126
			$QuicktimeLanguageLookup[87]    = 'Oromo';
2127
			$QuicktimeLanguageLookup[88]    = 'Somali';
2128
			$QuicktimeLanguageLookup[89]    = 'Swahili';
2129
			$QuicktimeLanguageLookup[90]    = 'Ruanda';
2130
			$QuicktimeLanguageLookup[91]    = 'Rundi';
2131
			$QuicktimeLanguageLookup[92]    = 'Chewa';
2132
			$QuicktimeLanguageLookup[93]    = 'Malagasy';
2133
			$QuicktimeLanguageLookup[94]    = 'Esperanto';
2134
			$QuicktimeLanguageLookup[128]   = 'Welsh';
2135
			$QuicktimeLanguageLookup[129]   = 'Basque';
2136
			$QuicktimeLanguageLookup[130]   = 'Catalan';
2137
			$QuicktimeLanguageLookup[131]   = 'Latin';
2138
			$QuicktimeLanguageLookup[132]   = 'Quechua';
2139
			$QuicktimeLanguageLookup[133]   = 'Guarani';
2140
			$QuicktimeLanguageLookup[134]   = 'Aymara';
2141
			$QuicktimeLanguageLookup[135]   = 'Tatar';
2142
			$QuicktimeLanguageLookup[136]   = 'Uighur';
2143
			$QuicktimeLanguageLookup[137]   = 'Dzongkha';
2144
			$QuicktimeLanguageLookup[138]   = 'JavaneseRom';
2145
			$QuicktimeLanguageLookup[32767] = 'Unspecified';
2146
		}
2147
		if (($languageid > 138) && ($languageid < 32767)) {
2148
			/*
2149
			ISO Language Codes - http://www.loc.gov/standards/iso639-2/php/code_list.php
2150
			Because the language codes specified by ISO 639-2/T are three characters long, they must be packed to fit into a 16-bit field.
2151
			The packing algorithm must map each of the three characters, which are always lowercase, into a 5-bit integer and then concatenate
2152
			these integers into the least significant 15 bits of a 16-bit integer, leaving the 16-bit integer's most significant bit set to zero.
2153
2154
			One algorithm for performing this packing is to treat each ISO character as a 16-bit integer. Subtract 0x60 from the first character
2155
			and multiply by 2^10 (0x400), subtract 0x60 from the second character and multiply by 2^5 (0x20), subtract 0x60 from the third character,
2156
			and add the three 16-bit values. This will result in a single 16-bit value with the three codes correctly packed into the 15 least
2157
			significant bits and the most significant bit set to zero.
2158
			*/
2159
			$iso_language_id  = '';
2160
			$iso_language_id .= chr((($languageid & 0x7C00) >> 10) + 0x60);
2161
			$iso_language_id .= chr((($languageid & 0x03E0) >>  5) + 0x60);
2162
			$iso_language_id .= chr((($languageid & 0x001F) >>  0) + 0x60);
2163
			$QuicktimeLanguageLookup[$languageid] = getid3_id3v2::LanguageLookup($iso_language_id);
2164
		}
2165
		return (isset($QuicktimeLanguageLookup[$languageid]) ? $QuicktimeLanguageLookup[$languageid] : 'invalid');
2166
	}
2167
2168
	/**
2169
	 * @param string $codecid
2170
	 *
2171
	 * @return string
2172
	 */
2173
	public function QuicktimeVideoCodecLookup($codecid) {
2174
		static $QuicktimeVideoCodecLookup = array();
2175
		if (empty($QuicktimeVideoCodecLookup)) {
2176
			$QuicktimeVideoCodecLookup['.SGI'] = 'SGI';
2177
			$QuicktimeVideoCodecLookup['3IV1'] = '3ivx MPEG-4 v1';
2178
			$QuicktimeVideoCodecLookup['3IV2'] = '3ivx MPEG-4 v2';
2179
			$QuicktimeVideoCodecLookup['3IVX'] = '3ivx MPEG-4';
2180
			$QuicktimeVideoCodecLookup['8BPS'] = 'Planar RGB';
2181
			$QuicktimeVideoCodecLookup['avc1'] = 'H.264/MPEG-4 AVC';
2182
			$QuicktimeVideoCodecLookup['avr '] = 'AVR-JPEG';
2183
			$QuicktimeVideoCodecLookup['b16g'] = '16Gray';
2184
			$QuicktimeVideoCodecLookup['b32a'] = '32AlphaGray';
2185
			$QuicktimeVideoCodecLookup['b48r'] = '48RGB';
2186
			$QuicktimeVideoCodecLookup['b64a'] = '64ARGB';
2187
			$QuicktimeVideoCodecLookup['base'] = 'Base';
2188
			$QuicktimeVideoCodecLookup['clou'] = 'Cloud';
2189
			$QuicktimeVideoCodecLookup['cmyk'] = 'CMYK';
2190
			$QuicktimeVideoCodecLookup['cvid'] = 'Cinepak';
2191
			$QuicktimeVideoCodecLookup['dmb1'] = 'OpenDML JPEG';
2192
			$QuicktimeVideoCodecLookup['dvc '] = 'DVC-NTSC';
2193
			$QuicktimeVideoCodecLookup['dvcp'] = 'DVC-PAL';
2194
			$QuicktimeVideoCodecLookup['dvpn'] = 'DVCPro-NTSC';
2195
			$QuicktimeVideoCodecLookup['dvpp'] = 'DVCPro-PAL';
2196
			$QuicktimeVideoCodecLookup['fire'] = 'Fire';
2197
			$QuicktimeVideoCodecLookup['flic'] = 'FLC';
2198
			$QuicktimeVideoCodecLookup['gif '] = 'GIF';
2199
			$QuicktimeVideoCodecLookup['h261'] = 'H261';
2200
			$QuicktimeVideoCodecLookup['h263'] = 'H263';
2201
			$QuicktimeVideoCodecLookup['IV41'] = 'Indeo4';
2202
			$QuicktimeVideoCodecLookup['jpeg'] = 'JPEG';
2203
			$QuicktimeVideoCodecLookup['kpcd'] = 'PhotoCD';
2204
			$QuicktimeVideoCodecLookup['mjpa'] = 'Motion JPEG-A';
2205
			$QuicktimeVideoCodecLookup['mjpb'] = 'Motion JPEG-B';
2206
			$QuicktimeVideoCodecLookup['msvc'] = 'Microsoft Video1';
2207
			$QuicktimeVideoCodecLookup['myuv'] = 'MPEG YUV420';
2208
			$QuicktimeVideoCodecLookup['path'] = 'Vector';
2209
			$QuicktimeVideoCodecLookup['png '] = 'PNG';
2210
			$QuicktimeVideoCodecLookup['PNTG'] = 'MacPaint';
2211
			$QuicktimeVideoCodecLookup['qdgx'] = 'QuickDrawGX';
2212
			$QuicktimeVideoCodecLookup['qdrw'] = 'QuickDraw';
2213
			$QuicktimeVideoCodecLookup['raw '] = 'RAW';
2214
			$QuicktimeVideoCodecLookup['ripl'] = 'WaterRipple';
2215
			$QuicktimeVideoCodecLookup['rpza'] = 'Video';
2216
			$QuicktimeVideoCodecLookup['smc '] = 'Graphics';
2217
			$QuicktimeVideoCodecLookup['SVQ1'] = 'Sorenson Video 1';
2218
			$QuicktimeVideoCodecLookup['SVQ1'] = 'Sorenson Video 3';
2219
			$QuicktimeVideoCodecLookup['syv9'] = 'Sorenson YUV9';
2220
			$QuicktimeVideoCodecLookup['tga '] = 'Targa';
2221
			$QuicktimeVideoCodecLookup['tiff'] = 'TIFF';
2222
			$QuicktimeVideoCodecLookup['WRAW'] = 'Windows RAW';
2223
			$QuicktimeVideoCodecLookup['WRLE'] = 'BMP';
2224
			$QuicktimeVideoCodecLookup['y420'] = 'YUV420';
2225
			$QuicktimeVideoCodecLookup['yuv2'] = 'ComponentVideo';
2226
			$QuicktimeVideoCodecLookup['yuvs'] = 'ComponentVideoUnsigned';
2227
			$QuicktimeVideoCodecLookup['yuvu'] = 'ComponentVideoSigned';
2228
		}
2229
		return (isset($QuicktimeVideoCodecLookup[$codecid]) ? $QuicktimeVideoCodecLookup[$codecid] : '');
2230
	}
2231
2232
	/**
2233
	 * @param string $codecid
2234
	 *
2235
	 * @return mixed|string
2236
	 */
2237
	public function QuicktimeAudioCodecLookup($codecid) {
2238
		static $QuicktimeAudioCodecLookup = array();
2239
		if (empty($QuicktimeAudioCodecLookup)) {
2240
			$QuicktimeAudioCodecLookup['.mp3']          = 'Fraunhofer MPEG Layer-III alias';
2241
			$QuicktimeAudioCodecLookup['aac ']          = 'ISO/IEC 14496-3 AAC';
2242
			$QuicktimeAudioCodecLookup['agsm']          = 'Apple GSM 10:1';
2243
			$QuicktimeAudioCodecLookup['alac']          = 'Apple Lossless Audio Codec';
2244
			$QuicktimeAudioCodecLookup['alaw']          = 'A-law 2:1';
2245
			$QuicktimeAudioCodecLookup['conv']          = 'Sample Format';
2246
			$QuicktimeAudioCodecLookup['dvca']          = 'DV';
2247
			$QuicktimeAudioCodecLookup['dvi ']          = 'DV 4:1';
2248
			$QuicktimeAudioCodecLookup['eqal']          = 'Frequency Equalizer';
2249
			$QuicktimeAudioCodecLookup['fl32']          = '32-bit Floating Point';
2250
			$QuicktimeAudioCodecLookup['fl64']          = '64-bit Floating Point';
2251
			$QuicktimeAudioCodecLookup['ima4']          = 'Interactive Multimedia Association 4:1';
2252
			$QuicktimeAudioCodecLookup['in24']          = '24-bit Integer';
2253
			$QuicktimeAudioCodecLookup['in32']          = '32-bit Integer';
2254
			$QuicktimeAudioCodecLookup['lpc ']          = 'LPC 23:1';
2255
			$QuicktimeAudioCodecLookup['MAC3']          = 'Macintosh Audio Compression/Expansion (MACE) 3:1';
2256
			$QuicktimeAudioCodecLookup['MAC6']          = 'Macintosh Audio Compression/Expansion (MACE) 6:1';
2257
			$QuicktimeAudioCodecLookup['mixb']          = '8-bit Mixer';
2258
			$QuicktimeAudioCodecLookup['mixw']          = '16-bit Mixer';
2259
			$QuicktimeAudioCodecLookup['mp4a']          = 'ISO/IEC 14496-3 AAC';
2260
			$QuicktimeAudioCodecLookup['MS'."\x00\x02"] = 'Microsoft ADPCM';
2261
			$QuicktimeAudioCodecLookup['MS'."\x00\x11"] = 'DV IMA';
2262
			$QuicktimeAudioCodecLookup['MS'."\x00\x55"] = 'Fraunhofer MPEG Layer III';
2263
			$QuicktimeAudioCodecLookup['NONE']          = 'No Encoding';
2264
			$QuicktimeAudioCodecLookup['Qclp']          = 'Qualcomm PureVoice';
2265
			$QuicktimeAudioCodecLookup['QDM2']          = 'QDesign Music 2';
2266
			$QuicktimeAudioCodecLookup['QDMC']          = 'QDesign Music 1';
2267
			$QuicktimeAudioCodecLookup['ratb']          = '8-bit Rate';
2268
			$QuicktimeAudioCodecLookup['ratw']          = '16-bit Rate';
2269
			$QuicktimeAudioCodecLookup['raw ']          = 'raw PCM';
2270
			$QuicktimeAudioCodecLookup['sour']          = 'Sound Source';
2271
			$QuicktimeAudioCodecLookup['sowt']          = 'signed/two\'s complement (Little Endian)';
2272
			$QuicktimeAudioCodecLookup['str1']          = 'Iomega MPEG layer II';
2273
			$QuicktimeAudioCodecLookup['str2']          = 'Iomega MPEG *layer II';
2274
			$QuicktimeAudioCodecLookup['str3']          = 'Iomega MPEG **layer II';
2275
			$QuicktimeAudioCodecLookup['str4']          = 'Iomega MPEG ***layer II';
2276
			$QuicktimeAudioCodecLookup['twos']          = 'signed/two\'s complement (Big Endian)';
2277
			$QuicktimeAudioCodecLookup['ulaw']          = 'mu-law 2:1';
2278
		}
2279
		return (isset($QuicktimeAudioCodecLookup[$codecid]) ? $QuicktimeAudioCodecLookup[$codecid] : '');
2280
	}
2281
2282
	/**
2283
	 * @param string $compressionid
2284
	 *
2285
	 * @return string
2286
	 */
2287
	public function QuicktimeDCOMLookup($compressionid) {
2288
		static $QuicktimeDCOMLookup = array();
2289
		if (empty($QuicktimeDCOMLookup)) {
2290
			$QuicktimeDCOMLookup['zlib'] = 'ZLib Deflate';
2291
			$QuicktimeDCOMLookup['adec'] = 'Apple Compression';
2292
		}
2293
		return (isset($QuicktimeDCOMLookup[$compressionid]) ? $QuicktimeDCOMLookup[$compressionid] : '');
2294
	}
2295
2296
	/**
2297
	 * @param int $colordepthid
2298
	 *
2299
	 * @return string
2300
	 */
2301
	public function QuicktimeColorNameLookup($colordepthid) {
2302
		static $QuicktimeColorNameLookup = array();
2303
		if (empty($QuicktimeColorNameLookup)) {
2304
			$QuicktimeColorNameLookup[1]  = '2-color (monochrome)';
2305
			$QuicktimeColorNameLookup[2]  = '4-color';
2306
			$QuicktimeColorNameLookup[4]  = '16-color';
2307
			$QuicktimeColorNameLookup[8]  = '256-color';
2308
			$QuicktimeColorNameLookup[16] = 'thousands (16-bit color)';
2309
			$QuicktimeColorNameLookup[24] = 'millions (24-bit color)';
2310
			$QuicktimeColorNameLookup[32] = 'millions+ (32-bit color)';
2311
			$QuicktimeColorNameLookup[33] = 'black & white';
2312
			$QuicktimeColorNameLookup[34] = '4-gray';
2313
			$QuicktimeColorNameLookup[36] = '16-gray';
2314
			$QuicktimeColorNameLookup[40] = '256-gray';
2315
		}
2316
		return (isset($QuicktimeColorNameLookup[$colordepthid]) ? $QuicktimeColorNameLookup[$colordepthid] : 'invalid');
2317
	}
2318
2319
	/**
2320
	 * @param int $stik
2321
	 *
2322
	 * @return string
2323
	 */
2324
	public function QuicktimeSTIKLookup($stik) {
2325
		static $QuicktimeSTIKLookup = array();
2326
		if (empty($QuicktimeSTIKLookup)) {
2327
			$QuicktimeSTIKLookup[0]  = 'Movie';
2328
			$QuicktimeSTIKLookup[1]  = 'Normal';
2329
			$QuicktimeSTIKLookup[2]  = 'Audiobook';
2330
			$QuicktimeSTIKLookup[5]  = 'Whacked Bookmark';
2331
			$QuicktimeSTIKLookup[6]  = 'Music Video';
2332
			$QuicktimeSTIKLookup[9]  = 'Short Film';
2333
			$QuicktimeSTIKLookup[10] = 'TV Show';
2334
			$QuicktimeSTIKLookup[11] = 'Booklet';
2335
			$QuicktimeSTIKLookup[14] = 'Ringtone';
2336
			$QuicktimeSTIKLookup[21] = 'Podcast';
2337
		}
2338
		return (isset($QuicktimeSTIKLookup[$stik]) ? $QuicktimeSTIKLookup[$stik] : 'invalid');
2339
	}
2340
2341
	/**
2342
	 * @param int $audio_profile_id
2343
	 *
2344
	 * @return string
2345
	 */
2346
	public function QuicktimeIODSaudioProfileName($audio_profile_id) {
2347
		static $QuicktimeIODSaudioProfileNameLookup = array();
2348
		if (empty($QuicktimeIODSaudioProfileNameLookup)) {
2349
			$QuicktimeIODSaudioProfileNameLookup = array(
2350
				0x00 => 'ISO Reserved (0x00)',
2351
				0x01 => 'Main Audio Profile @ Level 1',
2352
				0x02 => 'Main Audio Profile @ Level 2',
2353
				0x03 => 'Main Audio Profile @ Level 3',
2354
				0x04 => 'Main Audio Profile @ Level 4',
2355
				0x05 => 'Scalable Audio Profile @ Level 1',
2356
				0x06 => 'Scalable Audio Profile @ Level 2',
2357
				0x07 => 'Scalable Audio Profile @ Level 3',
2358
				0x08 => 'Scalable Audio Profile @ Level 4',
2359
				0x09 => 'Speech Audio Profile @ Level 1',
2360
				0x0A => 'Speech Audio Profile @ Level 2',
2361
				0x0B => 'Synthetic Audio Profile @ Level 1',
2362
				0x0C => 'Synthetic Audio Profile @ Level 2',
2363
				0x0D => 'Synthetic Audio Profile @ Level 3',
2364
				0x0E => 'High Quality Audio Profile @ Level 1',
2365
				0x0F => 'High Quality Audio Profile @ Level 2',
2366
				0x10 => 'High Quality Audio Profile @ Level 3',
2367
				0x11 => 'High Quality Audio Profile @ Level 4',
2368
				0x12 => 'High Quality Audio Profile @ Level 5',
2369
				0x13 => 'High Quality Audio Profile @ Level 6',
2370
				0x14 => 'High Quality Audio Profile @ Level 7',
2371
				0x15 => 'High Quality Audio Profile @ Level 8',
2372
				0x16 => 'Low Delay Audio Profile @ Level 1',
2373
				0x17 => 'Low Delay Audio Profile @ Level 2',
2374
				0x18 => 'Low Delay Audio Profile @ Level 3',
2375
				0x19 => 'Low Delay Audio Profile @ Level 4',
2376
				0x1A => 'Low Delay Audio Profile @ Level 5',
2377
				0x1B => 'Low Delay Audio Profile @ Level 6',
2378
				0x1C => 'Low Delay Audio Profile @ Level 7',
2379
				0x1D => 'Low Delay Audio Profile @ Level 8',
2380
				0x1E => 'Natural Audio Profile @ Level 1',
2381
				0x1F => 'Natural Audio Profile @ Level 2',
2382
				0x20 => 'Natural Audio Profile @ Level 3',
2383
				0x21 => 'Natural Audio Profile @ Level 4',
2384
				0x22 => 'Mobile Audio Internetworking Profile @ Level 1',
2385
				0x23 => 'Mobile Audio Internetworking Profile @ Level 2',
2386
				0x24 => 'Mobile Audio Internetworking Profile @ Level 3',
2387
				0x25 => 'Mobile Audio Internetworking Profile @ Level 4',
2388
				0x26 => 'Mobile Audio Internetworking Profile @ Level 5',
2389
				0x27 => 'Mobile Audio Internetworking Profile @ Level 6',
2390
				0x28 => 'AAC Profile @ Level 1',
2391
				0x29 => 'AAC Profile @ Level 2',
2392
				0x2A => 'AAC Profile @ Level 4',
2393
				0x2B => 'AAC Profile @ Level 5',
2394
				0x2C => 'High Efficiency AAC Profile @ Level 2',
2395
				0x2D => 'High Efficiency AAC Profile @ Level 3',
2396
				0x2E => 'High Efficiency AAC Profile @ Level 4',
2397
				0x2F => 'High Efficiency AAC Profile @ Level 5',
2398
				0xFE => 'Not part of MPEG-4 audio profiles',
2399
				0xFF => 'No audio capability required',
2400
			);
2401
		}
2402
		return (isset($QuicktimeIODSaudioProfileNameLookup[$audio_profile_id]) ? $QuicktimeIODSaudioProfileNameLookup[$audio_profile_id] : 'ISO Reserved / User Private');
2403
	}
2404
2405
	/**
2406
	 * @param int $video_profile_id
2407
	 *
2408
	 * @return string
2409
	 */
2410
	public function QuicktimeIODSvideoProfileName($video_profile_id) {
2411
		static $QuicktimeIODSvideoProfileNameLookup = array();
2412
		if (empty($QuicktimeIODSvideoProfileNameLookup)) {
2413
			$QuicktimeIODSvideoProfileNameLookup = array(
2414
				0x00 => 'Reserved (0x00) Profile',
2415
				0x01 => 'Simple Profile @ Level 1',
2416
				0x02 => 'Simple Profile @ Level 2',
2417
				0x03 => 'Simple Profile @ Level 3',
2418
				0x08 => 'Simple Profile @ Level 0',
2419
				0x10 => 'Simple Scalable Profile @ Level 0',
2420
				0x11 => 'Simple Scalable Profile @ Level 1',
2421
				0x12 => 'Simple Scalable Profile @ Level 2',
2422
				0x15 => 'AVC/H264 Profile',
2423
				0x21 => 'Core Profile @ Level 1',
2424
				0x22 => 'Core Profile @ Level 2',
2425
				0x32 => 'Main Profile @ Level 2',
2426
				0x33 => 'Main Profile @ Level 3',
2427
				0x34 => 'Main Profile @ Level 4',
2428
				0x42 => 'N-bit Profile @ Level 2',
2429
				0x51 => 'Scalable Texture Profile @ Level 1',
2430
				0x61 => 'Simple Face Animation Profile @ Level 1',
2431
				0x62 => 'Simple Face Animation Profile @ Level 2',
2432
				0x63 => 'Simple FBA Profile @ Level 1',
2433
				0x64 => 'Simple FBA Profile @ Level 2',
2434
				0x71 => 'Basic Animated Texture Profile @ Level 1',
2435
				0x72 => 'Basic Animated Texture Profile @ Level 2',
2436
				0x81 => 'Hybrid Profile @ Level 1',
2437
				0x82 => 'Hybrid Profile @ Level 2',
2438
				0x91 => 'Advanced Real Time Simple Profile @ Level 1',
2439
				0x92 => 'Advanced Real Time Simple Profile @ Level 2',
2440
				0x93 => 'Advanced Real Time Simple Profile @ Level 3',
2441
				0x94 => 'Advanced Real Time Simple Profile @ Level 4',
2442
				0xA1 => 'Core Scalable Profile @ Level1',
2443
				0xA2 => 'Core Scalable Profile @ Level2',
2444
				0xA3 => 'Core Scalable Profile @ Level3',
2445
				0xB1 => 'Advanced Coding Efficiency Profile @ Level 1',
2446
				0xB2 => 'Advanced Coding Efficiency Profile @ Level 2',
2447
				0xB3 => 'Advanced Coding Efficiency Profile @ Level 3',
2448
				0xB4 => 'Advanced Coding Efficiency Profile @ Level 4',
2449
				0xC1 => 'Advanced Core Profile @ Level 1',
2450
				0xC2 => 'Advanced Core Profile @ Level 2',
2451
				0xD1 => 'Advanced Scalable Texture @ Level1',
2452
				0xD2 => 'Advanced Scalable Texture @ Level2',
2453
				0xE1 => 'Simple Studio Profile @ Level 1',
2454
				0xE2 => 'Simple Studio Profile @ Level 2',
2455
				0xE3 => 'Simple Studio Profile @ Level 3',
2456
				0xE4 => 'Simple Studio Profile @ Level 4',
2457
				0xE5 => 'Core Studio Profile @ Level 1',
2458
				0xE6 => 'Core Studio Profile @ Level 2',
2459
				0xE7 => 'Core Studio Profile @ Level 3',
2460
				0xE8 => 'Core Studio Profile @ Level 4',
2461
				0xF0 => 'Advanced Simple Profile @ Level 0',
2462
				0xF1 => 'Advanced Simple Profile @ Level 1',
2463
				0xF2 => 'Advanced Simple Profile @ Level 2',
2464
				0xF3 => 'Advanced Simple Profile @ Level 3',
2465
				0xF4 => 'Advanced Simple Profile @ Level 4',
2466
				0xF5 => 'Advanced Simple Profile @ Level 5',
2467
				0xF7 => 'Advanced Simple Profile @ Level 3b',
2468
				0xF8 => 'Fine Granularity Scalable Profile @ Level 0',
2469
				0xF9 => 'Fine Granularity Scalable Profile @ Level 1',
2470
				0xFA => 'Fine Granularity Scalable Profile @ Level 2',
2471
				0xFB => 'Fine Granularity Scalable Profile @ Level 3',
2472
				0xFC => 'Fine Granularity Scalable Profile @ Level 4',
2473
				0xFD => 'Fine Granularity Scalable Profile @ Level 5',
2474
				0xFE => 'Not part of MPEG-4 Visual profiles',
2475
				0xFF => 'No visual capability required',
2476
			);
2477
		}
2478
		return (isset($QuicktimeIODSvideoProfileNameLookup[$video_profile_id]) ? $QuicktimeIODSvideoProfileNameLookup[$video_profile_id] : 'ISO Reserved Profile');
2479
	}
2480
2481
	/**
2482
	 * @param int $rtng
2483
	 *
2484
	 * @return string
2485
	 */
2486 View Code Duplication
	public function QuicktimeContentRatingLookup($rtng) {
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...
2487
		static $QuicktimeContentRatingLookup = array();
2488
		if (empty($QuicktimeContentRatingLookup)) {
2489
			$QuicktimeContentRatingLookup[0]  = 'None';
2490
			$QuicktimeContentRatingLookup[2]  = 'Clean';
2491
			$QuicktimeContentRatingLookup[4]  = 'Explicit';
2492
		}
2493
		return (isset($QuicktimeContentRatingLookup[$rtng]) ? $QuicktimeContentRatingLookup[$rtng] : 'invalid');
2494
	}
2495
2496
	/**
2497
	 * @param int $akid
2498
	 *
2499
	 * @return string
2500
	 */
2501
	public function QuicktimeStoreAccountTypeLookup($akid) {
2502
		static $QuicktimeStoreAccountTypeLookup = array();
2503
		if (empty($QuicktimeStoreAccountTypeLookup)) {
2504
			$QuicktimeStoreAccountTypeLookup[0] = 'iTunes';
2505
			$QuicktimeStoreAccountTypeLookup[1] = 'AOL';
2506
		}
2507
		return (isset($QuicktimeStoreAccountTypeLookup[$akid]) ? $QuicktimeStoreAccountTypeLookup[$akid] : 'invalid');
2508
	}
2509
2510
	/**
2511
	 * @param int $sfid
2512
	 *
2513
	 * @return string
2514
	 */
2515
	public function QuicktimeStoreFrontCodeLookup($sfid) {
2516
		static $QuicktimeStoreFrontCodeLookup = array();
2517
		if (empty($QuicktimeStoreFrontCodeLookup)) {
2518
			$QuicktimeStoreFrontCodeLookup[143460] = 'Australia';
2519
			$QuicktimeStoreFrontCodeLookup[143445] = 'Austria';
2520
			$QuicktimeStoreFrontCodeLookup[143446] = 'Belgium';
2521
			$QuicktimeStoreFrontCodeLookup[143455] = 'Canada';
2522
			$QuicktimeStoreFrontCodeLookup[143458] = 'Denmark';
2523
			$QuicktimeStoreFrontCodeLookup[143447] = 'Finland';
2524
			$QuicktimeStoreFrontCodeLookup[143442] = 'France';
2525
			$QuicktimeStoreFrontCodeLookup[143443] = 'Germany';
2526
			$QuicktimeStoreFrontCodeLookup[143448] = 'Greece';
2527
			$QuicktimeStoreFrontCodeLookup[143449] = 'Ireland';
2528
			$QuicktimeStoreFrontCodeLookup[143450] = 'Italy';
2529
			$QuicktimeStoreFrontCodeLookup[143462] = 'Japan';
2530
			$QuicktimeStoreFrontCodeLookup[143451] = 'Luxembourg';
2531
			$QuicktimeStoreFrontCodeLookup[143452] = 'Netherlands';
2532
			$QuicktimeStoreFrontCodeLookup[143461] = 'New Zealand';
2533
			$QuicktimeStoreFrontCodeLookup[143457] = 'Norway';
2534
			$QuicktimeStoreFrontCodeLookup[143453] = 'Portugal';
2535
			$QuicktimeStoreFrontCodeLookup[143454] = 'Spain';
2536
			$QuicktimeStoreFrontCodeLookup[143456] = 'Sweden';
2537
			$QuicktimeStoreFrontCodeLookup[143459] = 'Switzerland';
2538
			$QuicktimeStoreFrontCodeLookup[143444] = 'United Kingdom';
2539
			$QuicktimeStoreFrontCodeLookup[143441] = 'United States';
2540
		}
2541
		return (isset($QuicktimeStoreFrontCodeLookup[$sfid]) ? $QuicktimeStoreFrontCodeLookup[$sfid] : 'invalid');
2542
	}
2543
2544
	/**
2545
	 * @param string $atom_data
2546
	 *
2547
	 * @return array
2548
	 */
2549
	public function QuicktimeParseNikonNCTG($atom_data) {
2550
		// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
2551
		// Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
2552
		// Data is stored as records of:
2553
		// * 4 bytes record type
2554
		// * 2 bytes size of data field type:
2555
		//     0x0001 = flag   (size field *= 1-byte)
2556
		//     0x0002 = char   (size field *= 1-byte)
2557
		//     0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB
2558
		//     0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD
2559
		//     0x0005 = float  (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together
2560
		//     0x0007 = bytes  (size field *= 1-byte), values are stored as ??????
2561
		//     0x0008 = ?????  (size field *= 2-byte), values are stored as ??????
2562
		// * 2 bytes data size field
2563
		// * ? bytes data (string data may be null-padded; datestamp fields are in the format "2011:05:25 20:24:15")
2564
		// all integers are stored BigEndian
2565
2566
		$NCTGtagName = array(
2567
			0x00000001 => 'Make',
2568
			0x00000002 => 'Model',
2569
			0x00000003 => 'Software',
2570
			0x00000011 => 'CreateDate',
2571
			0x00000012 => 'DateTimeOriginal',
2572
			0x00000013 => 'FrameCount',
2573
			0x00000016 => 'FrameRate',
2574
			0x00000022 => 'FrameWidth',
2575
			0x00000023 => 'FrameHeight',
2576
			0x00000032 => 'AudioChannels',
2577
			0x00000033 => 'AudioBitsPerSample',
2578
			0x00000034 => 'AudioSampleRate',
2579
			0x02000001 => 'MakerNoteVersion',
2580
			0x02000005 => 'WhiteBalance',
2581
			0x0200000b => 'WhiteBalanceFineTune',
2582
			0x0200001e => 'ColorSpace',
2583
			0x02000023 => 'PictureControlData',
2584
			0x02000024 => 'WorldTime',
2585
			0x02000032 => 'UnknownInfo',
2586
			0x02000083 => 'LensType',
2587
			0x02000084 => 'Lens',
2588
		);
2589
2590
		$offset = 0;
2591
		$data = null;
0 ignored issues
show
Unused Code introduced by
$data is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2592
		$datalength = strlen($atom_data);
2593
		$parsed = array();
2594
		while ($offset < $datalength) {
2595
			$record_type       = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4));  $offset += 4;
2596
			$data_size_type    = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2));  $offset += 2;
2597
			$data_size         = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2));  $offset += 2;
2598
			switch ($data_size_type) {
2599
				case 0x0001: // 0x0001 = flag   (size field *= 1-byte)
2600
					$data = getid3_lib::BigEndian2Int(substr($atom_data, $offset, $data_size * 1));
2601
					$offset += ($data_size * 1);
2602
					break;
2603 View Code Duplication
				case 0x0002: // 0x0002 = char   (size field *= 1-byte)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
2604
					$data = substr($atom_data, $offset, $data_size * 1);
2605
					$offset += ($data_size * 1);
2606
					$data = rtrim($data, "\x00");
2607
					break;
2608 View Code Duplication
				case 0x0003: // 0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
2609
					$data = '';
2610
					for ($i = $data_size - 1; $i >= 0; $i--) {
2611
						$data .= substr($atom_data, $offset + ($i * 2), 2);
2612
					}
2613
					$data = getid3_lib::BigEndian2Int($data);
2614
					$offset += ($data_size * 2);
2615
					break;
2616 View Code Duplication
				case 0x0004: // 0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
2617
					$data = '';
2618
					for ($i = $data_size - 1; $i >= 0; $i--) {
2619
						$data .= substr($atom_data, $offset + ($i * 4), 4);
2620
					}
2621
					$data = getid3_lib::BigEndian2Int($data);
2622
					$offset += ($data_size * 4);
2623
					break;
2624
				case 0x0005: // 0x0005 = float  (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together
2625
					$data = array();
2626
					for ($i = 0; $i < $data_size; $i++) {
2627
						$numerator    = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 0, 4));
2628
						$denomninator = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 4, 4));
2629
						if ($denomninator == 0) {
2630
							$data[$i] = false;
2631
						} else {
2632
							$data[$i] = (double) $numerator / $denomninator;
2633
						}
2634
					}
2635
					$offset += (8 * $data_size);
2636
					if (count($data) == 1) {
2637
						$data = $data[0];
2638
					}
2639
					break;
2640 View Code Duplication
				case 0x0007: // 0x0007 = bytes  (size field *= 1-byte), values are stored as ??????
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
2641
					$data = substr($atom_data, $offset, $data_size * 1);
2642
					$offset += ($data_size * 1);
2643
					break;
2644 View Code Duplication
				case 0x0008: // 0x0008 = ?????  (size field *= 2-byte), values are stored as ??????
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
2645
					$data = substr($atom_data, $offset, $data_size * 2);
2646
					$offset += ($data_size * 2);
2647
					break;
2648
				default:
2649
					echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br>';
2650
					break 2;
2651
			}
2652
2653
			switch ($record_type) {
2654
				case 0x00000011: // CreateDate
2655
				case 0x00000012: // DateTimeOriginal
2656
					$data = strtotime($data);
2657
					break;
2658
				case 0x0200001e: // ColorSpace
2659
					switch ($data) {
2660
						case 1:
2661
							$data = 'sRGB';
2662
							break;
2663
						case 2:
2664
							$data = 'Adobe RGB';
2665
							break;
2666
					}
2667
					break;
2668
				case 0x02000023: // PictureControlData
2669
					$PictureControlAdjust = array(0=>'default', 1=>'quick', 2=>'full');
2670
					$FilterEffect = array(0x80=>'off', 0x81=>'yellow', 0x82=>'orange',    0x83=>'red', 0x84=>'green',  0xff=>'n/a');
2671
					$ToningEffect = array(0x80=>'b&w', 0x81=>'sepia',  0x82=>'cyanotype', 0x83=>'red', 0x84=>'yellow', 0x85=>'green', 0x86=>'blue-green', 0x87=>'blue', 0x88=>'purple-blue', 0x89=>'red-purple', 0xff=>'n/a');
2672
					$data = array(
2673
						'PictureControlVersion'     =>                           substr($data,  0,  4),
2674
						'PictureControlName'        =>                     rtrim(substr($data,  4, 20), "\x00"),
2675
						'PictureControlBase'        =>                     rtrim(substr($data, 24, 20), "\x00"),
2676
						//'?'                       =>                           substr($data, 44,  4),
2677
						'PictureControlAdjust'      => $PictureControlAdjust[ord(substr($data, 48,  1))],
2678
						'PictureControlQuickAdjust' =>                       ord(substr($data, 49,  1)),
2679
						'Sharpness'                 =>                       ord(substr($data, 50,  1)),
2680
						'Contrast'                  =>                       ord(substr($data, 51,  1)),
2681
						'Brightness'                =>                       ord(substr($data, 52,  1)),
2682
						'Saturation'                =>                       ord(substr($data, 53,  1)),
2683
						'HueAdjustment'             =>                       ord(substr($data, 54,  1)),
2684
						'FilterEffect'              =>         $FilterEffect[ord(substr($data, 55,  1))],
2685
						'ToningEffect'              =>         $ToningEffect[ord(substr($data, 56,  1))],
2686
						'ToningSaturation'          =>                       ord(substr($data, 57,  1)),
2687
					);
2688
					break;
2689
				case 0x02000024: // WorldTime
2690
					// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#WorldTime
2691
					// timezone is stored as offset from GMT in minutes
2692
					$timezone = getid3_lib::BigEndian2Int(substr($data, 0, 2));
2693
					if ($timezone & 0x8000) {
2694
						$timezone = 0 - (0x10000 - $timezone);
2695
					}
2696
					$timezone /= 60;
2697
2698
					$dst = (bool) getid3_lib::BigEndian2Int(substr($data, 2, 1));
2699
					switch (getid3_lib::BigEndian2Int(substr($data, 3, 1))) {
2700
						case 2:
2701
							$datedisplayformat = 'D/M/Y'; break;
2702
						case 1:
2703
							$datedisplayformat = 'M/D/Y'; break;
2704
						case 0:
2705
						default:
2706
							$datedisplayformat = 'Y/M/D'; break;
2707
					}
2708
2709
					$data = array('timezone'=>floatval($timezone), 'dst'=>$dst, 'display'=>$datedisplayformat);
2710
					break;
2711
				case 0x02000083: // LensType
2712
					$data = array(
2713
						//'_'  => $data,
2714
						'mf' => (bool) ($data & 0x01),
2715
						'd'  => (bool) ($data & 0x02),
2716
						'g'  => (bool) ($data & 0x04),
2717
						'vr' => (bool) ($data & 0x08),
2718
					);
2719
					break;
2720
			}
2721
			$tag_name = (isset($NCTGtagName[$record_type]) ? $NCTGtagName[$record_type] : '0x'.str_pad(dechex($record_type), 8, '0', STR_PAD_LEFT));
2722
			$parsed[$tag_name] = $data;
2723
		}
2724
		return $parsed;
2725
	}
2726
2727
	/**
2728
	 * @param string $keyname
2729
	 * @param string|array $data
2730
	 * @param string $boxname
2731
	 *
2732
	 * @return bool
2733
	 */
2734
	public function CopyToAppropriateCommentsSection($keyname, $data, $boxname='') {
2735
		static $handyatomtranslatorarray = array();
2736
		if (empty($handyatomtranslatorarray)) {
2737
			// http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt
2738
			// http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt
2739
			// http://atomicparsley.sourceforge.net/mpeg-4files.html
2740
			// https://code.google.com/p/mp4v2/wiki/iTunesMetadata
2741
			$handyatomtranslatorarray["\xA9".'alb'] = 'album';               // iTunes 4.0
2742
			$handyatomtranslatorarray["\xA9".'ART'] = 'artist';
2743
			$handyatomtranslatorarray["\xA9".'art'] = 'artist';              // iTunes 4.0
2744
			$handyatomtranslatorarray["\xA9".'aut'] = 'author';
2745
			$handyatomtranslatorarray["\xA9".'cmt'] = 'comment';             // iTunes 4.0
2746
			$handyatomtranslatorarray["\xA9".'com'] = 'comment';
2747
			$handyatomtranslatorarray["\xA9".'cpy'] = 'copyright';
2748
			$handyatomtranslatorarray["\xA9".'day'] = 'creation_date';       // iTunes 4.0
2749
			$handyatomtranslatorarray["\xA9".'dir'] = 'director';
2750
			$handyatomtranslatorarray["\xA9".'ed1'] = 'edit1';
2751
			$handyatomtranslatorarray["\xA9".'ed2'] = 'edit2';
2752
			$handyatomtranslatorarray["\xA9".'ed3'] = 'edit3';
2753
			$handyatomtranslatorarray["\xA9".'ed4'] = 'edit4';
2754
			$handyatomtranslatorarray["\xA9".'ed5'] = 'edit5';
2755
			$handyatomtranslatorarray["\xA9".'ed6'] = 'edit6';
2756
			$handyatomtranslatorarray["\xA9".'ed7'] = 'edit7';
2757
			$handyatomtranslatorarray["\xA9".'ed8'] = 'edit8';
2758
			$handyatomtranslatorarray["\xA9".'ed9'] = 'edit9';
2759
			$handyatomtranslatorarray["\xA9".'enc'] = 'encoded_by';
2760
			$handyatomtranslatorarray["\xA9".'fmt'] = 'format';
2761
			$handyatomtranslatorarray["\xA9".'gen'] = 'genre';               // iTunes 4.0
2762
			$handyatomtranslatorarray["\xA9".'grp'] = 'grouping';            // iTunes 4.2
2763
			$handyatomtranslatorarray["\xA9".'hst'] = 'host_computer';
2764
			$handyatomtranslatorarray["\xA9".'inf'] = 'information';
2765
			$handyatomtranslatorarray["\xA9".'lyr'] = 'lyrics';              // iTunes 5.0
2766
			$handyatomtranslatorarray["\xA9".'mak'] = 'make';
2767
			$handyatomtranslatorarray["\xA9".'mod'] = 'model';
2768
			$handyatomtranslatorarray["\xA9".'nam'] = 'title';               // iTunes 4.0
2769
			$handyatomtranslatorarray["\xA9".'ope'] = 'composer';
2770
			$handyatomtranslatorarray["\xA9".'prd'] = 'producer';
2771
			$handyatomtranslatorarray["\xA9".'PRD'] = 'product';
2772
			$handyatomtranslatorarray["\xA9".'prf'] = 'performers';
2773
			$handyatomtranslatorarray["\xA9".'req'] = 'system_requirements';
2774
			$handyatomtranslatorarray["\xA9".'src'] = 'source_credit';
2775
			$handyatomtranslatorarray["\xA9".'swr'] = 'software';
2776
			$handyatomtranslatorarray["\xA9".'too'] = 'encoding_tool';       // iTunes 4.0
2777
			$handyatomtranslatorarray["\xA9".'trk'] = 'track_number';
2778
			$handyatomtranslatorarray["\xA9".'url'] = 'url';
2779
			$handyatomtranslatorarray["\xA9".'wrn'] = 'warning';
2780
			$handyatomtranslatorarray["\xA9".'wrt'] = 'composer';
2781
			$handyatomtranslatorarray['aART'] = 'album_artist';
2782
			$handyatomtranslatorarray['apID'] = 'purchase_account';
2783
			$handyatomtranslatorarray['catg'] = 'category';            // iTunes 4.9
2784
			$handyatomtranslatorarray['covr'] = 'picture';             // iTunes 4.0
2785
			$handyatomtranslatorarray['cpil'] = 'compilation';         // iTunes 4.0
2786
			$handyatomtranslatorarray['cprt'] = 'copyright';           // iTunes 4.0?
2787
			$handyatomtranslatorarray['desc'] = 'description';         // iTunes 5.0
2788
			$handyatomtranslatorarray['disk'] = 'disc_number';         // iTunes 4.0
2789
			$handyatomtranslatorarray['egid'] = 'episode_guid';        // iTunes 4.9
2790
			$handyatomtranslatorarray['gnre'] = 'genre';               // iTunes 4.0
2791
			$handyatomtranslatorarray['hdvd'] = 'hd_video';            // iTunes 4.0
2792
			$handyatomtranslatorarray['ldes'] = 'description_long';    //
2793
			$handyatomtranslatorarray['keyw'] = 'keyword';             // iTunes 4.9
2794
			$handyatomtranslatorarray['pcst'] = 'podcast';             // iTunes 4.9
2795
			$handyatomtranslatorarray['pgap'] = 'gapless_playback';    // iTunes 7.0
2796
			$handyatomtranslatorarray['purd'] = 'purchase_date';       // iTunes 6.0.2
2797
			$handyatomtranslatorarray['purl'] = 'podcast_url';         // iTunes 4.9
2798
			$handyatomtranslatorarray['rtng'] = 'rating';              // iTunes 4.0
2799
			$handyatomtranslatorarray['soaa'] = 'sort_album_artist';   //
2800
			$handyatomtranslatorarray['soal'] = 'sort_album';          //
2801
			$handyatomtranslatorarray['soar'] = 'sort_artist';         //
2802
			$handyatomtranslatorarray['soco'] = 'sort_composer';       //
2803
			$handyatomtranslatorarray['sonm'] = 'sort_title';          //
2804
			$handyatomtranslatorarray['sosn'] = 'sort_show';           //
2805
			$handyatomtranslatorarray['stik'] = 'stik';                // iTunes 4.9
2806
			$handyatomtranslatorarray['tmpo'] = 'bpm';                 // iTunes 4.0
2807
			$handyatomtranslatorarray['trkn'] = 'track_number';        // iTunes 4.0
2808
			$handyatomtranslatorarray['tven'] = 'tv_episode_id';       //
2809
			$handyatomtranslatorarray['tves'] = 'tv_episode';          // iTunes 6.0
2810
			$handyatomtranslatorarray['tvnn'] = 'tv_network_name';     // iTunes 6.0
2811
			$handyatomtranslatorarray['tvsh'] = 'tv_show_name';        // iTunes 6.0
2812
			$handyatomtranslatorarray['tvsn'] = 'tv_season';           // iTunes 6.0
2813
2814
			// boxnames:
2815
			/*
2816
			$handyatomtranslatorarray['iTunSMPB']                    = 'iTunSMPB';
2817
			$handyatomtranslatorarray['iTunNORM']                    = 'iTunNORM';
2818
			$handyatomtranslatorarray['Encoding Params']             = 'Encoding Params';
2819
			$handyatomtranslatorarray['replaygain_track_gain']       = 'replaygain_track_gain';
2820
			$handyatomtranslatorarray['replaygain_track_peak']       = 'replaygain_track_peak';
2821
			$handyatomtranslatorarray['replaygain_track_minmax']     = 'replaygain_track_minmax';
2822
			$handyatomtranslatorarray['MusicIP PUID']                = 'MusicIP PUID';
2823
			$handyatomtranslatorarray['MusicBrainz Artist Id']       = 'MusicBrainz Artist Id';
2824
			$handyatomtranslatorarray['MusicBrainz Album Id']        = 'MusicBrainz Album Id';
2825
			$handyatomtranslatorarray['MusicBrainz Album Artist Id'] = 'MusicBrainz Album Artist Id';
2826
			$handyatomtranslatorarray['MusicBrainz Track Id']        = 'MusicBrainz Track Id';
2827
			$handyatomtranslatorarray['MusicBrainz Disc Id']         = 'MusicBrainz Disc Id';
2828
2829
			// http://age.hobba.nl/audio/tag_frame_reference.html
2830
			$handyatomtranslatorarray['PLAY_COUNTER']                = 'play_counter'; // Foobar2000 - https://www.getid3.org/phpBB3/viewtopic.php?t=1355
2831
			$handyatomtranslatorarray['MEDIATYPE']                   = 'mediatype';    // Foobar2000 - https://www.getid3.org/phpBB3/viewtopic.php?t=1355
2832
			*/
2833
		}
2834
		$info = &$this->getid3->info;
2835
		$comment_key = '';
2836
		if ($boxname && ($boxname != $keyname)) {
2837
			$comment_key = (isset($handyatomtranslatorarray[$boxname]) ? $handyatomtranslatorarray[$boxname] : $boxname);
2838
		} elseif (isset($handyatomtranslatorarray[$keyname])) {
2839
			$comment_key = $handyatomtranslatorarray[$keyname];
2840
		}
2841
		if ($comment_key) {
2842
			if ($comment_key == 'picture') {
2843
				if (!is_array($data)) {
2844
					$image_mime = '';
2845
					if (preg_match('#^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A#', $data)) {
2846
						$image_mime = 'image/png';
2847
					} elseif (preg_match('#^\xFF\xD8\xFF#', $data)) {
2848
						$image_mime = 'image/jpeg';
2849
					} elseif (preg_match('#^GIF#', $data)) {
2850
						$image_mime = 'image/gif';
2851
					} elseif (preg_match('#^BM#', $data)) {
2852
						$image_mime = 'image/bmp';
2853
					}
2854
					$data = array('data'=>$data, 'image_mime'=>$image_mime);
2855
				}
2856
			}
2857
			$gooddata = array($data);
2858
			if ($comment_key == 'genre') {
2859
				// some other taggers separate multiple genres with semicolon, e.g. "Heavy Metal;Thrash Metal;Metal"
2860
				$gooddata = explode(';', $data);
2861
			}
2862
			foreach ($gooddata as $data) {
2863
				if (is_array($data) || (!empty($info['quicktime']['comments'][$comment_key]) && in_array($data, $info['quicktime']['comments'][$comment_key]))) {
2864
					// avoid duplicate copies of identical data
2865
					continue;
2866
				}
2867
				$info['quicktime']['comments'][$comment_key][] = $data;
2868
			}
2869
		}
2870
		return true;
2871
	}
2872
2873
	/**
2874
	 * @param string $lstring
2875
	 * @param int    $count
2876
	 *
2877
	 * @return string
2878
	 */
2879
	public function LociString($lstring, &$count) {
2880
		// Loci strings are UTF-8 or UTF-16 and null (x00/x0000) terminated. UTF-16 has a BOM
2881
		// Also need to return the number of bytes the string occupied so additional fields can be extracted
2882
		$len = strlen($lstring);
2883
		if ($len == 0) {
2884
			$count = 0;
2885
			return '';
2886
		}
2887
		if ($lstring[0] == "\x00") {
2888
			$count = 1;
2889
			return '';
2890
		}
2891
		// check for BOM
2892
		if (($len > 2) && ((($lstring[0] == "\xFE") && ($lstring[1] == "\xFF")) || (($lstring[0] == "\xFF") && ($lstring[1] == "\xFE")))) {
2893
			// UTF-16
2894 View Code Duplication
			if (preg_match('/(.*)\x00/', $lstring, $lmatches)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
2895
				$count = strlen($lmatches[1]) * 2 + 2; //account for 2 byte characters and trailing \x0000
2896
				return getid3_lib::iconv_fallback_utf16_utf8($lmatches[1]);
2897
			} else {
2898
				return '';
2899
			}
2900
		}
2901
		// UTF-8
2902 View Code Duplication
		if (preg_match('/(.*)\x00/', $lstring, $lmatches)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
2903
			$count = strlen($lmatches[1]) + 1; //account for trailing \x00
2904
			return $lmatches[1];
2905
		}
2906
		return '';
2907
	}
2908
2909
	/**
2910
	 * @param string $nullterminatedstring
2911
	 *
2912
	 * @return string
2913
	 */
2914 View Code Duplication
	public function NoNullString($nullterminatedstring) {
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...
2915
		// remove the single null terminator on null terminated strings
2916
		if (substr($nullterminatedstring, strlen($nullterminatedstring) - 1, 1) === "\x00") {
2917
			return substr($nullterminatedstring, 0, strlen($nullterminatedstring) - 1);
2918
		}
2919
		return $nullterminatedstring;
2920
	}
2921
2922
	/**
2923
	 * @param string $pascalstring
2924
	 *
2925
	 * @return string
2926
	 */
2927
	public function Pascal2String($pascalstring) {
2928
		// Pascal strings have 1 unsigned byte at the beginning saying how many chars (1-255) are in the string
2929
		return substr($pascalstring, 1);
2930
	}
2931
2932
2933
	/**
2934
	 * Helper functions for m4b audiobook chapters
2935
	 * code by Steffen Hartmann 2015-Nov-08.
2936
	 *
2937
	 * @param array  $info
2938
	 * @param string $tag
2939
	 * @param string $history
2940
	 * @param array  $result
2941
	 */
2942
	public function search_tag_by_key($info, $tag, $history, &$result) {
2943
		foreach ($info as $key => $value) {
2944
			$key_history = $history.'/'.$key;
2945
			if ($key === $tag) {
2946
				$result[] = array($key_history, $info);
2947
			} else {
2948
				if (is_array($value)) {
2949
					$this->search_tag_by_key($value, $tag, $key_history, $result);
2950
				}
2951
			}
2952
		}
2953
	}
2954
2955
	/**
2956
	 * @param array  $info
2957
	 * @param string $k
2958
	 * @param string $v
2959
	 * @param string $history
2960
	 * @param array  $result
2961
	 */
2962
	public function search_tag_by_pair($info, $k, $v, $history, &$result) {
2963
		foreach ($info as $key => $value) {
2964
			$key_history = $history.'/'.$key;
2965
			if (($key === $k) && ($value === $v)) {
2966
				$result[] = array($key_history, $info);
2967
			} else {
2968
				if (is_array($value)) {
2969
					$this->search_tag_by_pair($value, $k, $v, $key_history, $result);
2970
				}
2971
			}
2972
		}
2973
	}
2974
2975
	/**
2976
	 * @param array $info
2977
	 *
2978
	 * @return array
2979
	 */
2980
	public function quicktime_time_to_sample_table($info) {
2981
		$res = array();
2982
		$this->search_tag_by_pair($info['quicktime']['moov'], 'name', 'stbl', 'quicktime/moov', $res);
2983
		foreach ($res as $value) {
2984
			$stbl_res = array();
2985
			$this->search_tag_by_pair($value[1], 'data_format', 'text', $value[0], $stbl_res);
2986
			if (count($stbl_res) > 0) {
2987
				$stts_res = array();
2988
				$this->search_tag_by_key($value[1], 'time_to_sample_table', $value[0], $stts_res);
2989
				if (count($stts_res) > 0) {
2990
					return $stts_res[0][1]['time_to_sample_table'];
2991
				}
2992
			}
2993
		}
2994
		return array();
2995
	}
2996
2997
	/**
2998
	 * @param array $info
2999
	 *
3000
	 * @return int
3001
	 */
3002
	public function quicktime_bookmark_time_scale($info) {
3003
		$time_scale = '';
3004
		$ts_prefix_len = 0;
3005
		$res = array();
3006
		$this->search_tag_by_pair($info['quicktime']['moov'], 'name', 'stbl', 'quicktime/moov', $res);
3007
		foreach ($res as $value) {
3008
			$stbl_res = array();
3009
			$this->search_tag_by_pair($value[1], 'data_format', 'text', $value[0], $stbl_res);
3010
			if (count($stbl_res) > 0) {
3011
				$ts_res = array();
3012
				$this->search_tag_by_key($info['quicktime']['moov'], 'time_scale', 'quicktime/moov', $ts_res);
3013
				foreach ($ts_res as $sub_value) {
3014
					$prefix = substr($sub_value[0], 0, -12);
3015
					if ((substr($stbl_res[0][0], 0, strlen($prefix)) === $prefix) && ($ts_prefix_len < strlen($prefix))) {
3016
						$time_scale = $sub_value[1]['time_scale'];
3017
						$ts_prefix_len = strlen($prefix);
3018
					}
3019
				}
3020
			}
3021
		}
3022
		return $time_scale;
3023
	}
3024
	/*
3025
	// END helper functions for m4b audiobook chapters
3026
	*/
3027
3028
3029
}
3030