Completed
Push — vendor/getid3 ( 49c253...dfd0b4 )
by Pauli
02:49
created

getid3_quicktime::QuicktimeVideoCodecLookup()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 58

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 4
nop 1
dl 0
loc 58
rs 8.9163
c 0
b 0
f 0

How to fix   Long Method   

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
if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers
19
	exit;
20
}
21
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
22
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); // needed for ISO 639-2 language code lookup
23
24
class getid3_quicktime extends getid3_handler
25
{
26
27
	public $ReturnAtomData        = true;
28
	public $ParseAllPossibleAtoms = false;
29
30
	/**
31
	 * @return bool
32
	 */
33
	public function Analyze() {
34
		$info = &$this->getid3->info;
35
36
		$info['fileformat'] = 'quicktime';
37
		$info['quicktime']['hinting']    = false;
38
		$info['quicktime']['controller'] = 'standard'; // may be overridden if 'ctyp' atom is present
39
40
		$this->fseek($info['avdataoffset']);
41
42
		$offset      = 0;
43
		$atomcounter = 0;
44
		$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]
45
		while ($offset < $info['avdataend']) {
46
			if (!getid3_lib::intValueSupported($offset)) {
47
				$this->error('Unable to parse atom at offset '.$offset.' because beyond '.round(PHP_INT_MAX / 1073741824).'GB limit of PHP filesystem functions');
48
				break;
49
			}
50
			$this->fseek($offset);
51
			$AtomHeader = $this->fread(8);
52
53
			$atomsize = getid3_lib::BigEndian2Int(substr($AtomHeader, 0, 4));
54
			$atomname = substr($AtomHeader, 4, 4);
55
56
			// 64-bit MOV patch by jlegateØktnc*com
57
			if ($atomsize == 1) {
58
				$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...
59
			}
60
61
			if (($offset + $atomsize) > $info['avdataend']) {
62
				$info['quicktime'][$atomname]['name']   = $atomname;
63
				$info['quicktime'][$atomname]['size']   = $atomsize;
64
				$info['quicktime'][$atomname]['offset'] = $offset;
65
				$this->error('Atom at offset '.$offset.' claims to go beyond end-of-file (length: '.$atomsize.' bytes)');
66
				return false;
67
			}
68
			if ($atomsize == 0) {
69
				// Furthermore, for historical reasons the list of atoms is optionally
70
				// terminated by a 32-bit integer set to 0. If you are writing a program
71
				// to read user data atoms, you should allow for the terminating 0.
72
				$info['quicktime'][$atomname]['name']   = $atomname;
73
				$info['quicktime'][$atomname]['size']   = $atomsize;
74
				$info['quicktime'][$atomname]['offset'] = $offset;
75
				break;
76
			}
77
78
			$atomHierarchy = array();
79
			$parsedAtomData = $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...
80
			$parsedAtomData['name']   = $atomname;
81
			$parsedAtomData['size']   = $atomsize;
82
			$parsedAtomData['offset'] = $offset;
83
			if (in_array($atomname, array('uuid'))) {
84
				@$info['quicktime'][$atomname][] = $parsedAtomData;
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...
85
			} else {
86
				$info['quicktime'][$atomname] = $parsedAtomData;
87
			}
88
89
			$offset += $atomsize;
90
			$atomcounter++;
91
		}
92
93
		if (!empty($info['avdataend_tmp'])) {
94
			// this value is assigned to a temp value and then erased because
95
			// otherwise any atoms beyond the 'mdat' atom would not get parsed
96
			$info['avdataend'] = $info['avdataend_tmp'];
97
			unset($info['avdataend_tmp']);
98
		}
99
100
		if (!empty($info['quicktime']['comments']['chapters']) && is_array($info['quicktime']['comments']['chapters']) && (count($info['quicktime']['comments']['chapters']) > 0)) {
101
			$durations = $this->quicktime_time_to_sample_table($info);
102
			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...
103
				$bookmark = array();
104
				$bookmark['title'] = $info['quicktime']['comments']['chapters'][$i];
105
				if (isset($durations[$i])) {
106
					$bookmark['duration_sample'] = $durations[$i]['sample_duration'];
107
					if ($i > 0) {
108
						$bookmark['start_sample'] = $info['quicktime']['bookmarks'][($i - 1)]['start_sample'] + $info['quicktime']['bookmarks'][($i - 1)]['duration_sample'];
109
					} else {
110
						$bookmark['start_sample'] = 0;
111
					}
112
					if ($time_scale = $this->quicktime_bookmark_time_scale($info)) {
113
						$bookmark['duration_seconds'] = $bookmark['duration_sample'] / $time_scale;
114
						$bookmark['start_seconds']    = $bookmark['start_sample']    / $time_scale;
115
					}
116
				}
117
				$info['quicktime']['bookmarks'][] = $bookmark;
118
			}
119
		}
120
121
		if (isset($info['quicktime']['temp_meta_key_names'])) {
122
			unset($info['quicktime']['temp_meta_key_names']);
123
		}
124
125
		if (!empty($info['quicktime']['comments']['location.ISO6709'])) {
126
			// https://en.wikipedia.org/wiki/ISO_6709
127
			foreach ($info['quicktime']['comments']['location.ISO6709'] as $ISO6709string) {
128
				$ISO6709parsed = array('latitude'=>false, 'longitude'=>false, 'altitude'=>false);
129
				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)) {
130
					@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...
131
132 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...
133
						$ISO6709parsed['latitude'] = (($lat_sign == '-') ? -1 : 1) * floatval(ltrim($lat_deg, '0').$lat_deg_dec);
134
					} elseif (strlen($lat_deg) == 4) {  // [+-]DDMM.M
135
						$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);
136
					} elseif (strlen($lat_deg) == 6) {  // [+-]DDMMSS.S
137
						$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);
138
					}
139
140 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...
141
						$ISO6709parsed['longitude'] = (($lon_sign == '-') ? -1 : 1) * floatval(ltrim($lon_deg, '0').$lon_deg_dec);
142
					} elseif (strlen($lon_deg) == 5) {  // [+-]DDDMM.M
143
						$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);
144
					} elseif (strlen($lon_deg) == 7) {  // [+-]DDDMMSS.S
145
						$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);
146
					}
147
148 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...
149
						$ISO6709parsed['altitude'] = (($alt_sign == '-') ? -1 : 1) * floatval(ltrim($alt_deg, '0').$alt_deg_dec);
150
					} elseif (strlen($alt_deg) == 5) {  // [+-]DDDMM.M
151
						$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);
152
					} elseif (strlen($alt_deg) == 7) {  // [+-]DDDMMSS.S
153
						$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);
154
					}
155
156
					foreach (array('latitude', 'longitude', 'altitude') as $key) {
157
						if ($ISO6709parsed[$key] !== false) {
158
							$value = (($lat_sign == '-') ? -1 : 1) * floatval($ISO6709parsed[$key]);
159
							if (!isset($info['quicktime']['comments']['gps_'.$key]) || !in_array($value, $info['quicktime']['comments']['gps_'.$key])) {
160
								@$info['quicktime']['comments']['gps_'.$key][] = (($lat_sign == '-') ? -1 : 1) * floatval($ISO6709parsed[$key]);
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...
161
							}
162
						}
163
					}
164
				}
165
				if ($ISO6709parsed['latitude'] === false) {
166
					$this->warning('location.ISO6709 string not parsed correctly: "'.$ISO6709string.'", please submit as a bug');
167
				}
168
				break;
169
			}
170
		}
171
172 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...
173
			$info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
174
		}
175
		if (isset($info['bitrate']) && !isset($info['audio']['bitrate']) && !isset($info['quicktime']['video'])) {
176
			$info['audio']['bitrate'] = $info['bitrate'];
177
		}
178
		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'])) {
179
			$info['video']['bitrate'] = $info['bitrate'] - $info['audio']['bitrate'];
180
		}
181
		if (!empty($info['playtime_seconds']) && !isset($info['video']['frame_rate']) && !empty($info['quicktime']['stts_framecount'])) {
182
			foreach ($info['quicktime']['stts_framecount'] as $key => $samples_count) {
183
				$samples_per_second = $samples_count / $info['playtime_seconds'];
184
				if ($samples_per_second > 240) {
185
					// has to be audio samples
186
				} else {
187
					$info['video']['frame_rate'] = $samples_per_second;
188
					break;
189
				}
190
			}
191
		}
192
		if ($info['audio']['dataformat'] == 'mp4') {
193
			$info['fileformat'] = 'mp4';
194
			if (empty($info['video']['resolution_x'])) {
195
				$info['mime_type']  = 'audio/mp4';
196
				unset($info['video']['dataformat']);
197
			} else {
198
				$info['mime_type']  = 'video/mp4';
199
			}
200
		}
201
202
		if (!$this->ReturnAtomData) {
203
			unset($info['quicktime']['moov']);
204
		}
205
206 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...
207
			$info['audio']['dataformat'] = 'quicktime';
208
		}
209 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...
210
			$info['video']['dataformat'] = 'quicktime';
211
		}
212
		if (isset($info['video']) && ($info['mime_type'] == 'audio/mp4') && empty($info['video']['resolution_x']) && empty($info['video']['resolution_y']))  {
213
			unset($info['video']);
214
		}
215
216
		return true;
217
	}
218
219
	/**
220
	 * @param string $atomname
221
	 * @param int    $atomsize
222
	 * @param string $atom_data
223
	 * @param int    $baseoffset
224
	 * @param array  $atomHierarchy
225
	 * @param bool   $ParseAllPossibleAtoms
226
	 *
227
	 * @return array|false
228
	 */
229
	public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
230
		// http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm
231
		// https://code.google.com/p/mp4v2/wiki/iTunesMetadata
232
233
		$info = &$this->getid3->info;
234
235
		$atom_parent = end($atomHierarchy); // not array_pop($atomHierarchy); see https://www.getid3.org/phpBB3/viewtopic.php?t=1717
236
		array_push($atomHierarchy, $atomname);
237
		$atom_structure              = array();
238
		$atom_structure['hierarchy'] = implode(' ', $atomHierarchy);
239
		$atom_structure['name']      = $atomname;
240
		$atom_structure['size']      = $atomsize;
241
		$atom_structure['offset']    = $baseoffset;
242
		if (substr($atomname, 0, 3) == "\x00\x00\x00") {
243
			// https://github.com/JamesHeinrich/getID3/issues/139
244
			$atomname = getid3_lib::BigEndian2Int($atomname);
245
			$atom_structure['name'] = $atomname;
246
			$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
247
		} else {
248
			switch ($atomname) {
249
				case 'moov': // MOVie container atom
250
				case 'trak': // TRAcK container atom
251
				case 'clip': // CLIPping container atom
252
				case 'matt': // track MATTe container atom
253
				case 'edts': // EDiTS container atom
254
				case 'tref': // Track REFerence container atom
255
				case 'mdia': // MeDIA container atom
256
				case 'minf': // Media INFormation container atom
257
				case 'dinf': // Data INFormation container atom
258
				case 'nmhd': // Null Media HeaDer container atom
259
				case 'udta': // User DaTA container atom
260
				case 'cmov': // Compressed MOVie container atom
261
				case 'rmra': // Reference Movie Record Atom
262
				case 'rmda': // Reference Movie Descriptor Atom
263
				case 'gmhd': // Generic Media info HeaDer atom (seen on QTVR)
264
					$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
265
					break;
266
267
				case 'ilst': // Item LiST container atom
268
					if ($atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms)) {
269
						// some "ilst" atoms contain data atoms that have a numeric name, and the data is far more accessible if the returned array is compacted
270
						$allnumericnames = true;
271
						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...
272
							if (!is_integer($subatomarray['name']) || (count($subatomarray['subatoms']) != 1)) {
273
								$allnumericnames = false;
274
								break;
275
							}
276
						}
277
						if ($allnumericnames) {
278
							$newData = array();
279
							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...
280
								foreach ($subatomarray['subatoms'] as $newData_subatomarray) {
281
									unset($newData_subatomarray['hierarchy'], $newData_subatomarray['name']);
282
									$newData[$subatomarray['name']] = $newData_subatomarray;
283
									break;
284
								}
285
							}
286
							$atom_structure['data'] = $newData;
287
							unset($atom_structure['subatoms']);
288
						}
289
					}
290
					break;
291
292
				case 'stbl': // Sample TaBLe container atom
293
					$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
294
					$isVideo = false;
295
					$framerate  = 0;
296
					$framecount = 0;
297
					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...
298
						if (isset($value_array['sample_description_table'])) {
299
							foreach ($value_array['sample_description_table'] as $key2 => $value_array2) {
300
								if (isset($value_array2['data_format'])) {
301
									switch ($value_array2['data_format']) {
302
										case 'avc1':
303
										case 'mp4v':
304
											// video data
305
											$isVideo = true;
306
											break;
307
										case 'mp4a':
308
											// audio data
309
											break;
310
									}
311
								}
312
							}
313
						} elseif (isset($value_array['time_to_sample_table'])) {
314
							foreach ($value_array['time_to_sample_table'] as $key2 => $value_array2) {
315
								if (isset($value_array2['sample_count']) && isset($value_array2['sample_duration']) && ($value_array2['sample_duration'] > 0)) {
316
									$framerate  = round($info['quicktime']['time_scale'] / $value_array2['sample_duration'], 3);
317
									$framecount = $value_array2['sample_count'];
318
								}
319
							}
320
						}
321
					}
322
					if ($isVideo && $framerate) {
323
						$info['quicktime']['video']['frame_rate'] = $framerate;
324
						$info['video']['frame_rate'] = $info['quicktime']['video']['frame_rate'];
325
					}
326
					if ($isVideo && $framecount) {
327
						$info['quicktime']['video']['frame_count'] = $framecount;
328
					}
329
					break;
330
331
332
				case "\xA9".'alb': // ALBum
333
				case "\xA9".'ART': //
334
				case "\xA9".'art': // ARTist
335
				case "\xA9".'aut': //
336
				case "\xA9".'cmt': // CoMmenT
337
				case "\xA9".'com': // COMposer
338
				case "\xA9".'cpy': //
339
				case "\xA9".'day': // content created year
340
				case "\xA9".'dir': //
341
				case "\xA9".'ed1': //
342
				case "\xA9".'ed2': //
343
				case "\xA9".'ed3': //
344
				case "\xA9".'ed4': //
345
				case "\xA9".'ed5': //
346
				case "\xA9".'ed6': //
347
				case "\xA9".'ed7': //
348
				case "\xA9".'ed8': //
349
				case "\xA9".'ed9': //
350
				case "\xA9".'enc': //
351
				case "\xA9".'fmt': //
352
				case "\xA9".'gen': // GENre
353
				case "\xA9".'grp': // GRouPing
354
				case "\xA9".'hst': //
355
				case "\xA9".'inf': //
356
				case "\xA9".'lyr': // LYRics
357
				case "\xA9".'mak': //
358
				case "\xA9".'mod': //
359
				case "\xA9".'nam': // full NAMe
360
				case "\xA9".'ope': //
361
				case "\xA9".'PRD': //
362
				case "\xA9".'prf': //
363
				case "\xA9".'req': //
364
				case "\xA9".'src': //
365
				case "\xA9".'swr': //
366
				case "\xA9".'too': // encoder
367
				case "\xA9".'trk': // TRacK
368
				case "\xA9".'url': //
369
				case "\xA9".'wrn': //
370
				case "\xA9".'wrt': // WRiTer
371
				case '----': // itunes specific
372
				case 'aART': // Album ARTist
373
				case 'akID': // iTunes store account type
374
				case 'apID': // Purchase Account
375
				case 'atID': //
376
				case 'catg': // CaTeGory
377
				case 'cmID': //
378
				case 'cnID': //
379
				case 'covr': // COVeR artwork
380
				case 'cpil': // ComPILation
381
				case 'cprt': // CoPyRighT
382
				case 'desc': // DESCription
383
				case 'disk': // DISK number
384
				case 'egid': // Episode Global ID
385
				case 'geID': //
386
				case 'gnre': // GeNRE
387
				case 'hdvd': // HD ViDeo
388
				case 'keyw': // KEYWord
389
				case 'ldes': // Long DEScription
390
				case 'pcst': // PodCaST
391
				case 'pgap': // GAPless Playback
392
				case 'plID': //
393
				case 'purd': // PURchase Date
394
				case 'purl': // Podcast URL
395
				case 'rati': //
396
				case 'rndu': //
397
				case 'rpdu': //
398
				case 'rtng': // RaTiNG
399
				case 'sfID': // iTunes store country
400
				case 'soaa': // SOrt Album Artist
401
				case 'soal': // SOrt ALbum
402
				case 'soar': // SOrt ARtist
403
				case 'soco': // SOrt COmposer
404
				case 'sonm': // SOrt NaMe
405
				case 'sosn': // SOrt Show Name
406
				case 'stik': //
407
				case 'tmpo': // TeMPO (BPM)
408
				case 'trkn': // TRacK Number
409
				case 'tven': // tvEpisodeID
410
				case 'tves': // TV EpiSode
411
				case 'tvnn': // TV Network Name
412
				case 'tvsh': // TV SHow Name
413
				case 'tvsn': // TV SeasoN
414
					if ($atom_parent == 'udta') {
415
						// User data atom handler
416
						$atom_structure['data_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
417
						$atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2));
418
						$atom_structure['data']        =                           substr($atom_data, 4);
419
420
						$atom_structure['language']    = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
421 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...
422
							$info['comments']['language'][] = $atom_structure['language'];
423
						}
424
					} else {
425
						// Apple item list box atom handler
426
						$atomoffset = 0;
427
						if (substr($atom_data, 2, 2) == "\x10\xB5") {
428
							// not sure what it means, but observed on iPhone4 data.
429
							// Each $atom_data has 2 bytes of datasize, plus 0x10B5, then data
430
							while ($atomoffset < strlen($atom_data)) {
431
								$boxsmallsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset,     2));
432
								$boxsmalltype =                           substr($atom_data, $atomoffset + 2, 2);
433
								$boxsmalldata =                           substr($atom_data, $atomoffset + 4, $boxsmallsize);
434 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...
435
									$this->warning('Invalid QuickTime atom smallbox size "'.$boxsmallsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset));
436
									$atom_structure['data'] = null;
437
									$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...
438
									break;
439
								}
440
								switch ($boxsmalltype) {
441
									case "\x10\xB5":
442
										$atom_structure['data'] = $boxsmalldata;
443
										break;
444 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...
445
										$this->warning('Unknown QuickTime smallbox type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxsmalltype).'" ('.trim(getid3_lib::PrintHexBytes($boxsmalltype)).') at offset '.$baseoffset);
446
										$atom_structure['data'] = $atom_data;
447
										break;
448
								}
449
								$atomoffset += (4 + $boxsmallsize);
450
							}
451
						} else {
452
							while ($atomoffset < strlen($atom_data)) {
453
								$boxsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset, 4));
454
								$boxtype =                           substr($atom_data, $atomoffset + 4, 4);
455
								$boxdata =                           substr($atom_data, $atomoffset + 8, $boxsize - 8);
456 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...
457
									$this->warning('Invalid QuickTime atom box size "'.$boxsize.'" in atom "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" at offset: '.($atom_structure['offset'] + $atomoffset));
458
									$atom_structure['data'] = null;
459
									$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...
460
									break;
461
								}
462
								$atomoffset += $boxsize;
463
464
								switch ($boxtype) {
465
									case 'mean':
466
									case 'name':
467
										$atom_structure[$boxtype] = substr($boxdata, 4);
468
										break;
469
470
									case 'data':
471
										$atom_structure['version']   = getid3_lib::BigEndian2Int(substr($boxdata,  0, 1));
472
										$atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($boxdata,  1, 3));
473
										switch ($atom_structure['flags_raw']) {
474
											case  0: // data flag
475
											case 21: // tmpo/cpil flag
476
												switch ($atomname) {
477
													case 'cpil':
478
													case 'hdvd':
479
													case 'pcst':
480
													case 'pgap':
481
														// 8-bit integer (boolean)
482
														$atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
483
														break;
484
485
													case 'tmpo':
486
														// 16-bit integer
487
														$atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 2));
488
														break;
489
490
													case 'disk':
491
													case 'trkn':
492
														// binary
493
														$num       = getid3_lib::BigEndian2Int(substr($boxdata, 10, 2));
494
														$num_total = getid3_lib::BigEndian2Int(substr($boxdata, 12, 2));
495
														$atom_structure['data']  = empty($num) ? '' : $num;
496
														$atom_structure['data'] .= empty($num_total) ? '' : '/'.$num_total;
497
														break;
498
499
													case 'gnre':
500
														// enum
501
														$GenreID = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
502
														$atom_structure['data']    = getid3_id3v1::LookupGenreName($GenreID - 1);
503
														break;
504
505 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...
506
														// 8-bit integer
507
														$atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
508
														$atom_structure['data']    = $this->QuicktimeContentRatingLookup($atom_structure[$atomname]);
509
														break;
510
511 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...
512
														// 8-bit integer (enum)
513
														$atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
514
														$atom_structure['data']    = $this->QuicktimeSTIKLookup($atom_structure[$atomname]);
515
														break;
516
517 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...
518
														// 32-bit integer
519
														$atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
520
														$atom_structure['data']    = $this->QuicktimeStoreFrontCodeLookup($atom_structure[$atomname]);
521
														break;
522
523
													case 'egid':
524
													case 'purl':
525
														$atom_structure['data'] = substr($boxdata, 8);
526
														break;
527
528
													case 'plID':
529
														// 64-bit integer
530
														$atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 8));
531
														break;
532
533 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...
534
														$atom_structure['data'] = substr($boxdata, 8);
535
														// not a foolproof check, but better than nothing
536
														if (preg_match('#^\\xFF\\xD8\\xFF#', $atom_structure['data'])) {
537
															$atom_structure['image_mime'] = 'image/jpeg';
538
														} elseif (preg_match('#^\\x89\\x50\\x4E\\x47\\x0D\\x0A\\x1A\\x0A#', $atom_structure['data'])) {
539
															$atom_structure['image_mime'] = 'image/png';
540
														} elseif (preg_match('#^GIF#', $atom_structure['data'])) {
541
															$atom_structure['image_mime'] = 'image/gif';
542
														}
543
														$info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_structure['data'], 'description'=>'cover');
544
														break;
545
546
													case 'atID':
547
													case 'cnID':
548
													case 'geID':
549
													case 'tves':
550
													case 'tvsn':
551
													default:
552
														// 32-bit integer
553
														$atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
554
												}
555
												break;
556
557
											case  1: // text flag
558
											case 13: // image flag
559 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...
560
												$atom_structure['data'] = substr($boxdata, 8);
561
												if ($atomname == 'covr') {
562
													// not a foolproof check, but better than nothing
563
													if (preg_match('#^\\xFF\\xD8\\xFF#', $atom_structure['data'])) {
564
														$atom_structure['image_mime'] = 'image/jpeg';
565
													} elseif (preg_match('#^\\x89\\x50\\x4E\\x47\\x0D\\x0A\\x1A\\x0A#', $atom_structure['data'])) {
566
														$atom_structure['image_mime'] = 'image/png';
567
													} elseif (preg_match('#^GIF#', $atom_structure['data'])) {
568
														$atom_structure['image_mime'] = 'image/gif';
569
													}
570
													$info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_structure['data'], 'description'=>'cover');
571
												}
572
												break;
573
574
										}
575
										break;
576
577 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...
578
										$this->warning('Unknown QuickTime box type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $boxtype).'" ('.trim(getid3_lib::PrintHexBytes($boxtype)).') at offset '.$baseoffset);
579
										$atom_structure['data'] = $atom_data;
580
581
								}
582
							}
583
						}
584
					}
585
					$this->CopyToAppropriateCommentsSection($atomname, $atom_structure['data'], $atom_structure['name']);
586
					break;
587
588
589
				case 'play': // auto-PLAY atom
590
					$atom_structure['autoplay'] = (bool) getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
591
592
					$info['quicktime']['autoplay'] = $atom_structure['autoplay'];
593
					break;
594
595
596 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...
597
					$atom_structure['location_x']  = getid3_lib::BigEndian2Int(substr($atom_data,  0, 2));
598
					$atom_structure['location_y']  = getid3_lib::BigEndian2Int(substr($atom_data,  2, 2));
599
					break;
600
601
602
				case 'LOOP': // LOOPing atom
603
				case 'SelO': // play SELection Only atom
604
				case 'AllF': // play ALL Frames atom
605
					$atom_structure['data'] = getid3_lib::BigEndian2Int($atom_data);
606
					break;
607
608
609
				case 'name': //
610
				case 'MCPS': // Media Cleaner PRo
611
				case '@PRM': // adobe PReMiere version
612
				case '@PRQ': // adobe PRemiere Quicktime version
613
					$atom_structure['data'] = $atom_data;
614
					break;
615
616
617
				case 'cmvd': // Compressed MooV Data atom
618
					// Code by ubergeekØubergeek*tv based on information from
619
					// http://developer.apple.com/quicktime/icefloe/dispatch012.html
620
					$atom_structure['unCompressedSize'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4));
621
622
					$CompressedFileData = substr($atom_data, 4);
623
					if ($UncompressedHeader = @gzuncompress($CompressedFileData)) {
624
						$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($UncompressedHeader, 0, $atomHierarchy, $ParseAllPossibleAtoms);
625
					} else {
626
						$this->warning('Error decompressing compressed MOV atom at offset '.$atom_structure['offset']);
627
					}
628
					break;
629
630
631
				case 'dcom': // Data COMpression atom
632
					$atom_structure['compression_id']   = $atom_data;
633
					$atom_structure['compression_text'] = $this->QuicktimeDCOMLookup($atom_data);
634
					break;
635
636
637
				case 'rdrf': // Reference movie Data ReFerence atom
638
					$atom_structure['version']                = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
639
					$atom_structure['flags_raw']              = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3));
640
					$atom_structure['flags']['internal_data'] = (bool) ($atom_structure['flags_raw'] & 0x000001);
641
642
					$atom_structure['reference_type_name']    =                           substr($atom_data,  4, 4);
643
					$atom_structure['reference_length']       = getid3_lib::BigEndian2Int(substr($atom_data,  8, 4));
644
					switch ($atom_structure['reference_type_name']) {
645
						case 'url ':
646
							$atom_structure['url']            =       $this->NoNullString(substr($atom_data, 12));
647
							break;
648
649
						case 'alis':
650
							$atom_structure['file_alias']     =                           substr($atom_data, 12);
651
							break;
652
653
						case 'rsrc':
654
							$atom_structure['resource_alias'] =                           substr($atom_data, 12);
655
							break;
656
657
						default:
658
							$atom_structure['data']           =                           substr($atom_data, 12);
659
							break;
660
					}
661
					break;
662
663
664
				case 'rmqu': // Reference Movie QUality atom
665
					$atom_structure['movie_quality'] = getid3_lib::BigEndian2Int($atom_data);
666
					break;
667
668
669 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...
670
					$atom_structure['version']          = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
671
					$atom_structure['flags_raw']        = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
672
					$atom_structure['cpu_speed_rating'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 2));
673
					break;
674
675
676
				case 'rmvc': // Reference Movie Version Check atom
677
					$atom_structure['version']            = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
678
					$atom_structure['flags_raw']          = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
679
					$atom_structure['gestalt_selector']   =                           substr($atom_data,  4, 4);
680
					$atom_structure['gestalt_value_mask'] = getid3_lib::BigEndian2Int(substr($atom_data,  8, 4));
681
					$atom_structure['gestalt_value']      = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
682
					$atom_structure['gestalt_check_type'] = getid3_lib::BigEndian2Int(substr($atom_data, 14, 2));
683
					break;
684
685
686
				case 'rmcd': // Reference Movie Component check atom
687
					$atom_structure['version']                = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
688
					$atom_structure['flags_raw']              = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
689
					$atom_structure['component_type']         =                           substr($atom_data,  4, 4);
690
					$atom_structure['component_subtype']      =                           substr($atom_data,  8, 4);
691
					$atom_structure['component_manufacturer'] =                           substr($atom_data, 12, 4);
692
					$atom_structure['component_flags_raw']    = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
693
					$atom_structure['component_flags_mask']   = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));
694
					$atom_structure['component_min_version']  = getid3_lib::BigEndian2Int(substr($atom_data, 24, 4));
695
					break;
696
697
698 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...
699
					$atom_structure['version']       = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
700
					$atom_structure['flags_raw']     = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
701
					$atom_structure['data_rate']     = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
702
703
					$atom_structure['data_rate_bps'] = $atom_structure['data_rate'] * 10;
704
					break;
705
706
707
				case 'rmla': // Reference Movie Language Atom
708
					$atom_structure['version']     = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
709
					$atom_structure['flags_raw']   = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
710
					$atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 2));
711
712
					$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...
713 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...
714
						$info['comments']['language'][] = $atom_structure['language'];
715
					}
716
					break;
717
718
719
				case 'ptv ': // Print To Video - defines a movie's full screen mode
720
					// http://developer.apple.com/documentation/QuickTime/APIREF/SOURCESIV/at_ptv-_pg.htm
721
					$atom_structure['display_size_raw']  = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
722
					$atom_structure['reserved_1']        = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2)); // hardcoded: 0x0000
723
					$atom_structure['reserved_2']        = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x0000
724
					$atom_structure['slide_show_flag']   = getid3_lib::BigEndian2Int(substr($atom_data, 6, 1));
725
					$atom_structure['play_on_open_flag'] = getid3_lib::BigEndian2Int(substr($atom_data, 7, 1));
726
727
					$atom_structure['flags']['play_on_open'] = (bool) $atom_structure['play_on_open_flag'];
728
					$atom_structure['flags']['slide_show']   = (bool) $atom_structure['slide_show_flag'];
729
730
					$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...
731
					$ptv_lookup[1] = 'double';
732
					$ptv_lookup[2] = 'half';
733
					$ptv_lookup[3] = 'full';
734
					$ptv_lookup[4] = 'current';
735
					if (isset($ptv_lookup[$atom_structure['display_size_raw']])) {
736
						$atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']];
737
					} else {
738
						$this->warning('unknown "ptv " display constant ('.$atom_structure['display_size_raw'].')');
739
					}
740
					break;
741
742
743
				case 'stsd': // Sample Table Sample Description atom
744
					$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
745
					$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
746
					$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
747
748
					// see: https://github.com/JamesHeinrich/getID3/issues/111
749
					// Some corrupt files have been known to have high bits set in the number_entries field
750
					// This field shouldn't really need to be 32-bits, values stores are likely in the range 1-100000
751
					// Workaround: mask off the upper byte and throw a warning if it's nonzero
752
					if ($atom_structure['number_entries'] > 0x000FFFFF) {
753
						if ($atom_structure['number_entries'] > 0x00FFFFFF) {
754
							$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));
755
							$atom_structure['number_entries'] = ($atom_structure['number_entries'] & 0x00FFFFFF);
756
						} else {
757
							$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');
758
						}
759
					}
760
761
					$stsdEntriesDataOffset = 8;
762
					for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
763
						$atom_structure['sample_description_table'][$i]['size']             = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 4));
764
						$stsdEntriesDataOffset += 4;
765
						$atom_structure['sample_description_table'][$i]['data_format']      =                           substr($atom_data, $stsdEntriesDataOffset, 4);
766
						$stsdEntriesDataOffset += 4;
767
						$atom_structure['sample_description_table'][$i]['reserved']         = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 6));
768
						$stsdEntriesDataOffset += 6;
769
						$atom_structure['sample_description_table'][$i]['reference_index']  = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 2));
770
						$stsdEntriesDataOffset += 2;
771
						$atom_structure['sample_description_table'][$i]['data']             =                           substr($atom_data, $stsdEntriesDataOffset, ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2));
772
						$stsdEntriesDataOffset += ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2);
773
774
						if (substr($atom_structure['sample_description_table'][$i]['data'],  1, 54) == 'application/octet-stream;type=com.parrot.videometadata') {
775
							// special handling for apparently-malformed (TextMetaDataSampleEntry?) data for some version of Parrot drones
776
							$atom_structure['sample_description_table'][$i]['parrot_frame_metadata']['mime_type']        =       substr($atom_structure['sample_description_table'][$i]['data'],  1, 55);
777
							$atom_structure['sample_description_table'][$i]['parrot_frame_metadata']['metadata_version'] = (int) substr($atom_structure['sample_description_table'][$i]['data'], 55,  1);
778
							unset($atom_structure['sample_description_table'][$i]['data']);
779
$this->warning('incomplete/incorrect handling of "stsd" with Parrot metadata in this version of getID3() ['.$this->getid3->version().']');
780
							continue;
781
						}
782
783
						$atom_structure['sample_description_table'][$i]['encoder_version']  = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'],  0, 2));
784
						$atom_structure['sample_description_table'][$i]['encoder_revision'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'],  2, 2));
785
						$atom_structure['sample_description_table'][$i]['encoder_vendor']   =                           substr($atom_structure['sample_description_table'][$i]['data'],  4, 4);
786
787
						switch ($atom_structure['sample_description_table'][$i]['encoder_vendor']) {
788
789
							case "\x00\x00\x00\x00":
790
								// audio tracks
791
								$atom_structure['sample_description_table'][$i]['audio_channels']       =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'],  8,  2));
792
								$atom_structure['sample_description_table'][$i]['audio_bit_depth']      =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 10,  2));
793
								$atom_structure['sample_description_table'][$i]['audio_compression_id'] =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12,  2));
794
								$atom_structure['sample_description_table'][$i]['audio_packet_size']    =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 14,  2));
795
								$atom_structure['sample_description_table'][$i]['audio_sample_rate']    = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 16,  4));
796
797
								// video tracks
798
								// http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap3/qtff3.html
799
								$atom_structure['sample_description_table'][$i]['temporal_quality'] =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'],  8,  4));
800
								$atom_structure['sample_description_table'][$i]['spatial_quality']  =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12,  4));
801
								$atom_structure['sample_description_table'][$i]['width']            =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16,  2));
802
								$atom_structure['sample_description_table'][$i]['height']           =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18,  2));
803
								$atom_structure['sample_description_table'][$i]['resolution_x']     = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24,  4));
804
								$atom_structure['sample_description_table'][$i]['resolution_y']     = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 28,  4));
805
								$atom_structure['sample_description_table'][$i]['data_size']        =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32,  4));
806
								$atom_structure['sample_description_table'][$i]['frame_count']      =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 36,  2));
807
								$atom_structure['sample_description_table'][$i]['compressor_name']  =                             substr($atom_structure['sample_description_table'][$i]['data'], 38,  4);
808
								$atom_structure['sample_description_table'][$i]['pixel_depth']      =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 42,  2));
809
								$atom_structure['sample_description_table'][$i]['color_table_id']   =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 44,  2));
810
811
								switch ($atom_structure['sample_description_table'][$i]['data_format']) {
812
									case '2vuY':
813
									case 'avc1':
814
									case 'cvid':
815
									case 'dvc ':
816
									case 'dvcp':
817
									case 'gif ':
818
									case 'h263':
819
									case 'jpeg':
820
									case 'kpcd':
821
									case 'mjpa':
822
									case 'mjpb':
823
									case 'mp4v':
824
									case 'png ':
825
									case 'raw ':
826
									case 'rle ':
827
									case 'rpza':
828
									case 'smc ':
829
									case 'SVQ1':
830
									case 'SVQ3':
831
									case 'tiff':
832
									case 'v210':
833
									case 'v216':
834
									case 'v308':
835
									case 'v408':
836
									case 'v410':
837
									case 'yuv2':
838
										$info['fileformat'] = 'mp4';
839
										$info['video']['fourcc'] = $atom_structure['sample_description_table'][$i]['data_format'];
840
										if ($this->QuicktimeVideoCodecLookup($info['video']['fourcc'])) {
841
											$info['video']['fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($info['video']['fourcc']);
842
										}
843
844
										// https://www.getid3.org/phpBB3/viewtopic.php?t=1550
845
										//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
846
										if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($atom_structure['sample_description_table'][$i]['height'])) {
847
											// assume that values stored here are more important than values stored in [tkhd] atom
848
											$info['video']['resolution_x'] = $atom_structure['sample_description_table'][$i]['width'];
849
											$info['video']['resolution_y'] = $atom_structure['sample_description_table'][$i]['height'];
850
											$info['quicktime']['video']['resolution_x'] = $info['video']['resolution_x'];
851
											$info['quicktime']['video']['resolution_y'] = $info['video']['resolution_y'];
852
										}
853
										break;
854
855
									case 'qtvr':
856
										$info['video']['dataformat'] = 'quicktimevr';
857
										break;
858
859
									case 'mp4a':
860
									default:
861
										$info['quicktime']['audio']['codec']       = $this->QuicktimeAudioCodecLookup($atom_structure['sample_description_table'][$i]['data_format']);
862
										$info['quicktime']['audio']['sample_rate'] = $atom_structure['sample_description_table'][$i]['audio_sample_rate'];
863
										$info['quicktime']['audio']['channels']    = $atom_structure['sample_description_table'][$i]['audio_channels'];
864
										$info['quicktime']['audio']['bit_depth']   = $atom_structure['sample_description_table'][$i]['audio_bit_depth'];
865
										$info['audio']['codec']                    = $info['quicktime']['audio']['codec'];
866
										$info['audio']['sample_rate']              = $info['quicktime']['audio']['sample_rate'];
867
										$info['audio']['channels']                 = $info['quicktime']['audio']['channels'];
868
										$info['audio']['bits_per_sample']          = $info['quicktime']['audio']['bit_depth'];
869
										switch ($atom_structure['sample_description_table'][$i]['data_format']) {
870
											case 'raw ': // PCM
871
											case 'alac': // Apple Lossless Audio Codec
872
											case 'sowt': // signed/two's complement (Little Endian)
873
											case 'twos': // signed/two's complement (Big Endian)
874
											case 'in24': // 24-bit Integer
875
											case 'in32': // 32-bit Integer
876
											case 'fl32': // 32-bit Floating Point
877
											case 'fl64': // 64-bit Floating Point
878
												$info['audio']['lossless'] = $info['quicktime']['audio']['lossless'] = true;
879
												$info['audio']['bitrate']  = $info['quicktime']['audio']['bitrate']  = $info['audio']['channels'] * $info['audio']['bits_per_sample'] * $info['audio']['sample_rate'];
880
												break;
881
											default:
882
												$info['audio']['lossless'] = false;
883
												break;
884
										}
885
										break;
886
								}
887
								break;
888
889
							default:
890
								switch ($atom_structure['sample_description_table'][$i]['data_format']) {
891
									case 'mp4s':
892
										$info['fileformat'] = 'mp4';
893
										break;
894
895
									default:
896
										// video atom
897
										$atom_structure['sample_description_table'][$i]['video_temporal_quality']  =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'],  8,  4));
898
										$atom_structure['sample_description_table'][$i]['video_spatial_quality']   =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12,  4));
899
										$atom_structure['sample_description_table'][$i]['video_frame_width']       =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16,  2));
900
										$atom_structure['sample_description_table'][$i]['video_frame_height']      =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18,  2));
901
										$atom_structure['sample_description_table'][$i]['video_resolution_x']      = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 20,  4));
902
										$atom_structure['sample_description_table'][$i]['video_resolution_y']      = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24,  4));
903
										$atom_structure['sample_description_table'][$i]['video_data_size']         =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 28,  4));
904
										$atom_structure['sample_description_table'][$i]['video_frame_count']       =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32,  2));
905
										$atom_structure['sample_description_table'][$i]['video_encoder_name_len']  =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 34,  1));
906
										$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']);
907
										$atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 66,  2));
908
										$atom_structure['sample_description_table'][$i]['video_color_table_id']    =   getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 68,  2));
909
910
										$atom_structure['sample_description_table'][$i]['video_pixel_color_type']  = (($atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color');
911
										$atom_structure['sample_description_table'][$i]['video_pixel_color_name']  = $this->QuicktimeColorNameLookup($atom_structure['sample_description_table'][$i]['video_pixel_color_depth']);
912
913
										if ($atom_structure['sample_description_table'][$i]['video_pixel_color_name'] != 'invalid') {
914
											$info['quicktime']['video']['codec_fourcc']        = $atom_structure['sample_description_table'][$i]['data_format'];
915
											$info['quicktime']['video']['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($atom_structure['sample_description_table'][$i]['data_format']);
916
											$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']);
917
											$info['quicktime']['video']['color_depth']         = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'];
918
											$info['quicktime']['video']['color_depth_name']    = $atom_structure['sample_description_table'][$i]['video_pixel_color_name'];
919
920
											$info['video']['codec']           = $info['quicktime']['video']['codec'];
921
											$info['video']['bits_per_sample'] = $info['quicktime']['video']['color_depth'];
922
										}
923
										$info['video']['lossless']           = false;
924
										$info['video']['pixel_aspect_ratio'] = (float) 1;
925
										break;
926
								}
927
								break;
928
						}
929
						switch (strtolower($atom_structure['sample_description_table'][$i]['data_format'])) {
930
							case 'mp4a':
931
								$info['audio']['dataformat']         = 'mp4';
932
								$info['quicktime']['audio']['codec'] = 'mp4';
933
								break;
934
935
							case '3ivx':
936
							case '3iv1':
937
							case '3iv2':
938
								$info['video']['dataformat'] = '3ivx';
939
								break;
940
941
							case 'xvid':
942
								$info['video']['dataformat'] = 'xvid';
943
								break;
944
945
							case 'mp4v':
946
								$info['video']['dataformat'] = 'mpeg4';
947
								break;
948
949
							case 'divx':
950
							case 'div1':
951
							case 'div2':
952
							case 'div3':
953
							case 'div4':
954
							case 'div5':
955
							case 'div6':
956
								$info['video']['dataformat'] = 'divx';
957
								break;
958
959
							default:
960
								// do nothing
961
								break;
962
						}
963
						unset($atom_structure['sample_description_table'][$i]['data']);
964
					}
965
					break;
966
967
968
				case 'stts': // Sample Table Time-to-Sample atom
969
					$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
970
					$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
971
					$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
972
					$sttsEntriesDataOffset = 8;
973
					//$FrameRateCalculatorArray = array();
974
					$frames_count = 0;
975
976
					$max_stts_entries_to_scan = ($info['php_memory_limit'] ? min(floor($this->getid3->memory_limit / 10000), $atom_structure['number_entries']) : $atom_structure['number_entries']);
977
					if ($max_stts_entries_to_scan < $atom_structure['number_entries']) {
978
						$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).');
979
					}
980 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...
981
						$atom_structure['time_to_sample_table'][$i]['sample_count']    = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4));
982
						$sttsEntriesDataOffset += 4;
983
						$atom_structure['time_to_sample_table'][$i]['sample_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4));
984
						$sttsEntriesDataOffset += 4;
985
986
						$frames_count += $atom_structure['time_to_sample_table'][$i]['sample_count'];
987
988
						// THIS SECTION REPLACED WITH CODE IN "stbl" ATOM
989
						//if (!empty($info['quicktime']['time_scale']) && ($atom_structure['time_to_sample_table'][$i]['sample_duration'] > 0)) {
990
						//	$stts_new_framerate = $info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'];
991
						//	if ($stts_new_framerate <= 60) {
992
						//		// some atoms have durations of "1" giving a very large framerate, which probably is not right
993
						//		$info['video']['frame_rate'] = max($info['video']['frame_rate'], $stts_new_framerate);
994
						//	}
995
						//}
996
						//
997
						//$FrameRateCalculatorArray[($info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'])] += $atom_structure['time_to_sample_table'][$i]['sample_count'];
998
					}
999
					$info['quicktime']['stts_framecount'][] = $frames_count;
1000
					//$sttsFramesTotal  = 0;
1001
					//$sttsSecondsTotal = 0;
1002
					//foreach ($FrameRateCalculatorArray as $frames_per_second => $frame_count) {
1003
					//	if (($frames_per_second > 60) || ($frames_per_second < 1)) {
1004
					//		// not video FPS information, probably audio information
1005
					//		$sttsFramesTotal  = 0;
1006
					//		$sttsSecondsTotal = 0;
1007
					//		break;
1008
					//	}
1009
					//	$sttsFramesTotal  += $frame_count;
1010
					//	$sttsSecondsTotal += $frame_count / $frames_per_second;
1011
					//}
1012
					//if (($sttsFramesTotal > 0) && ($sttsSecondsTotal > 0)) {
1013
					//	if (($sttsFramesTotal / $sttsSecondsTotal) > $info['video']['frame_rate']) {
1014
					//		$info['video']['frame_rate'] = $sttsFramesTotal / $sttsSecondsTotal;
1015
					//	}
1016
					//}
1017
					break;
1018
1019
1020 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...
1021
					if ($ParseAllPossibleAtoms) {
1022
						$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1023
						$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1024
						$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1025
						$stssEntriesDataOffset = 8;
1026
						for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
1027
							$atom_structure['time_to_sample_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stssEntriesDataOffset, 4));
1028
							$stssEntriesDataOffset += 4;
1029
						}
1030
					}
1031
					break;
1032
1033
1034
				case 'stsc': // Sample Table Sample-to-Chunk atom
1035
					if ($ParseAllPossibleAtoms) {
1036
						$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1037
						$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1038
						$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1039
						$stscEntriesDataOffset = 8;
1040 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...
1041
							$atom_structure['sample_to_chunk_table'][$i]['first_chunk']        = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
1042
							$stscEntriesDataOffset += 4;
1043
							$atom_structure['sample_to_chunk_table'][$i]['samples_per_chunk']  = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
1044
							$stscEntriesDataOffset += 4;
1045
							$atom_structure['sample_to_chunk_table'][$i]['sample_description'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
1046
							$stscEntriesDataOffset += 4;
1047
						}
1048
					}
1049
					break;
1050
1051
1052
				case 'stsz': // Sample Table SiZe atom
1053
					if ($ParseAllPossibleAtoms) {
1054
						$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1055
						$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1056
						$atom_structure['sample_size']    = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1057
						$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  8, 4));
1058
						$stszEntriesDataOffset = 12;
1059
						if ($atom_structure['sample_size'] == 0) {
1060
							for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
1061
								$atom_structure['sample_size_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stszEntriesDataOffset, 4));
1062
								$stszEntriesDataOffset += 4;
1063
							}
1064
						}
1065
					}
1066
					break;
1067
1068
1069 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...
1070
//					if (true) {
1071
					if ($ParseAllPossibleAtoms) {
1072
						$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1073
						$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1074
						$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1075
						$stcoEntriesDataOffset = 8;
1076
						for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
1077
							$atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 4));
1078
							$stcoEntriesDataOffset += 4;
1079
						}
1080
					}
1081
					break;
1082
1083
1084 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...
1085
					if ($ParseAllPossibleAtoms) {
1086
						$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1087
						$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1088
						$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1089
						$stcoEntriesDataOffset = 8;
1090
						for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
1091
							$atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 8));
1092
							$stcoEntriesDataOffset += 8;
1093
						}
1094
					}
1095
					break;
1096
1097
1098
				case 'dref': // Data REFerence atom
1099
					$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1100
					$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1101
					$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1102
					$drefDataOffset = 8;
1103
					for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
1104
						$atom_structure['data_references'][$i]['size']                    = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 4));
1105
						$drefDataOffset += 4;
1106
						$atom_structure['data_references'][$i]['type']                    =                           substr($atom_data, $drefDataOffset, 4);
1107
						$drefDataOffset += 4;
1108
						$atom_structure['data_references'][$i]['version']                 = getid3_lib::BigEndian2Int(substr($atom_data,  $drefDataOffset, 1));
1109
						$drefDataOffset += 1;
1110
						$atom_structure['data_references'][$i]['flags_raw']               = getid3_lib::BigEndian2Int(substr($atom_data,  $drefDataOffset, 3)); // hardcoded: 0x0000
1111
						$drefDataOffset += 3;
1112
						$atom_structure['data_references'][$i]['data']                    =                           substr($atom_data, $drefDataOffset, ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3));
1113
						$drefDataOffset += ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3);
1114
1115
						$atom_structure['data_references'][$i]['flags']['self_reference'] = (bool) ($atom_structure['data_references'][$i]['flags_raw'] & 0x001);
1116
					}
1117
					break;
1118
1119
1120
				case 'gmin': // base Media INformation atom
1121
					$atom_structure['version']                = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1122
					$atom_structure['flags_raw']              = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1123
					$atom_structure['graphics_mode']          = getid3_lib::BigEndian2Int(substr($atom_data,  4, 2));
1124
					$atom_structure['opcolor_red']            = getid3_lib::BigEndian2Int(substr($atom_data,  6, 2));
1125
					$atom_structure['opcolor_green']          = getid3_lib::BigEndian2Int(substr($atom_data,  8, 2));
1126
					$atom_structure['opcolor_blue']           = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2));
1127
					$atom_structure['balance']                = getid3_lib::BigEndian2Int(substr($atom_data, 12, 2));
1128
					$atom_structure['reserved']               = getid3_lib::BigEndian2Int(substr($atom_data, 14, 2));
1129
					break;
1130
1131
1132 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...
1133
					$atom_structure['version']                = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1134
					$atom_structure['flags_raw']              = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1135
					$atom_structure['balance']                = getid3_lib::BigEndian2Int(substr($atom_data,  4, 2));
1136
					$atom_structure['reserved']               = getid3_lib::BigEndian2Int(substr($atom_data,  6, 2));
1137
					break;
1138
1139
1140
				case 'vmhd': // Video Media information HeaDer atom
1141
					$atom_structure['version']                = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1142
					$atom_structure['flags_raw']              = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3));
1143
					$atom_structure['graphics_mode']          = getid3_lib::BigEndian2Int(substr($atom_data,  4, 2));
1144
					$atom_structure['opcolor_red']            = getid3_lib::BigEndian2Int(substr($atom_data,  6, 2));
1145
					$atom_structure['opcolor_green']          = getid3_lib::BigEndian2Int(substr($atom_data,  8, 2));
1146
					$atom_structure['opcolor_blue']           = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2));
1147
1148
					$atom_structure['flags']['no_lean_ahead'] = (bool) ($atom_structure['flags_raw'] & 0x001);
1149
					break;
1150
1151
1152
				case 'hdlr': // HanDLeR reference atom
1153
					$atom_structure['version']                = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1154
					$atom_structure['flags_raw']              = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1155
					$atom_structure['component_type']         =                           substr($atom_data,  4, 4);
1156
					$atom_structure['component_subtype']      =                           substr($atom_data,  8, 4);
1157
					$atom_structure['component_manufacturer'] =                           substr($atom_data, 12, 4);
1158
					$atom_structure['component_flags_raw']    = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
1159
					$atom_structure['component_flags_mask']   = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));
1160
					$atom_structure['component_name']         = $this->MaybePascal2String(substr($atom_data, 24));
1161
1162
					if (($atom_structure['component_subtype'] == 'STpn') && ($atom_structure['component_manufacturer'] == 'zzzz')) {
1163
						$info['video']['dataformat'] = 'quicktimevr';
1164
					}
1165
					break;
1166
1167
1168
				case 'mdhd': // MeDia HeaDer atom
1169
					$atom_structure['version']               = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1170
					$atom_structure['flags_raw']             = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1171
					$atom_structure['creation_time']         = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1172
					$atom_structure['modify_time']           = getid3_lib::BigEndian2Int(substr($atom_data,  8, 4));
1173
					$atom_structure['time_scale']            = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
1174
					$atom_structure['duration']              = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
1175
					$atom_structure['language_id']           = getid3_lib::BigEndian2Int(substr($atom_data, 20, 2));
1176
					$atom_structure['quality']               = getid3_lib::BigEndian2Int(substr($atom_data, 22, 2));
1177
1178
					if ($atom_structure['time_scale'] == 0) {
1179
						$this->error('Corrupt Quicktime file: mdhd.time_scale == zero');
1180
						return false;
1181
					}
1182
					$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']);
1183
1184
					$atom_structure['creation_time_unix']    = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
1185
					$atom_structure['modify_time_unix']      = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
1186
					$atom_structure['playtime_seconds']      = $atom_structure['duration'] / $atom_structure['time_scale'];
1187
					$atom_structure['language']              = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
1188 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...
1189
						$info['comments']['language'][] = $atom_structure['language'];
1190
					}
1191
					$info['quicktime']['timestamps_unix']['create'][$atom_structure['hierarchy']] = $atom_structure['creation_time_unix'];
1192
					$info['quicktime']['timestamps_unix']['modify'][$atom_structure['hierarchy']] = $atom_structure['modify_time_unix'];
1193
					break;
1194
1195
1196
				case 'pnot': // Preview atom
1197
					$atom_structure['modification_date']      = getid3_lib::BigEndian2Int(substr($atom_data,  0, 4)); // "standard Macintosh format"
1198
					$atom_structure['version_number']         = getid3_lib::BigEndian2Int(substr($atom_data,  4, 2)); // hardcoded: 0x00
1199
					$atom_structure['atom_type']              =                           substr($atom_data,  6, 4);        // usually: 'PICT'
1200
					$atom_structure['atom_index']             = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2)); // usually: 0x01
1201
1202
					$atom_structure['modification_date_unix'] = getid3_lib::DateMac2Unix($atom_structure['modification_date']);
1203
					$info['quicktime']['timestamps_unix']['modify'][$atom_structure['hierarchy']] = $atom_structure['modification_date_unix'];
1204
					break;
1205
1206
1207 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...
1208
					$atom_structure['region_size']   = getid3_lib::BigEndian2Int(substr($atom_data,  0, 2)); // The Region size, Region boundary box,
1209
					$atom_structure['boundary_box']  = getid3_lib::BigEndian2Int(substr($atom_data,  2, 8)); // and Clipping region data fields
1210
					$atom_structure['clipping_data'] =                           substr($atom_data, 10);           // constitute a QuickDraw region.
1211
					break;
1212
1213
1214
				case 'load': // track LOAD settings atom
1215
					$atom_structure['preload_start_time'] = getid3_lib::BigEndian2Int(substr($atom_data,  0, 4));
1216
					$atom_structure['preload_duration']   = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1217
					$atom_structure['preload_flags_raw']  = getid3_lib::BigEndian2Int(substr($atom_data,  8, 4));
1218
					$atom_structure['default_hints_raw']  = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
1219
1220
					$atom_structure['default_hints']['double_buffer'] = (bool) ($atom_structure['default_hints_raw'] & 0x0020);
1221
					$atom_structure['default_hints']['high_quality']  = (bool) ($atom_structure['default_hints_raw'] & 0x0100);
1222
					break;
1223
1224
1225
				case 'tmcd': // TiMe CoDe atom
1226
				case 'chap': // CHAPter list atom
1227
				case 'sync': // SYNChronization atom
1228
				case 'scpt': // tranSCriPT atom
1229 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...
1230
					for ($i = 0; $i < strlen($atom_data); $i += 4) {
1231
						@$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...
1232
					}
1233
					break;
1234
1235
1236
				case 'elst': // Edit LiST atom
1237
					$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1238
					$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1239
					$atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1240
					for ($i = 0; $i < $atom_structure['number_entries']; $i++ ) {
1241
						$atom_structure['edit_list'][$i]['track_duration'] =   getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 0, 4));
1242
						$atom_structure['edit_list'][$i]['media_time']     =   getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 4, 4));
1243
						$atom_structure['edit_list'][$i]['media_rate']     = getid3_lib::FixedPoint16_16(substr($atom_data, 8 + ($i * 12) + 8, 4));
1244
					}
1245
					break;
1246
1247
1248 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...
1249
					$atom_structure['version']        = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1250
					$atom_structure['flags_raw']      = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3)); // hardcoded: 0x0000
1251
					$atom_structure['matte_data_raw'] =               substr($atom_data,  4);
1252
					break;
1253
1254
1255
				case 'ctab': // Color TABle atom
1256
					$atom_structure['color_table_seed']   = getid3_lib::BigEndian2Int(substr($atom_data,  0, 4)); // hardcoded: 0x00000000
1257
					$atom_structure['color_table_flags']  = getid3_lib::BigEndian2Int(substr($atom_data,  4, 2)); // hardcoded: 0x8000
1258
					$atom_structure['color_table_size']   = getid3_lib::BigEndian2Int(substr($atom_data,  6, 2)) + 1;
1259
					for ($colortableentry = 0; $colortableentry < $atom_structure['color_table_size']; $colortableentry++) {
1260
						$atom_structure['color_table'][$colortableentry]['alpha'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 0, 2));
1261
						$atom_structure['color_table'][$colortableentry]['red']   = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 2, 2));
1262
						$atom_structure['color_table'][$colortableentry]['green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 4, 2));
1263
						$atom_structure['color_table'][$colortableentry]['blue']  = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 6, 2));
1264
					}
1265
					break;
1266
1267
1268
				case 'mvhd': // MoVie HeaDer atom
1269
					$atom_structure['version']            =   getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1270
					$atom_structure['flags_raw']          =   getid3_lib::BigEndian2Int(substr($atom_data,  1, 3));
1271
					$atom_structure['creation_time']      =   getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1272
					$atom_structure['modify_time']        =   getid3_lib::BigEndian2Int(substr($atom_data,  8, 4));
1273
					$atom_structure['time_scale']         =   getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
1274
					$atom_structure['duration']           =   getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
1275
					$atom_structure['preferred_rate']     = getid3_lib::FixedPoint16_16(substr($atom_data, 20, 4));
1276
					$atom_structure['preferred_volume']   =   getid3_lib::FixedPoint8_8(substr($atom_data, 24, 2));
1277
					$atom_structure['reserved']           =                             substr($atom_data, 26, 10);
1278
					$atom_structure['matrix_a']           = getid3_lib::FixedPoint16_16(substr($atom_data, 36, 4));
1279
					$atom_structure['matrix_b']           = getid3_lib::FixedPoint16_16(substr($atom_data, 40, 4));
1280
					$atom_structure['matrix_u']           =  getid3_lib::FixedPoint2_30(substr($atom_data, 44, 4));
1281
					$atom_structure['matrix_c']           = getid3_lib::FixedPoint16_16(substr($atom_data, 48, 4));
1282
					$atom_structure['matrix_d']           = getid3_lib::FixedPoint16_16(substr($atom_data, 52, 4));
1283
					$atom_structure['matrix_v']           =  getid3_lib::FixedPoint2_30(substr($atom_data, 56, 4));
1284
					$atom_structure['matrix_x']           = getid3_lib::FixedPoint16_16(substr($atom_data, 60, 4));
1285
					$atom_structure['matrix_y']           = getid3_lib::FixedPoint16_16(substr($atom_data, 64, 4));
1286
					$atom_structure['matrix_w']           =  getid3_lib::FixedPoint2_30(substr($atom_data, 68, 4));
1287
					$atom_structure['preview_time']       =   getid3_lib::BigEndian2Int(substr($atom_data, 72, 4));
1288
					$atom_structure['preview_duration']   =   getid3_lib::BigEndian2Int(substr($atom_data, 76, 4));
1289
					$atom_structure['poster_time']        =   getid3_lib::BigEndian2Int(substr($atom_data, 80, 4));
1290
					$atom_structure['selection_time']     =   getid3_lib::BigEndian2Int(substr($atom_data, 84, 4));
1291
					$atom_structure['selection_duration'] =   getid3_lib::BigEndian2Int(substr($atom_data, 88, 4));
1292
					$atom_structure['current_time']       =   getid3_lib::BigEndian2Int(substr($atom_data, 92, 4));
1293
					$atom_structure['next_track_id']      =   getid3_lib::BigEndian2Int(substr($atom_data, 96, 4));
1294
1295
					if ($atom_structure['time_scale'] == 0) {
1296
						$this->error('Corrupt Quicktime file: mvhd.time_scale == zero');
1297
						return false;
1298
					}
1299
					$atom_structure['creation_time_unix']        = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
1300
					$atom_structure['modify_time_unix']          = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
1301
					$info['quicktime']['timestamps_unix']['create'][$atom_structure['hierarchy']] = $atom_structure['creation_time_unix'];
1302
					$info['quicktime']['timestamps_unix']['modify'][$atom_structure['hierarchy']] = $atom_structure['modify_time_unix'];
1303
					$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']);
1304
					$info['quicktime']['display_scale'] = $atom_structure['matrix_a'];
1305
					$info['playtime_seconds']           = $atom_structure['duration'] / $atom_structure['time_scale'];
1306
					break;
1307
1308
1309
				case 'tkhd': // TracK HeaDer atom
1310
					$atom_structure['version']             =   getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1311
					$atom_structure['flags_raw']           =   getid3_lib::BigEndian2Int(substr($atom_data,  1, 3));
1312
					$atom_structure['creation_time']       =   getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1313
					$atom_structure['modify_time']         =   getid3_lib::BigEndian2Int(substr($atom_data,  8, 4));
1314
					$atom_structure['trackid']             =   getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
1315
					$atom_structure['reserved1']           =   getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
1316
					$atom_structure['duration']            =   getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));
1317
					$atom_structure['reserved2']           =   getid3_lib::BigEndian2Int(substr($atom_data, 24, 8));
1318
					$atom_structure['layer']               =   getid3_lib::BigEndian2Int(substr($atom_data, 32, 2));
1319
					$atom_structure['alternate_group']     =   getid3_lib::BigEndian2Int(substr($atom_data, 34, 2));
1320
					$atom_structure['volume']              =   getid3_lib::FixedPoint8_8(substr($atom_data, 36, 2));
1321
					$atom_structure['reserved3']           =   getid3_lib::BigEndian2Int(substr($atom_data, 38, 2));
1322
					// http://developer.apple.com/library/mac/#documentation/QuickTime/RM/MovieBasics/MTEditing/K-Chapter/11MatrixFunctions.html
1323
					// http://developer.apple.com/library/mac/#documentation/QuickTime/qtff/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-18737
1324
					$atom_structure['matrix_a']            = getid3_lib::FixedPoint16_16(substr($atom_data, 40, 4));
1325
					$atom_structure['matrix_b']            = getid3_lib::FixedPoint16_16(substr($atom_data, 44, 4));
1326
					$atom_structure['matrix_u']            =  getid3_lib::FixedPoint2_30(substr($atom_data, 48, 4));
1327
					$atom_structure['matrix_c']            = getid3_lib::FixedPoint16_16(substr($atom_data, 52, 4));
1328
					$atom_structure['matrix_d']            = getid3_lib::FixedPoint16_16(substr($atom_data, 56, 4));
1329
					$atom_structure['matrix_v']            =  getid3_lib::FixedPoint2_30(substr($atom_data, 60, 4));
1330
					$atom_structure['matrix_x']            = getid3_lib::FixedPoint16_16(substr($atom_data, 64, 4));
1331
					$atom_structure['matrix_y']            = getid3_lib::FixedPoint16_16(substr($atom_data, 68, 4));
1332
					$atom_structure['matrix_w']            =  getid3_lib::FixedPoint2_30(substr($atom_data, 72, 4));
1333
					$atom_structure['width']               = getid3_lib::FixedPoint16_16(substr($atom_data, 76, 4));
1334
					$atom_structure['height']              = getid3_lib::FixedPoint16_16(substr($atom_data, 80, 4));
1335
					$atom_structure['flags']['enabled']    = (bool) ($atom_structure['flags_raw'] & 0x0001);
1336
					$atom_structure['flags']['in_movie']   = (bool) ($atom_structure['flags_raw'] & 0x0002);
1337
					$atom_structure['flags']['in_preview'] = (bool) ($atom_structure['flags_raw'] & 0x0004);
1338
					$atom_structure['flags']['in_poster']  = (bool) ($atom_structure['flags_raw'] & 0x0008);
1339
					$atom_structure['creation_time_unix']  = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
1340
					$atom_structure['modify_time_unix']    = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
1341
					$info['quicktime']['timestamps_unix']['create'][$atom_structure['hierarchy']] = $atom_structure['creation_time_unix'];
1342
					$info['quicktime']['timestamps_unix']['modify'][$atom_structure['hierarchy']] = $atom_structure['modify_time_unix'];
1343
1344
					// https://www.getid3.org/phpBB3/viewtopic.php?t=1908
1345
					// attempt to compute rotation from matrix values
1346
					// 2017-Dec-28: uncertain if 90/270 are correctly oriented; values returned by FixedPoint16_16 should perhaps be -1 instead of 65535(?)
1347
					$matrixRotation = 0;
1348
					switch ($atom_structure['matrix_a'].':'.$atom_structure['matrix_b'].':'.$atom_structure['matrix_c'].':'.$atom_structure['matrix_d']) {
1349
						case '1:0:0:1':         $matrixRotation =   0; break;
1350
						case '0:1:65535:0':     $matrixRotation =  90; break;
1351
						case '65535:0:0:65535': $matrixRotation = 180; break;
1352
						case '0:65535:1:0':     $matrixRotation = 270; break;
1353
						default: break;
1354
					}
1355
1356
					// https://www.getid3.org/phpBB3/viewtopic.php?t=2468
1357
					// The rotation matrix can appear in the Quicktime file multiple times, at least once for each track,
1358
					// and it's possible that only the video track (or, in theory, one of the video tracks) is flagged as
1359
					// rotated while the other tracks (e.g. audio) is tagged as rotation=0 (behavior noted on iPhone 8 Plus)
1360
					// The correct solution would be to check if the TrackID associated with the rotation matrix is indeed
1361
					// a video track (or the main video track) and only set the rotation then, but since information about
1362
					// what track is what is not trivially there to be examined, the lazy solution is to set the rotation
1363
					// if it is found to be nonzero, on the assumption that tracks that don't need it will have rotation set
1364
					// to zero (and be effectively ignored) and the video track will have rotation set correctly, which will
1365
					// either be zero and automatically correct, or nonzero and be set correctly.
1366
					if (!isset($info['video']['rotate']) || (($info['video']['rotate'] == 0) && ($matrixRotation > 0))) {
1367
						$info['quicktime']['video']['rotate'] = $info['video']['rotate'] = $matrixRotation;
1368
					}
1369
1370
					if ($atom_structure['flags']['enabled'] == 1) {
1371
						if (!isset($info['video']['resolution_x']) || !isset($info['video']['resolution_y'])) {
1372
							$info['video']['resolution_x'] = $atom_structure['width'];
1373
							$info['video']['resolution_y'] = $atom_structure['height'];
1374
						}
1375
						$info['video']['resolution_x'] = max($info['video']['resolution_x'], $atom_structure['width']);
1376
						$info['video']['resolution_y'] = max($info['video']['resolution_y'], $atom_structure['height']);
1377
						$info['quicktime']['video']['resolution_x'] = $info['video']['resolution_x'];
1378
						$info['quicktime']['video']['resolution_y'] = $info['video']['resolution_y'];
1379
					} else {
1380
						// see: https://www.getid3.org/phpBB3/viewtopic.php?t=1295
1381
						//if (isset($info['video']['resolution_x'])) { unset($info['video']['resolution_x']); }
1382
						//if (isset($info['video']['resolution_y'])) { unset($info['video']['resolution_y']); }
1383
						//if (isset($info['quicktime']['video']))    { unset($info['quicktime']['video']);    }
1384
					}
1385
					break;
1386
1387
1388
				case 'iods': // Initial Object DeScriptor atom
1389
					// http://www.koders.com/c/fid1FAB3E762903DC482D8A246D4A4BF9F28E049594.aspx?s=windows.h
1390
					// http://libquicktime.sourcearchive.com/documentation/1.0.2plus-pdebian/iods_8c-source.html
1391
					$offset = 0;
1392
					$atom_structure['version']                =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1393
					$offset += 1;
1394
					$atom_structure['flags_raw']              =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 3));
1395
					$offset += 3;
1396
					$atom_structure['mp4_iod_tag']            =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1397
					$offset += 1;
1398
					$atom_structure['length']                 = $this->quicktime_read_mp4_descr_length($atom_data, $offset);
1399
					//$offset already adjusted by quicktime_read_mp4_descr_length()
1400
					$atom_structure['object_descriptor_id']   =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2));
1401
					$offset += 2;
1402
					$atom_structure['od_profile_level']       =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1403
					$offset += 1;
1404
					$atom_structure['scene_profile_level']    =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1405
					$offset += 1;
1406
					$atom_structure['audio_profile_id']       =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1407
					$offset += 1;
1408
					$atom_structure['video_profile_id']       =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1409
					$offset += 1;
1410
					$atom_structure['graphics_profile_level'] =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1411
					$offset += 1;
1412
1413
					$atom_structure['num_iods_tracks'] = ($atom_structure['length'] - 7) / 6; // 6 bytes would only be right if all tracks use 1-byte length fields
1414 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...
1415
						$atom_structure['track'][$i]['ES_ID_IncTag'] =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
1416
						$offset += 1;
1417
						$atom_structure['track'][$i]['length']       = $this->quicktime_read_mp4_descr_length($atom_data, $offset);
1418
						//$offset already adjusted by quicktime_read_mp4_descr_length()
1419
						$atom_structure['track'][$i]['track_id']     =       getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4));
1420
						$offset += 4;
1421
					}
1422
1423
					$atom_structure['audio_profile_name'] = $this->QuicktimeIODSaudioProfileName($atom_structure['audio_profile_id']);
1424
					$atom_structure['video_profile_name'] = $this->QuicktimeIODSvideoProfileName($atom_structure['video_profile_id']);
1425
					break;
1426
1427 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...
1428
					$atom_structure['signature'] =                           substr($atom_data,  0, 4);
1429
					$atom_structure['unknown_1'] = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1430
					$atom_structure['fourcc']    =                           substr($atom_data,  8, 4);
1431
					break;
1432
1433
				case 'mdat': // Media DATa atom
1434
					// 'mdat' contains the actual data for the audio/video, possibly also subtitles
1435
1436
	/* 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] */
1437
1438
					// first, skip any 'wide' padding, and second 'mdat' header (with specified size of zero?)
1439
					$mdat_offset = 0;
1440
					while (true) {
1441
						if (substr($atom_data, $mdat_offset, 8) == "\x00\x00\x00\x08".'wide') {
1442
							$mdat_offset += 8;
1443
						} elseif (substr($atom_data, $mdat_offset, 8) == "\x00\x00\x00\x00".'mdat') {
1444
							$mdat_offset += 8;
1445
						} else {
1446
							break;
1447
						}
1448
					}
1449
					if (substr($atom_data, $mdat_offset, 4) == 'GPRO') {
1450
						$GOPRO_chunk_length = getid3_lib::LittleEndian2Int(substr($atom_data, $mdat_offset + 4, 4));
1451
						$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...
1452
						$atom_structure['GPRO']['raw'] = substr($atom_data, $mdat_offset + 8, $GOPRO_chunk_length - 8);
1453
						$atom_structure['GPRO']['firmware'] = substr($atom_structure['GPRO']['raw'],  0, 15);
1454
						$atom_structure['GPRO']['unknown1'] = substr($atom_structure['GPRO']['raw'], 15, 16);
1455
						$atom_structure['GPRO']['unknown2'] = substr($atom_structure['GPRO']['raw'], 31, 32);
1456
						$atom_structure['GPRO']['unknown3'] = substr($atom_structure['GPRO']['raw'], 63, 16);
1457
						$atom_structure['GPRO']['camera']   = substr($atom_structure['GPRO']['raw'], 79, 32);
1458
						$info['quicktime']['camera']['model'] = rtrim($atom_structure['GPRO']['camera'], "\x00");
1459
					}
1460
1461
					// check to see if it looks like chapter titles, in the form of unterminated strings with a leading 16-bit size field
1462
					while (($mdat_offset < (strlen($atom_data) - 8))
1463
						&& ($chapter_string_length = getid3_lib::BigEndian2Int(substr($atom_data, $mdat_offset, 2)))
1464
						&& ($chapter_string_length < 1000)
1465
						&& ($chapter_string_length <= (strlen($atom_data) - $mdat_offset - 2))
1466
						&& preg_match('#^([\x00-\xFF]{2})([\x20-\xFF]+)$#', substr($atom_data, $mdat_offset, $chapter_string_length + 2), $chapter_matches)) {
1467
							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...
1468
							$mdat_offset += (2 + $chapter_string_length);
1469
							@$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...
1470
1471
							// "encd" atom specifies encoding. In theory could be anything, almost always UTF-8, but may be UTF-16 with BOM (not currently handled)
1472
							if (substr($atom_data, $mdat_offset, 12) == "\x00\x00\x00\x0C\x65\x6E\x63\x64\x00\x00\x01\x00") { // UTF-8
1473
								$mdat_offset += 12;
1474
							}
1475
					}
1476
1477
					if (($atomsize > 8) && (!isset($info['avdataend_tmp']) || ($info['quicktime'][$atomname]['size'] > ($info['avdataend_tmp'] - $info['avdataoffset'])))) {
1478
1479
						$info['avdataoffset'] = $atom_structure['offset'] + 8;                       // $info['quicktime'][$atomname]['offset'] + 8;
1480
						$OldAVDataEnd         = $info['avdataend'];
1481
						$info['avdataend']    = $atom_structure['offset'] + $atom_structure['size']; // $info['quicktime'][$atomname]['offset'] + $info['quicktime'][$atomname]['size'];
1482
1483
						$getid3_temp = new getID3();
1484
						$getid3_temp->openfile($this->getid3->filename, $this->getid3->info['filesize'], $this->getid3->fp);
1485
						$getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
1486
						$getid3_temp->info['avdataend']    = $info['avdataend'];
1487
						$getid3_mp3 = new getid3_mp3($getid3_temp);
1488
						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...
1489
							$getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false);
1490
							if (!empty($getid3_temp->info['warning'])) {
1491
								foreach ($getid3_temp->info['warning'] as $value) {
1492
									$this->warning($value);
1493
								}
1494
							}
1495
							if (!empty($getid3_temp->info['mpeg'])) {
1496
								$info['mpeg'] = $getid3_temp->info['mpeg'];
1497
								if (isset($info['mpeg']['audio'])) {
1498
									$info['audio']['dataformat']   = 'mp3';
1499
									$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')));
1500
									$info['audio']['sample_rate']  = $info['mpeg']['audio']['sample_rate'];
1501
									$info['audio']['channels']     = $info['mpeg']['audio']['channels'];
1502
									$info['audio']['bitrate']      = $info['mpeg']['audio']['bitrate'];
1503
									$info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
1504
									$info['bitrate']               = $info['audio']['bitrate'];
1505
								}
1506
							}
1507
						}
1508
						unset($getid3_mp3, $getid3_temp);
1509
						$info['avdataend'] = $OldAVDataEnd;
1510
						unset($OldAVDataEnd);
1511
1512
					}
1513
1514
					unset($mdat_offset, $chapter_string_length, $chapter_matches);
1515
					break;
1516
1517
				case 'free': // FREE space atom
1518
				case 'skip': // SKIP atom
1519
				case 'wide': // 64-bit expansion placeholder atom
1520
					// 'free', 'skip' and 'wide' are just padding, contains no useful data at all
1521
1522
					// When writing QuickTime files, it is sometimes necessary to update an atom's size.
1523
					// It is impossible to update a 32-bit atom to a 64-bit atom since the 32-bit atom
1524
					// is only 8 bytes in size, and the 64-bit atom requires 16 bytes. Therefore, QuickTime
1525
					// puts an 8-byte placeholder atom before any atoms it may have to update the size of.
1526
					// In this way, if the atom needs to be converted from a 32-bit to a 64-bit atom, the
1527
					// placeholder atom can be overwritten to obtain the necessary 8 extra bytes.
1528
					// The placeholder atom has a type of kWideAtomPlaceholderType ( 'wide' ).
1529
					break;
1530
1531
1532
				case 'nsav': // NoSAVe atom
1533
					// http://developer.apple.com/technotes/tn/tn2038.html
1534
					$atom_structure['data'] = getid3_lib::BigEndian2Int(substr($atom_data,  0, 4));
1535
					break;
1536
1537
				case 'ctyp': // Controller TYPe atom (seen on QTVR)
1538
					// http://homepages.slingshot.co.nz/~helmboy/quicktime/formats/qtm-layout.txt
1539
					// some controller names are:
1540
					//   0x00 + 'std' for linear movie
1541
					//   'none' for no controls
1542
					$atom_structure['ctyp'] = substr($atom_data, 0, 4);
1543
					$info['quicktime']['controller'] = $atom_structure['ctyp'];
1544
					switch ($atom_structure['ctyp']) {
1545
						case 'qtvr':
1546
							$info['video']['dataformat'] = 'quicktimevr';
1547
							break;
1548
					}
1549
					break;
1550
1551
				case 'pano': // PANOrama track (seen on QTVR)
1552
					$atom_structure['pano'] = getid3_lib::BigEndian2Int(substr($atom_data,  0, 4));
1553
					break;
1554
1555
				case 'hint': // HINT track
1556
				case 'hinf': //
1557
				case 'hinv': //
1558
				case 'hnti': //
1559
					$info['quicktime']['hinting'] = true;
1560
					break;
1561
1562
				case 'imgt': // IMaGe Track reference (kQTVRImageTrackRefType) (seen on QTVR)
1563
					for ($i = 0; $i < ($atom_structure['size'] - 8); $i += 4) {
1564
						$atom_structure['imgt'][] = getid3_lib::BigEndian2Int(substr($atom_data, $i, 4));
1565
					}
1566
					break;
1567
1568
1569
				// Observed-but-not-handled atom types are just listed here to prevent warnings being generated
1570
				case 'FXTC': // Something to do with Adobe After Effects (?)
1571
				case 'PrmA':
1572
				case 'code':
1573
				case 'FIEL': // this is NOT "fiel" (Field Ordering) as describe here: http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap3/chapter_4_section_2.html
1574
				case 'tapt': // TrackApertureModeDimensionsAID - http://developer.apple.com/documentation/QuickTime/Reference/QT7-1_Update_Reference/Constants/Constants.html
1575
							// tapt seems to be used to compute the video size [https://www.getid3.org/phpBB3/viewtopic.php?t=838]
1576
							// * http://lists.apple.com/archives/quicktime-api/2006/Aug/msg00014.html
1577
							// * http://handbrake.fr/irclogs/handbrake-dev/handbrake-dev20080128_pg2.html
1578
				case 'ctts'://  STCompositionOffsetAID             - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
1579
				case 'cslg'://  STCompositionShiftLeastGreatestAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
1580
				case 'sdtp'://  STSampleDependencyAID              - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
1581
				case 'stps'://  STPartialSyncSampleAID             - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
1582
					//$atom_structure['data'] = $atom_data;
1583
					break;
1584
1585
				case "\xA9".'xyz':  // GPS latitude+longitude+altitude
1586
					$atom_structure['data'] = $atom_data;
1587
					if (preg_match('#([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)?/$#i', $atom_data, $matches)) {
1588
						@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...
1589
						$info['quicktime']['comments']['gps_latitude'][]  = floatval($latitude);
1590
						$info['quicktime']['comments']['gps_longitude'][] = floatval($longitude);
1591
						if (!empty($altitude)) {
1592
							$info['quicktime']['comments']['gps_altitude'][] = floatval($altitude);
1593
						}
1594
					} else {
1595
						$this->warning('QuickTime atom "©xyz" data does not match expected data pattern at offset '.$baseoffset.'. Please report as getID3() bug.');
1596
					}
1597
					break;
1598
1599
				case 'NCDT':
1600
					// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
1601
					// Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
1602
					$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms);
1603
					break;
1604
				case 'NCTH': // Nikon Camera THumbnail image
1605
				case 'NCVW': // Nikon Camera preVieW image
1606
					// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
1607
					if (preg_match('/^\xFF\xD8\xFF/', $atom_data)) {
1608
						$atom_structure['data'] = $atom_data;
1609
						$atom_structure['image_mime'] = 'image/jpeg';
1610
						$atom_structure['description'] = (($atomname == 'NCTH') ? 'Nikon Camera Thumbnail Image' : (($atomname == 'NCVW') ? 'Nikon Camera Preview Image' : 'Nikon preview image'));
1611
						$info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_data, 'description'=>$atom_structure['description']);
1612
					}
1613
					break;
1614
				case 'NCTG': // Nikon - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
1615
					$atom_structure['data'] = $this->QuicktimeParseNikonNCTG($atom_data);
1616
					break;
1617
				case 'NCHD': // Nikon:MakerNoteVersion  - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
1618
				case 'NCDB': // Nikon                   - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
1619
				case 'CNCV': // Canon:CompressorVersion - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Canon.html
1620
					$atom_structure['data'] = $atom_data;
1621
					break;
1622
1623 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...
1624
					// some kind of metacontainer, may contain a big data dump such as:
1625
					// 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
1626
					// http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt
1627
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['subatoms']  = $this->QuicktimeParseContainerAtom(substr($atom_data, 4), $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
1631
					//$atom_structure['subatoms']  = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
1632
					break;
1633
1634 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...
1635
					// https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/Metadata/Metadata.html
1636
1637
					$atom_structure['version']   =          getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
1638
					$atom_structure['flags_raw'] =          getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
1639
					$atom_structure['subatoms']  = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
1640
					break;
1641
1642
				case 'data': // metaDATA atom
1643
					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
1644
					// seems to be 2 bytes language code (ASCII), 2 bytes unknown (set to 0x10B5 in sample I have), remainder is useful data
1645
					$atom_structure['language'] =                           substr($atom_data, 4 + 0, 2);
1646
					$atom_structure['unknown']  = getid3_lib::BigEndian2Int(substr($atom_data, 4 + 2, 2));
1647
					$atom_structure['data']     =                           substr($atom_data, 4 + 4);
1648
					$atom_structure['key_name'] = @$info['quicktime']['temp_meta_key_names'][$metaDATAkey++];
1649
1650
					if ($atom_structure['key_name'] && $atom_structure['data']) {
1651
						@$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...
1652
					}
1653
					break;
1654
1655
				case 'keys': // KEYS that may be present in the metadata atom.
1656
					// https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW21
1657
					// The metadata item keys atom holds a list of the metadata keys that may be present in the metadata atom.
1658
					// 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".
1659
					$atom_structure['version']       = getid3_lib::BigEndian2Int(substr($atom_data,  0, 1));
1660
					$atom_structure['flags_raw']     = getid3_lib::BigEndian2Int(substr($atom_data,  1, 3));
1661
					$atom_structure['entry_count']   = getid3_lib::BigEndian2Int(substr($atom_data,  4, 4));
1662
					$keys_atom_offset = 8;
1663
					for ($i = 1; $i <= $atom_structure['entry_count']; $i++) {
1664
						$atom_structure['keys'][$i]['key_size']      = getid3_lib::BigEndian2Int(substr($atom_data, $keys_atom_offset + 0, 4));
1665
						$atom_structure['keys'][$i]['key_namespace'] =                           substr($atom_data, $keys_atom_offset + 4, 4);
1666
						$atom_structure['keys'][$i]['key_value']     =                           substr($atom_data, $keys_atom_offset + 8, $atom_structure['keys'][$i]['key_size'] - 8);
1667
						$keys_atom_offset += $atom_structure['keys'][$i]['key_size']; // key_size includes the 4+4 bytes for key_size and key_namespace
1668
1669
						$info['quicktime']['temp_meta_key_names'][$i] = $atom_structure['keys'][$i]['key_value'];
1670
					}
1671
					break;
1672
1673
				case 'uuid': // user-defined atom often seen containing XML data, also used for potentially many other purposes, only a few specifically handled by getID3 (e.g. 360fly spatial data)
1674
					//Get the UUID ID in first 16 bytes
1675
					$uuid_bytes_read = unpack('H8time_low/H4time_mid/H4time_hi/H4clock_seq_hi/H12clock_seq_low', substr($atom_data, 0, 16));
1676
					$atom_structure['uuid_field_id'] = implode('-', $uuid_bytes_read);
1677
1678
					switch ($atom_structure['uuid_field_id']) {   // http://fileformats.archiveteam.org/wiki/Boxes/atoms_format#UUID_boxes
1679
1680
						case '0537cdab-9d0c-4431-a72a-fa561f2a113e': // Exif                                       - http://fileformats.archiveteam.org/wiki/Exif
1681
						case '2c4c0100-8504-40b9-a03e-562148d6dfeb': // Photoshop Image Resources                  - http://fileformats.archiveteam.org/wiki/Photoshop_Image_Resources
1682
						case '33c7a4d2-b81d-4723-a0ba-f1a3e097ad38': // IPTC-IIM                                   - http://fileformats.archiveteam.org/wiki/IPTC-IIM
1683
						case '8974dbce-7be7-4c51-84f9-7148f9882554': // PIFF Track Encryption Box                  - http://fileformats.archiveteam.org/wiki/Protected_Interoperable_File_Format
1684
						case '96a9f1f1-dc98-402d-a7ae-d68e34451809': // GeoJP2 World File Box                      - http://fileformats.archiveteam.org/wiki/GeoJP2
1685
						case 'a2394f52-5a9b-4f14-a244-6c427c648df4': // PIFF Sample Encryption Box                 - http://fileformats.archiveteam.org/wiki/Protected_Interoperable_File_Format
1686
						case 'b14bf8bd-083d-4b43-a5ae-8cd7d5a6ce03': // GeoJP2 GeoTIFF Box                         - http://fileformats.archiveteam.org/wiki/GeoJP2
1687 View Code Duplication
						case 'd08a4f18-10f3-4a82-b6c8-32d8aba183d3': // PIFF Protection System Specific Header Box - http://fileformats.archiveteam.org/wiki/Protected_Interoperable_File_Format
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...
1688
							$this->warning('Unhandled (but recognized) "uuid" atom identified by "'.$atom_structure['uuid_field_id'].'" at offset '.$atom_structure['offset'].' ('.strlen($atom_data).' bytes)');
1689
							break;
1690
1691
						case 'be7acfcb-97a9-42e8-9c71-999491e3afac': // XMP data (in XML format)
1692
							$atom_structure['xml'] = substr($atom_data, 16, strlen($atom_data) - 16 - 8); // 16 bytes for UUID, 8 bytes header(?)
1693
							break;
1694
1695
						case 'efe1589a-bb77-49ef-8095-27759eb1dc6f': // 360fly data
1696
							/* 360fly code in this block by Paul Lewis 2019-Oct-31 */
1697
							/*	Sensor Timestamps need to be calculated using the recordings base time at ['quicktime']['moov']['subatoms'][0]['creation_time_unix']. */
1698
							$atom_structure['title'] = '360Fly Sensor Data';
1699
1700
							//Get the UUID HEADER data
1701
							$uuid_bytes_read = unpack('vheader_size/vheader_version/vtimescale/vhardware_version/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/', substr($atom_data, 16, 32));
1702
							$atom_structure['uuid_header'] = $uuid_bytes_read;
1703
1704
							$start_byte = 48;
1705
							$atom_SENSOR_data = substr($atom_data, $start_byte);
1706
							$atom_structure['sensor_data']['data_type'] = array(
1707
									'fusion_count'   => 0,       // ID 250
1708
									'fusion_data'    => array(),
1709
									'accel_count'    => 0,       // ID 1
1710
									'accel_data'     => array(),
1711
									'gyro_count'     => 0,       // ID 2
1712
									'gyro_data'      => array(),
1713
									'magno_count'    => 0,       // ID 3
1714
									'magno_data'     => array(),
1715
									'gps_count'      => 0,       // ID 5
1716
									'gps_data'       => array(),
1717
									'rotation_count' => 0,       // ID 6
1718
									'rotation_data'  => array(),
1719
									'unknown_count'  => 0,       // ID ??
1720
									'unknown_data'   => array(),
1721
									'debug_list'     => '',      // Used to debug variables stored as comma delimited strings
1722
							);
1723
							$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...
1724
							// Can start loop here to decode all sensor data in 32 Byte chunks:
1725
							foreach (str_split($atom_SENSOR_data, 32) as $sensor_key => $sensor_data) {
1726
								// This gets me a data_type code to work out what data is in the next 31 bytes.
1727
								$sensor_data_type = substr($sensor_data, 0, 1);
1728
								$sensor_data_content = substr($sensor_data, 1);
1729
								$uuid_bytes_read = unpack('C*', $sensor_data_type);
1730
								$sensor_data_array = array();
1731
								switch ($uuid_bytes_read[1]) {
1732 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...
1733
										$atom_structure['sensor_data']['data_type']['fusion_count']++;
1734
										$uuid_bytes_read = unpack('cmode/Jtimestamp/Gyaw/Gpitch/Groll/x*', $sensor_data_content);
1735
										$sensor_data_array['mode']      = $uuid_bytes_read['mode'];
1736
										$sensor_data_array['timestamp'] = $uuid_bytes_read['timestamp'];
1737
										$sensor_data_array['yaw']       = $uuid_bytes_read['yaw'];
1738
										$sensor_data_array['pitch']     = $uuid_bytes_read['pitch'];
1739
										$sensor_data_array['roll']      = $uuid_bytes_read['roll'];
1740
										array_push($atom_structure['sensor_data']['data_type']['fusion_data'], $sensor_data_array);
1741
										break;
1742 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...
1743
										$atom_structure['sensor_data']['data_type']['accel_count']++;
1744
										$uuid_bytes_read = unpack('cmode/Jtimestamp/Gyaw/Gpitch/Groll/x*', $sensor_data_content);
1745
										$sensor_data_array['mode']      = $uuid_bytes_read['mode'];
1746
										$sensor_data_array['timestamp'] = $uuid_bytes_read['timestamp'];
1747
										$sensor_data_array['yaw']       = $uuid_bytes_read['yaw'];
1748
										$sensor_data_array['pitch']     = $uuid_bytes_read['pitch'];
1749
										$sensor_data_array['roll']      = $uuid_bytes_read['roll'];
1750
										array_push($atom_structure['sensor_data']['data_type']['accel_data'], $sensor_data_array);
1751
										break;
1752 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...
1753
										$atom_structure['sensor_data']['data_type']['gyro_count']++;
1754
										$uuid_bytes_read = unpack('cmode/Jtimestamp/Gyaw/Gpitch/Groll/x*', $sensor_data_content);
1755
										$sensor_data_array['mode']      = $uuid_bytes_read['mode'];
1756
										$sensor_data_array['timestamp'] = $uuid_bytes_read['timestamp'];
1757
										$sensor_data_array['yaw']       = $uuid_bytes_read['yaw'];
1758
										$sensor_data_array['pitch']     = $uuid_bytes_read['pitch'];
1759
										$sensor_data_array['roll']      = $uuid_bytes_read['roll'];
1760
										array_push($atom_structure['sensor_data']['data_type']['gyro_data'], $sensor_data_array);
1761
										break;
1762 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...
1763
										$atom_structure['sensor_data']['data_type']['magno_count']++;
1764
										$uuid_bytes_read = unpack('cmode/Jtimestamp/Gmagx/Gmagy/Gmagz/x*', $sensor_data_content);
1765
										$sensor_data_array['mode']      = $uuid_bytes_read['mode'];
1766
										$sensor_data_array['timestamp'] = $uuid_bytes_read['timestamp'];
1767
										$sensor_data_array['magx']      = $uuid_bytes_read['magx'];
1768
										$sensor_data_array['magy']      = $uuid_bytes_read['magy'];
1769
										$sensor_data_array['magz']      = $uuid_bytes_read['magz'];
1770
										array_push($atom_structure['sensor_data']['data_type']['magno_data'], $sensor_data_array);
1771
										break;
1772
									case 5:
1773
										$atom_structure['sensor_data']['data_type']['gps_count']++;
1774
										$uuid_bytes_read = unpack('cmode/Jtimestamp/Glat/Glon/Galt/Gspeed/nbearing/nacc/x*', $sensor_data_content);
1775
										$sensor_data_array['mode']      = $uuid_bytes_read['mode'];
1776
										$sensor_data_array['timestamp'] = $uuid_bytes_read['timestamp'];
1777
										$sensor_data_array['lat']       = $uuid_bytes_read['lat'];
1778
										$sensor_data_array['lon']       = $uuid_bytes_read['lon'];
1779
										$sensor_data_array['alt']       = $uuid_bytes_read['alt'];
1780
										$sensor_data_array['speed']     = $uuid_bytes_read['speed'];
1781
										$sensor_data_array['bearing']   = $uuid_bytes_read['bearing'];
1782
										$sensor_data_array['acc']       = $uuid_bytes_read['acc'];
1783
										array_push($atom_structure['sensor_data']['data_type']['gps_data'], $sensor_data_array);
1784
										//array_push($debug_structure['debug_items'], $uuid_bytes_read['timestamp']);
1785
										break;
1786 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...
1787
										$atom_structure['sensor_data']['data_type']['rotation_count']++;
1788
										$uuid_bytes_read = unpack('cmode/Jtimestamp/Grotx/Groty/Grotz/x*', $sensor_data_content);
1789
										$sensor_data_array['mode']      = $uuid_bytes_read['mode'];
1790
										$sensor_data_array['timestamp'] = $uuid_bytes_read['timestamp'];
1791
										$sensor_data_array['rotx']      = $uuid_bytes_read['rotx'];
1792
										$sensor_data_array['roty']      = $uuid_bytes_read['roty'];
1793
										$sensor_data_array['rotz']      = $uuid_bytes_read['rotz'];
1794
										array_push($atom_structure['sensor_data']['data_type']['rotation_data'], $sensor_data_array);
1795
										break;
1796
									default:
1797
										$atom_structure['sensor_data']['data_type']['unknown_count']++;
1798
										break;
1799
								}
1800
							}
1801
							//if (isset($debug_structure['debug_items']) && count($debug_structure['debug_items']) > 0) {
1802
							//	$atom_structure['sensor_data']['data_type']['debug_list'] = implode(',', $debug_structure['debug_items']);
1803
							//} else {
1804
								$atom_structure['sensor_data']['data_type']['debug_list'] = 'No debug items in list!';
1805
							//}
1806
							break;
1807
1808 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...
1809
							$this->warning('Unhandled "uuid" atom identified by "'.$atom_structure['uuid_field_id'].'" at offset '.$atom_structure['offset'].' ('.strlen($atom_data).' bytes)');
1810
					}
1811
					break;
1812
1813
				case 'gps ':
1814
					// https://dashcamtalk.com/forum/threads/script-to-extract-gps-data-from-novatek-mp4.20808/page-2#post-291730
1815
					// The 'gps ' contains simple look up table made up of 8byte rows, that point to the 'free' atoms that contains the actual GPS data.
1816
					// The first row is version/metadata/notsure, I skip that.
1817
					// The following rows consist of 4byte address (absolute) and 4byte size (0x1000), these point to the GPS data in the file.
1818
1819
					$GPS_rowsize = 8; // 4 bytes for offset, 4 bytes for size
1820
					if (strlen($atom_data) > 0) {
1821
						if ((strlen($atom_data) % $GPS_rowsize) == 0) {
1822
							$atom_structure['gps_toc'] = array();
1823
							foreach (str_split($atom_data, $GPS_rowsize) as $counter => $datapair) {
1824
								$atom_structure['gps_toc'][] = unpack('Noffset/Nsize', substr($atom_data, $counter * $GPS_rowsize, $GPS_rowsize));
1825
							}
1826
1827
							$atom_structure['gps_entries'] = array();
1828
							$previous_offset = $this->ftell();
1829
							foreach ($atom_structure['gps_toc'] as $key => $gps_pointer) {
1830
								if ($key == 0) {
1831
									// "The first row is version/metadata/notsure, I skip that."
1832
									continue;
1833
								}
1834
								$this->fseek($gps_pointer['offset']);
1835
								$GPS_free_data = $this->fread($gps_pointer['size']);
1836
1837
								/*
1838
								// 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
1839
1840
								// https://dashcamtalk.com/forum/threads/script-to-extract-gps-data-from-novatek-mp4.20808/page-2#post-291730
1841
								// The structure of the GPS data atom (the 'free' atoms mentioned above) is following:
1842
								// hour,minute,second,year,month,day,active,latitude_b,longitude_b,unknown2,latitude,longitude,speed = struct.unpack_from('<IIIIIIssssfff',data, 48)
1843
								// For those unfamiliar with python struct:
1844
								// I = int
1845
								// s = is string (size 1, in this case)
1846
								// f = float
1847
1848
								//$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));
1849
								*/
1850
1851
								// $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62
1852
								// $GPRMC,183731,A,3907.482,N,12102.436,W,000.0,360.0,080301,015.5,E*67
1853
								// $GPRMC,002454,A,3553.5295,N,13938.6570,E,0.0,43.1,180700,7.1,W,A*3F
1854
								// $GPRMC,094347.000,A,5342.0061,N,00737.9908,W,0.01,156.75,140217,,,A*7D
1855
								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)) {
1856
									$GPS_this_GPRMC = array();
1857
									$GPS_this_GPRMC_raw = array();
1858
									list(
1859
										$GPS_this_GPRMC_raw['gprmc'],
1860
										$GPS_this_GPRMC_raw['timestamp'],
1861
										$GPS_this_GPRMC_raw['status'],
1862
										$GPS_this_GPRMC_raw['latitude'],
1863
										$GPS_this_GPRMC_raw['latitude_direction'],
1864
										$GPS_this_GPRMC_raw['longitude'],
1865
										$GPS_this_GPRMC_raw['longitude_direction'],
1866
										$GPS_this_GPRMC_raw['knots'],
1867
										$GPS_this_GPRMC_raw['angle'],
1868
										$GPS_this_GPRMC_raw['datestamp'],
1869
										$GPS_this_GPRMC_raw['variation'],
1870
										$GPS_this_GPRMC_raw['variation_direction'],
1871
										$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...
1872
										$GPS_this_GPRMC_raw['checksum'],
1873
									) = $matches;
1874
									$GPS_this_GPRMC['raw'] = $GPS_this_GPRMC_raw;
1875
1876
									$hour   = substr($GPS_this_GPRMC['raw']['timestamp'], 0, 2);
1877
									$minute = substr($GPS_this_GPRMC['raw']['timestamp'], 2, 2);
1878
									$second = substr($GPS_this_GPRMC['raw']['timestamp'], 4, 2);
1879
									$ms     = substr($GPS_this_GPRMC['raw']['timestamp'], 6);    // may contain decimal seconds
1880
									$day    = substr($GPS_this_GPRMC['raw']['datestamp'], 0, 2);
1881
									$month  = substr($GPS_this_GPRMC['raw']['datestamp'], 2, 2);
1882
									$year   = (int) substr($GPS_this_GPRMC['raw']['datestamp'], 4, 2);
1883
									$year += (($year > 90) ? 1900 : 2000); // complete lack of foresight: datestamps are stored with 2-digit years, take best guess
1884
									$GPS_this_GPRMC['timestamp'] = $year.'-'.$month.'-'.$day.' '.$hour.':'.$minute.':'.$second.$ms;
1885
1886
									$GPS_this_GPRMC['active'] = ($GPS_this_GPRMC['raw']['status'] == 'A'); // A=Active,V=Void
1887
1888
									foreach (array('latitude','longitude') as $latlon) {
1889
										preg_match('#^([0-9]{1,3})([0-9]{2}\\.[0-9]+)$#', $GPS_this_GPRMC['raw'][$latlon], $matches);
1890
										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...
1891
										$GPS_this_GPRMC[$latlon] = $deg + ($min / 60);
1892
									}
1893
									$GPS_this_GPRMC['latitude']  *= (($GPS_this_GPRMC['raw']['latitude_direction']  == 'S') ? -1 : 1);
1894
									$GPS_this_GPRMC['longitude'] *= (($GPS_this_GPRMC['raw']['longitude_direction'] == 'W') ? -1 : 1);
1895
1896
									$GPS_this_GPRMC['heading']    = $GPS_this_GPRMC['raw']['angle'];
1897
									$GPS_this_GPRMC['speed_knot'] = $GPS_this_GPRMC['raw']['knots'];
1898
									$GPS_this_GPRMC['speed_kmh']  = $GPS_this_GPRMC['raw']['knots'] * 1.852;
1899
									if ($GPS_this_GPRMC['raw']['variation']) {
1900
										$GPS_this_GPRMC['variation']  = $GPS_this_GPRMC['raw']['variation'];
1901
										$GPS_this_GPRMC['variation'] *= (($GPS_this_GPRMC['raw']['variation_direction'] == 'W') ? -1 : 1);
1902
									}
1903
1904
									$atom_structure['gps_entries'][$key] = $GPS_this_GPRMC;
1905
1906
									@$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...
1907
										'latitude'  => (float) $GPS_this_GPRMC['latitude'],
1908
										'longitude' => (float) $GPS_this_GPRMC['longitude'],
1909
										'speed_kmh' => (float) $GPS_this_GPRMC['speed_kmh'],
1910
										'heading'   => (float) $GPS_this_GPRMC['heading'],
1911
									);
1912
1913
								} else {
1914
									$this->warning('Unhandled GPS format in "free" atom at offset '.$gps_pointer['offset']);
1915
								}
1916
							}
1917
							$this->fseek($previous_offset);
0 ignored issues
show
Bug introduced by
It seems like $previous_offset defined by $this->ftell() on line 1828 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...
1918
1919
						} else {
1920
							$this->warning('QuickTime atom "'.$atomname.'" is not mod-8 bytes long ('.$atomsize.' bytes) at offset '.$baseoffset);
1921
						}
1922
					} else {
1923
						$this->warning('QuickTime atom "'.$atomname.'" is zero bytes long at offset '.$baseoffset);
1924
					}
1925
					break;
1926
1927
				case 'loci':// 3GP location (El Loco)
1928
					$loffset = 0;
1929
					$info['quicktime']['comments']['gps_flags']     = array(  getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)));
1930
					$info['quicktime']['comments']['gps_lang']      = array(  getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)));
1931
					$info['quicktime']['comments']['gps_location']  = array(          $this->LociString(substr($atom_data, 6), $loffset));
1932
					$loci_data = substr($atom_data, 6 + $loffset);
1933
					$info['quicktime']['comments']['gps_role']      = array(  getid3_lib::BigEndian2Int(substr($loci_data, 0, 1)));
1934
					$info['quicktime']['comments']['gps_longitude'] = array(getid3_lib::FixedPoint16_16(substr($loci_data, 1, 4)));
1935
					$info['quicktime']['comments']['gps_latitude']  = array(getid3_lib::FixedPoint16_16(substr($loci_data, 5, 4)));
1936
					$info['quicktime']['comments']['gps_altitude']  = array(getid3_lib::FixedPoint16_16(substr($loci_data, 9, 4)));
1937
					$info['quicktime']['comments']['gps_body']      = array(          $this->LociString(substr($loci_data, 13           ), $loffset));
1938
					$info['quicktime']['comments']['gps_notes']     = array(          $this->LociString(substr($loci_data, 13 + $loffset), $loffset));
1939
					break;
1940
1941
				case 'chpl': // CHaPter List
1942
					// https://www.adobe.com/content/dam/Adobe/en/devnet/flv/pdfs/video_file_format_spec_v10.pdf
1943
					$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...
1944
					$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...
1945
					$chpl_count   = getid3_lib::BigEndian2Int(substr($atom_data, 8, 1));
1946
					$chpl_offset = 9;
1947
					for ($i = 0; $i < $chpl_count; $i++) {
1948
						if (($chpl_offset + 9) >= strlen($atom_data)) {
1949
							$this->warning('QuickTime chapter '.$i.' extends beyond end of "chpl" atom');
1950
							break;
1951
						}
1952
						$info['quicktime']['chapters'][$i]['timestamp'] = getid3_lib::BigEndian2Int(substr($atom_data, $chpl_offset, 8)) / 10000000; // timestamps are stored as 100-nanosecond units
1953
						$chpl_offset += 8;
1954
						$chpl_title_size = getid3_lib::BigEndian2Int(substr($atom_data, $chpl_offset, 1));
1955
						$chpl_offset += 1;
1956
						$info['quicktime']['chapters'][$i]['title']     =                           substr($atom_data, $chpl_offset, $chpl_title_size);
1957
						$chpl_offset += $chpl_title_size;
1958
					}
1959
					break;
1960
1961
				case 'FIRM': // FIRMware version(?), seen on GoPro Hero4
1962
					$info['quicktime']['camera']['firmware'] = $atom_data;
1963
					break;
1964
1965
				case 'CAME': // FIRMware version(?), seen on GoPro Hero4
1966
					$info['quicktime']['camera']['serial_hash'] = unpack('H*', $atom_data);
1967
					break;
1968
1969
				case 'dscp':
1970
				case 'rcif':
1971
					// https://www.getid3.org/phpBB3/viewtopic.php?t=1908
1972
					if (substr($atom_data, 0, 7) == "\x00\x00\x00\x00\x55\xC4".'{') {
1973
						if ($json_decoded = @json_decode(rtrim(substr($atom_data, 6), "\x00"), true)) {
1974
							$info['quicktime']['camera'][$atomname] = $json_decoded;
1975
							if (($atomname == 'rcif') && isset($info['quicktime']['camera']['rcif']['wxcamera']['rotate'])) {
1976
								$info['video']['rotate'] = $info['quicktime']['video']['rotate'] = $info['quicktime']['camera']['rcif']['wxcamera']['rotate'];
1977
							}
1978
						} else {
1979
							$this->warning('Failed to JSON decode atom "'.$atomname.'"');
1980
							$atom_structure['data'] = $atom_data;
1981
						}
1982
						unset($json_decoded);
1983
					} else {
1984
						$this->warning('Expecting 55 C4 7B at start of atom "'.$atomname.'", found '.getid3_lib::PrintHexBytes(substr($atom_data, 4, 3)).' instead');
1985
						$atom_structure['data'] = $atom_data;
1986
					}
1987
					break;
1988
1989
				case 'frea':
1990
					// https://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Kodak.html#frea
1991
					// may contain "scra" (PreviewImage) and/or "thma" (ThumbnailImage)
1992
					$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms);
1993
					break;
1994
				case 'tima': // subatom to "frea"
1995
					// no idea what this does, the one sample file I've seen has a value of 0x00000027
1996
					$atom_structure['data'] = $atom_data;
1997
					break;
1998
				case 'ver ': // subatom to "frea"
1999
					// some kind of version number, the one sample file I've seen has a value of "3.00.073"
2000
					$atom_structure['data'] = $atom_data;
2001
					break;
2002 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...
2003
					// https://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Kodak.html#frea
2004
					if (strlen($atom_data) > 0) {
2005
						$info['quicktime']['comments']['picture'][] = array('data'=>$atom_data, 'image_mime'=>'image/jpeg', 'description'=>'ThumbnailImage');
2006
					}
2007
					break;
2008 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...
2009
					// https://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Kodak.html#frea
2010
					// but the only sample file I've seen has no useful data here
2011
					if (strlen($atom_data) > 0) {
2012
						$info['quicktime']['comments']['picture'][] = array('data'=>$atom_data, 'image_mime'=>'image/jpeg', 'description'=>'PreviewImage');
2013
					}
2014
					break;
2015
2016
				case 'cdsc': // timed metadata reference
2017
					// A QuickTime movie can contain none, one, or several timed metadata tracks. Timed metadata tracks can refer to multiple tracks.
2018
					// Metadata tracks are linked to the tracks they describe using a track-reference of type 'cdsc'. The metadata track holds the 'cdsc' track reference.
2019
					$atom_structure['track_number'] = getid3_lib::BigEndian2Int($atom_data);
2020
					break;
2021
2022 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...
2023
					$this->warning('Unknown QuickTime atom type: "'.preg_replace('#[^a-zA-Z0-9 _\\-]#', '?', $atomname).'" ('.trim(getid3_lib::PrintHexBytes($atomname)).'), '.$atomsize.' bytes at offset '.$baseoffset);
2024
					$atom_structure['data'] = $atom_data;
2025
					break;
2026
			}
2027
		}
2028
		array_pop($atomHierarchy);
2029
		return $atom_structure;
2030
	}
2031
2032
	/**
2033
	 * @param string $atom_data
2034
	 * @param int    $baseoffset
2035
	 * @param array  $atomHierarchy
2036
	 * @param bool   $ParseAllPossibleAtoms
2037
	 *
2038
	 * @return array|false
2039
	 */
2040
	public function QuicktimeParseContainerAtom($atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
2041
		$atom_structure  = false;
2042
		$subatomoffset  = 0;
2043
		$subatomcounter = 0;
2044
		if ((strlen($atom_data) == 4) && (getid3_lib::BigEndian2Int($atom_data) == 0x00000000)) {
2045
			return false;
2046
		}
2047
		while ($subatomoffset < strlen($atom_data)) {
2048
			$subatomsize = getid3_lib::BigEndian2Int(substr($atom_data, $subatomoffset + 0, 4));
2049
			$subatomname =                           substr($atom_data, $subatomoffset + 4, 4);
2050
			$subatomdata =                           substr($atom_data, $subatomoffset + 8, $subatomsize - 8);
2051
			if ($subatomsize == 0) {
2052
				// Furthermore, for historical reasons the list of atoms is optionally
2053
				// terminated by a 32-bit integer set to 0. If you are writing a program
2054
				// to read user data atoms, you should allow for the terminating 0.
2055
				if (strlen($atom_data) > 12) {
2056
					$subatomoffset += 4;
2057
					continue;
2058
				}
2059
				return $atom_structure;
2060
			}
2061
			if (strlen($subatomdata) < ($subatomsize - 8)) {
2062
			    // we don't have enough data to decode the subatom.
2063
			    // this may be because we are refusing to parse large subatoms, or it may be because this atom had its size set too large
2064
			    // so we passed in the start of a following atom incorrectly?
2065
			    return $atom_structure;
2066
			}
2067
			$atom_structure[$subatomcounter++] = $this->QuicktimeParseAtom($subatomname, $subatomsize, $subatomdata, $baseoffset + $subatomoffset, $atomHierarchy, $ParseAllPossibleAtoms);
2068
			$subatomoffset += $subatomsize;
2069
		}
2070
		return $atom_structure;
2071
	}
2072
2073
	/**
2074
	 * @param string $data
2075
	 * @param int    $offset
2076
	 *
2077
	 * @return int
2078
	 */
2079
	public function quicktime_read_mp4_descr_length($data, &$offset) {
2080
		// http://libquicktime.sourcearchive.com/documentation/2:1.0.2plus-pdebian-2build1/esds_8c-source.html
2081
		$num_bytes = 0;
2082
		$length    = 0;
2083
		do {
2084
			$b = ord(substr($data, $offset++, 1));
2085
			$length = ($length << 7) | ($b & 0x7F);
2086
		} while (($b & 0x80) && ($num_bytes++ < 4));
2087
		return $length;
2088
	}
2089
2090
	/**
2091
	 * @param int $languageid
2092
	 *
2093
	 * @return string
2094
	 */
2095
	public function QuicktimeLanguageLookup($languageid) {
2096
		// http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-34353
2097
		static $QuicktimeLanguageLookup = array();
2098
		if (empty($QuicktimeLanguageLookup)) {
2099
			$QuicktimeLanguageLookup[0]     = 'English';
2100
			$QuicktimeLanguageLookup[1]     = 'French';
2101
			$QuicktimeLanguageLookup[2]     = 'German';
2102
			$QuicktimeLanguageLookup[3]     = 'Italian';
2103
			$QuicktimeLanguageLookup[4]     = 'Dutch';
2104
			$QuicktimeLanguageLookup[5]     = 'Swedish';
2105
			$QuicktimeLanguageLookup[6]     = 'Spanish';
2106
			$QuicktimeLanguageLookup[7]     = 'Danish';
2107
			$QuicktimeLanguageLookup[8]     = 'Portuguese';
2108
			$QuicktimeLanguageLookup[9]     = 'Norwegian';
2109
			$QuicktimeLanguageLookup[10]    = 'Hebrew';
2110
			$QuicktimeLanguageLookup[11]    = 'Japanese';
2111
			$QuicktimeLanguageLookup[12]    = 'Arabic';
2112
			$QuicktimeLanguageLookup[13]    = 'Finnish';
2113
			$QuicktimeLanguageLookup[14]    = 'Greek';
2114
			$QuicktimeLanguageLookup[15]    = 'Icelandic';
2115
			$QuicktimeLanguageLookup[16]    = 'Maltese';
2116
			$QuicktimeLanguageLookup[17]    = 'Turkish';
2117
			$QuicktimeLanguageLookup[18]    = 'Croatian';
2118
			$QuicktimeLanguageLookup[19]    = 'Chinese (Traditional)';
2119
			$QuicktimeLanguageLookup[20]    = 'Urdu';
2120
			$QuicktimeLanguageLookup[21]    = 'Hindi';
2121
			$QuicktimeLanguageLookup[22]    = 'Thai';
2122
			$QuicktimeLanguageLookup[23]    = 'Korean';
2123
			$QuicktimeLanguageLookup[24]    = 'Lithuanian';
2124
			$QuicktimeLanguageLookup[25]    = 'Polish';
2125
			$QuicktimeLanguageLookup[26]    = 'Hungarian';
2126
			$QuicktimeLanguageLookup[27]    = 'Estonian';
2127
			$QuicktimeLanguageLookup[28]    = 'Lettish';
2128
			$QuicktimeLanguageLookup[28]    = 'Latvian';
2129
			$QuicktimeLanguageLookup[29]    = 'Saamisk';
2130
			$QuicktimeLanguageLookup[29]    = 'Lappish';
2131
			$QuicktimeLanguageLookup[30]    = 'Faeroese';
2132
			$QuicktimeLanguageLookup[31]    = 'Farsi';
2133
			$QuicktimeLanguageLookup[31]    = 'Persian';
2134
			$QuicktimeLanguageLookup[32]    = 'Russian';
2135
			$QuicktimeLanguageLookup[33]    = 'Chinese (Simplified)';
2136
			$QuicktimeLanguageLookup[34]    = 'Flemish';
2137
			$QuicktimeLanguageLookup[35]    = 'Irish';
2138
			$QuicktimeLanguageLookup[36]    = 'Albanian';
2139
			$QuicktimeLanguageLookup[37]    = 'Romanian';
2140
			$QuicktimeLanguageLookup[38]    = 'Czech';
2141
			$QuicktimeLanguageLookup[39]    = 'Slovak';
2142
			$QuicktimeLanguageLookup[40]    = 'Slovenian';
2143
			$QuicktimeLanguageLookup[41]    = 'Yiddish';
2144
			$QuicktimeLanguageLookup[42]    = 'Serbian';
2145
			$QuicktimeLanguageLookup[43]    = 'Macedonian';
2146
			$QuicktimeLanguageLookup[44]    = 'Bulgarian';
2147
			$QuicktimeLanguageLookup[45]    = 'Ukrainian';
2148
			$QuicktimeLanguageLookup[46]    = 'Byelorussian';
2149
			$QuicktimeLanguageLookup[47]    = 'Uzbek';
2150
			$QuicktimeLanguageLookup[48]    = 'Kazakh';
2151
			$QuicktimeLanguageLookup[49]    = 'Azerbaijani';
2152
			$QuicktimeLanguageLookup[50]    = 'AzerbaijanAr';
2153
			$QuicktimeLanguageLookup[51]    = 'Armenian';
2154
			$QuicktimeLanguageLookup[52]    = 'Georgian';
2155
			$QuicktimeLanguageLookup[53]    = 'Moldavian';
2156
			$QuicktimeLanguageLookup[54]    = 'Kirghiz';
2157
			$QuicktimeLanguageLookup[55]    = 'Tajiki';
2158
			$QuicktimeLanguageLookup[56]    = 'Turkmen';
2159
			$QuicktimeLanguageLookup[57]    = 'Mongolian';
2160
			$QuicktimeLanguageLookup[58]    = 'MongolianCyr';
2161
			$QuicktimeLanguageLookup[59]    = 'Pashto';
2162
			$QuicktimeLanguageLookup[60]    = 'Kurdish';
2163
			$QuicktimeLanguageLookup[61]    = 'Kashmiri';
2164
			$QuicktimeLanguageLookup[62]    = 'Sindhi';
2165
			$QuicktimeLanguageLookup[63]    = 'Tibetan';
2166
			$QuicktimeLanguageLookup[64]    = 'Nepali';
2167
			$QuicktimeLanguageLookup[65]    = 'Sanskrit';
2168
			$QuicktimeLanguageLookup[66]    = 'Marathi';
2169
			$QuicktimeLanguageLookup[67]    = 'Bengali';
2170
			$QuicktimeLanguageLookup[68]    = 'Assamese';
2171
			$QuicktimeLanguageLookup[69]    = 'Gujarati';
2172
			$QuicktimeLanguageLookup[70]    = 'Punjabi';
2173
			$QuicktimeLanguageLookup[71]    = 'Oriya';
2174
			$QuicktimeLanguageLookup[72]    = 'Malayalam';
2175
			$QuicktimeLanguageLookup[73]    = 'Kannada';
2176
			$QuicktimeLanguageLookup[74]    = 'Tamil';
2177
			$QuicktimeLanguageLookup[75]    = 'Telugu';
2178
			$QuicktimeLanguageLookup[76]    = 'Sinhalese';
2179
			$QuicktimeLanguageLookup[77]    = 'Burmese';
2180
			$QuicktimeLanguageLookup[78]    = 'Khmer';
2181
			$QuicktimeLanguageLookup[79]    = 'Lao';
2182
			$QuicktimeLanguageLookup[80]    = 'Vietnamese';
2183
			$QuicktimeLanguageLookup[81]    = 'Indonesian';
2184
			$QuicktimeLanguageLookup[82]    = 'Tagalog';
2185
			$QuicktimeLanguageLookup[83]    = 'MalayRoman';
2186
			$QuicktimeLanguageLookup[84]    = 'MalayArabic';
2187
			$QuicktimeLanguageLookup[85]    = 'Amharic';
2188
			$QuicktimeLanguageLookup[86]    = 'Tigrinya';
2189
			$QuicktimeLanguageLookup[87]    = 'Galla';
2190
			$QuicktimeLanguageLookup[87]    = 'Oromo';
2191
			$QuicktimeLanguageLookup[88]    = 'Somali';
2192
			$QuicktimeLanguageLookup[89]    = 'Swahili';
2193
			$QuicktimeLanguageLookup[90]    = 'Ruanda';
2194
			$QuicktimeLanguageLookup[91]    = 'Rundi';
2195
			$QuicktimeLanguageLookup[92]    = 'Chewa';
2196
			$QuicktimeLanguageLookup[93]    = 'Malagasy';
2197
			$QuicktimeLanguageLookup[94]    = 'Esperanto';
2198
			$QuicktimeLanguageLookup[128]   = 'Welsh';
2199
			$QuicktimeLanguageLookup[129]   = 'Basque';
2200
			$QuicktimeLanguageLookup[130]   = 'Catalan';
2201
			$QuicktimeLanguageLookup[131]   = 'Latin';
2202
			$QuicktimeLanguageLookup[132]   = 'Quechua';
2203
			$QuicktimeLanguageLookup[133]   = 'Guarani';
2204
			$QuicktimeLanguageLookup[134]   = 'Aymara';
2205
			$QuicktimeLanguageLookup[135]   = 'Tatar';
2206
			$QuicktimeLanguageLookup[136]   = 'Uighur';
2207
			$QuicktimeLanguageLookup[137]   = 'Dzongkha';
2208
			$QuicktimeLanguageLookup[138]   = 'JavaneseRom';
2209
			$QuicktimeLanguageLookup[32767] = 'Unspecified';
2210
		}
2211
		if (($languageid > 138) && ($languageid < 32767)) {
2212
			/*
2213
			ISO Language Codes - http://www.loc.gov/standards/iso639-2/php/code_list.php
2214
			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.
2215
			The packing algorithm must map each of the three characters, which are always lowercase, into a 5-bit integer and then concatenate
2216
			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.
2217
2218
			One algorithm for performing this packing is to treat each ISO character as a 16-bit integer. Subtract 0x60 from the first character
2219
			and multiply by 2^10 (0x400), subtract 0x60 from the second character and multiply by 2^5 (0x20), subtract 0x60 from the third character,
2220
			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
2221
			significant bits and the most significant bit set to zero.
2222
			*/
2223
			$iso_language_id  = '';
2224
			$iso_language_id .= chr((($languageid & 0x7C00) >> 10) + 0x60);
2225
			$iso_language_id .= chr((($languageid & 0x03E0) >>  5) + 0x60);
2226
			$iso_language_id .= chr((($languageid & 0x001F) >>  0) + 0x60);
2227
			$QuicktimeLanguageLookup[$languageid] = getid3_id3v2::LanguageLookup($iso_language_id);
2228
		}
2229
		return (isset($QuicktimeLanguageLookup[$languageid]) ? $QuicktimeLanguageLookup[$languageid] : 'invalid');
2230
	}
2231
2232
	/**
2233
	 * @param string $codecid
2234
	 *
2235
	 * @return string
2236
	 */
2237
	public function QuicktimeVideoCodecLookup($codecid) {
2238
		static $QuicktimeVideoCodecLookup = array();
2239
		if (empty($QuicktimeVideoCodecLookup)) {
2240
			$QuicktimeVideoCodecLookup['.SGI'] = 'SGI';
2241
			$QuicktimeVideoCodecLookup['3IV1'] = '3ivx MPEG-4 v1';
2242
			$QuicktimeVideoCodecLookup['3IV2'] = '3ivx MPEG-4 v2';
2243
			$QuicktimeVideoCodecLookup['3IVX'] = '3ivx MPEG-4';
2244
			$QuicktimeVideoCodecLookup['8BPS'] = 'Planar RGB';
2245
			$QuicktimeVideoCodecLookup['avc1'] = 'H.264/MPEG-4 AVC';
2246
			$QuicktimeVideoCodecLookup['avr '] = 'AVR-JPEG';
2247
			$QuicktimeVideoCodecLookup['b16g'] = '16Gray';
2248
			$QuicktimeVideoCodecLookup['b32a'] = '32AlphaGray';
2249
			$QuicktimeVideoCodecLookup['b48r'] = '48RGB';
2250
			$QuicktimeVideoCodecLookup['b64a'] = '64ARGB';
2251
			$QuicktimeVideoCodecLookup['base'] = 'Base';
2252
			$QuicktimeVideoCodecLookup['clou'] = 'Cloud';
2253
			$QuicktimeVideoCodecLookup['cmyk'] = 'CMYK';
2254
			$QuicktimeVideoCodecLookup['cvid'] = 'Cinepak';
2255
			$QuicktimeVideoCodecLookup['dmb1'] = 'OpenDML JPEG';
2256
			$QuicktimeVideoCodecLookup['dvc '] = 'DVC-NTSC';
2257
			$QuicktimeVideoCodecLookup['dvcp'] = 'DVC-PAL';
2258
			$QuicktimeVideoCodecLookup['dvpn'] = 'DVCPro-NTSC';
2259
			$QuicktimeVideoCodecLookup['dvpp'] = 'DVCPro-PAL';
2260
			$QuicktimeVideoCodecLookup['fire'] = 'Fire';
2261
			$QuicktimeVideoCodecLookup['flic'] = 'FLC';
2262
			$QuicktimeVideoCodecLookup['gif '] = 'GIF';
2263
			$QuicktimeVideoCodecLookup['h261'] = 'H261';
2264
			$QuicktimeVideoCodecLookup['h263'] = 'H263';
2265
			$QuicktimeVideoCodecLookup['IV41'] = 'Indeo4';
2266
			$QuicktimeVideoCodecLookup['jpeg'] = 'JPEG';
2267
			$QuicktimeVideoCodecLookup['kpcd'] = 'PhotoCD';
2268
			$QuicktimeVideoCodecLookup['mjpa'] = 'Motion JPEG-A';
2269
			$QuicktimeVideoCodecLookup['mjpb'] = 'Motion JPEG-B';
2270
			$QuicktimeVideoCodecLookup['msvc'] = 'Microsoft Video1';
2271
			$QuicktimeVideoCodecLookup['myuv'] = 'MPEG YUV420';
2272
			$QuicktimeVideoCodecLookup['path'] = 'Vector';
2273
			$QuicktimeVideoCodecLookup['png '] = 'PNG';
2274
			$QuicktimeVideoCodecLookup['PNTG'] = 'MacPaint';
2275
			$QuicktimeVideoCodecLookup['qdgx'] = 'QuickDrawGX';
2276
			$QuicktimeVideoCodecLookup['qdrw'] = 'QuickDraw';
2277
			$QuicktimeVideoCodecLookup['raw '] = 'RAW';
2278
			$QuicktimeVideoCodecLookup['ripl'] = 'WaterRipple';
2279
			$QuicktimeVideoCodecLookup['rpza'] = 'Video';
2280
			$QuicktimeVideoCodecLookup['smc '] = 'Graphics';
2281
			$QuicktimeVideoCodecLookup['SVQ1'] = 'Sorenson Video 1';
2282
			$QuicktimeVideoCodecLookup['SVQ1'] = 'Sorenson Video 3';
2283
			$QuicktimeVideoCodecLookup['syv9'] = 'Sorenson YUV9';
2284
			$QuicktimeVideoCodecLookup['tga '] = 'Targa';
2285
			$QuicktimeVideoCodecLookup['tiff'] = 'TIFF';
2286
			$QuicktimeVideoCodecLookup['WRAW'] = 'Windows RAW';
2287
			$QuicktimeVideoCodecLookup['WRLE'] = 'BMP';
2288
			$QuicktimeVideoCodecLookup['y420'] = 'YUV420';
2289
			$QuicktimeVideoCodecLookup['yuv2'] = 'ComponentVideo';
2290
			$QuicktimeVideoCodecLookup['yuvs'] = 'ComponentVideoUnsigned';
2291
			$QuicktimeVideoCodecLookup['yuvu'] = 'ComponentVideoSigned';
2292
		}
2293
		return (isset($QuicktimeVideoCodecLookup[$codecid]) ? $QuicktimeVideoCodecLookup[$codecid] : '');
2294
	}
2295
2296
	/**
2297
	 * @param string $codecid
2298
	 *
2299
	 * @return mixed|string
2300
	 */
2301
	public function QuicktimeAudioCodecLookup($codecid) {
2302
		static $QuicktimeAudioCodecLookup = array();
2303
		if (empty($QuicktimeAudioCodecLookup)) {
2304
			$QuicktimeAudioCodecLookup['.mp3']          = 'Fraunhofer MPEG Layer-III alias';
2305
			$QuicktimeAudioCodecLookup['aac ']          = 'ISO/IEC 14496-3 AAC';
2306
			$QuicktimeAudioCodecLookup['agsm']          = 'Apple GSM 10:1';
2307
			$QuicktimeAudioCodecLookup['alac']          = 'Apple Lossless Audio Codec';
2308
			$QuicktimeAudioCodecLookup['alaw']          = 'A-law 2:1';
2309
			$QuicktimeAudioCodecLookup['conv']          = 'Sample Format';
2310
			$QuicktimeAudioCodecLookup['dvca']          = 'DV';
2311
			$QuicktimeAudioCodecLookup['dvi ']          = 'DV 4:1';
2312
			$QuicktimeAudioCodecLookup['eqal']          = 'Frequency Equalizer';
2313
			$QuicktimeAudioCodecLookup['fl32']          = '32-bit Floating Point';
2314
			$QuicktimeAudioCodecLookup['fl64']          = '64-bit Floating Point';
2315
			$QuicktimeAudioCodecLookup['ima4']          = 'Interactive Multimedia Association 4:1';
2316
			$QuicktimeAudioCodecLookup['in24']          = '24-bit Integer';
2317
			$QuicktimeAudioCodecLookup['in32']          = '32-bit Integer';
2318
			$QuicktimeAudioCodecLookup['lpc ']          = 'LPC 23:1';
2319
			$QuicktimeAudioCodecLookup['MAC3']          = 'Macintosh Audio Compression/Expansion (MACE) 3:1';
2320
			$QuicktimeAudioCodecLookup['MAC6']          = 'Macintosh Audio Compression/Expansion (MACE) 6:1';
2321
			$QuicktimeAudioCodecLookup['mixb']          = '8-bit Mixer';
2322
			$QuicktimeAudioCodecLookup['mixw']          = '16-bit Mixer';
2323
			$QuicktimeAudioCodecLookup['mp4a']          = 'ISO/IEC 14496-3 AAC';
2324
			$QuicktimeAudioCodecLookup['MS'."\x00\x02"] = 'Microsoft ADPCM';
2325
			$QuicktimeAudioCodecLookup['MS'."\x00\x11"] = 'DV IMA';
2326
			$QuicktimeAudioCodecLookup['MS'."\x00\x55"] = 'Fraunhofer MPEG Layer III';
2327
			$QuicktimeAudioCodecLookup['NONE']          = 'No Encoding';
2328
			$QuicktimeAudioCodecLookup['Qclp']          = 'Qualcomm PureVoice';
2329
			$QuicktimeAudioCodecLookup['QDM2']          = 'QDesign Music 2';
2330
			$QuicktimeAudioCodecLookup['QDMC']          = 'QDesign Music 1';
2331
			$QuicktimeAudioCodecLookup['ratb']          = '8-bit Rate';
2332
			$QuicktimeAudioCodecLookup['ratw']          = '16-bit Rate';
2333
			$QuicktimeAudioCodecLookup['raw ']          = 'raw PCM';
2334
			$QuicktimeAudioCodecLookup['sour']          = 'Sound Source';
2335
			$QuicktimeAudioCodecLookup['sowt']          = 'signed/two\'s complement (Little Endian)';
2336
			$QuicktimeAudioCodecLookup['str1']          = 'Iomega MPEG layer II';
2337
			$QuicktimeAudioCodecLookup['str2']          = 'Iomega MPEG *layer II';
2338
			$QuicktimeAudioCodecLookup['str3']          = 'Iomega MPEG **layer II';
2339
			$QuicktimeAudioCodecLookup['str4']          = 'Iomega MPEG ***layer II';
2340
			$QuicktimeAudioCodecLookup['twos']          = 'signed/two\'s complement (Big Endian)';
2341
			$QuicktimeAudioCodecLookup['ulaw']          = 'mu-law 2:1';
2342
		}
2343
		return (isset($QuicktimeAudioCodecLookup[$codecid]) ? $QuicktimeAudioCodecLookup[$codecid] : '');
2344
	}
2345
2346
	/**
2347
	 * @param string $compressionid
2348
	 *
2349
	 * @return string
2350
	 */
2351
	public function QuicktimeDCOMLookup($compressionid) {
2352
		static $QuicktimeDCOMLookup = array();
2353
		if (empty($QuicktimeDCOMLookup)) {
2354
			$QuicktimeDCOMLookup['zlib'] = 'ZLib Deflate';
2355
			$QuicktimeDCOMLookup['adec'] = 'Apple Compression';
2356
		}
2357
		return (isset($QuicktimeDCOMLookup[$compressionid]) ? $QuicktimeDCOMLookup[$compressionid] : '');
2358
	}
2359
2360
	/**
2361
	 * @param int $colordepthid
2362
	 *
2363
	 * @return string
2364
	 */
2365
	public function QuicktimeColorNameLookup($colordepthid) {
2366
		static $QuicktimeColorNameLookup = array();
2367
		if (empty($QuicktimeColorNameLookup)) {
2368
			$QuicktimeColorNameLookup[1]  = '2-color (monochrome)';
2369
			$QuicktimeColorNameLookup[2]  = '4-color';
2370
			$QuicktimeColorNameLookup[4]  = '16-color';
2371
			$QuicktimeColorNameLookup[8]  = '256-color';
2372
			$QuicktimeColorNameLookup[16] = 'thousands (16-bit color)';
2373
			$QuicktimeColorNameLookup[24] = 'millions (24-bit color)';
2374
			$QuicktimeColorNameLookup[32] = 'millions+ (32-bit color)';
2375
			$QuicktimeColorNameLookup[33] = 'black & white';
2376
			$QuicktimeColorNameLookup[34] = '4-gray';
2377
			$QuicktimeColorNameLookup[36] = '16-gray';
2378
			$QuicktimeColorNameLookup[40] = '256-gray';
2379
		}
2380
		return (isset($QuicktimeColorNameLookup[$colordepthid]) ? $QuicktimeColorNameLookup[$colordepthid] : 'invalid');
2381
	}
2382
2383
	/**
2384
	 * @param int $stik
2385
	 *
2386
	 * @return string
2387
	 */
2388
	public function QuicktimeSTIKLookup($stik) {
2389
		static $QuicktimeSTIKLookup = array();
2390
		if (empty($QuicktimeSTIKLookup)) {
2391
			$QuicktimeSTIKLookup[0]  = 'Movie';
2392
			$QuicktimeSTIKLookup[1]  = 'Normal';
2393
			$QuicktimeSTIKLookup[2]  = 'Audiobook';
2394
			$QuicktimeSTIKLookup[5]  = 'Whacked Bookmark';
2395
			$QuicktimeSTIKLookup[6]  = 'Music Video';
2396
			$QuicktimeSTIKLookup[9]  = 'Short Film';
2397
			$QuicktimeSTIKLookup[10] = 'TV Show';
2398
			$QuicktimeSTIKLookup[11] = 'Booklet';
2399
			$QuicktimeSTIKLookup[14] = 'Ringtone';
2400
			$QuicktimeSTIKLookup[21] = 'Podcast';
2401
		}
2402
		return (isset($QuicktimeSTIKLookup[$stik]) ? $QuicktimeSTIKLookup[$stik] : 'invalid');
2403
	}
2404
2405
	/**
2406
	 * @param int $audio_profile_id
2407
	 *
2408
	 * @return string
2409
	 */
2410
	public function QuicktimeIODSaudioProfileName($audio_profile_id) {
2411
		static $QuicktimeIODSaudioProfileNameLookup = array();
2412
		if (empty($QuicktimeIODSaudioProfileNameLookup)) {
2413
			$QuicktimeIODSaudioProfileNameLookup = array(
2414
				0x00 => 'ISO Reserved (0x00)',
2415
				0x01 => 'Main Audio Profile @ Level 1',
2416
				0x02 => 'Main Audio Profile @ Level 2',
2417
				0x03 => 'Main Audio Profile @ Level 3',
2418
				0x04 => 'Main Audio Profile @ Level 4',
2419
				0x05 => 'Scalable Audio Profile @ Level 1',
2420
				0x06 => 'Scalable Audio Profile @ Level 2',
2421
				0x07 => 'Scalable Audio Profile @ Level 3',
2422
				0x08 => 'Scalable Audio Profile @ Level 4',
2423
				0x09 => 'Speech Audio Profile @ Level 1',
2424
				0x0A => 'Speech Audio Profile @ Level 2',
2425
				0x0B => 'Synthetic Audio Profile @ Level 1',
2426
				0x0C => 'Synthetic Audio Profile @ Level 2',
2427
				0x0D => 'Synthetic Audio Profile @ Level 3',
2428
				0x0E => 'High Quality Audio Profile @ Level 1',
2429
				0x0F => 'High Quality Audio Profile @ Level 2',
2430
				0x10 => 'High Quality Audio Profile @ Level 3',
2431
				0x11 => 'High Quality Audio Profile @ Level 4',
2432
				0x12 => 'High Quality Audio Profile @ Level 5',
2433
				0x13 => 'High Quality Audio Profile @ Level 6',
2434
				0x14 => 'High Quality Audio Profile @ Level 7',
2435
				0x15 => 'High Quality Audio Profile @ Level 8',
2436
				0x16 => 'Low Delay Audio Profile @ Level 1',
2437
				0x17 => 'Low Delay Audio Profile @ Level 2',
2438
				0x18 => 'Low Delay Audio Profile @ Level 3',
2439
				0x19 => 'Low Delay Audio Profile @ Level 4',
2440
				0x1A => 'Low Delay Audio Profile @ Level 5',
2441
				0x1B => 'Low Delay Audio Profile @ Level 6',
2442
				0x1C => 'Low Delay Audio Profile @ Level 7',
2443
				0x1D => 'Low Delay Audio Profile @ Level 8',
2444
				0x1E => 'Natural Audio Profile @ Level 1',
2445
				0x1F => 'Natural Audio Profile @ Level 2',
2446
				0x20 => 'Natural Audio Profile @ Level 3',
2447
				0x21 => 'Natural Audio Profile @ Level 4',
2448
				0x22 => 'Mobile Audio Internetworking Profile @ Level 1',
2449
				0x23 => 'Mobile Audio Internetworking Profile @ Level 2',
2450
				0x24 => 'Mobile Audio Internetworking Profile @ Level 3',
2451
				0x25 => 'Mobile Audio Internetworking Profile @ Level 4',
2452
				0x26 => 'Mobile Audio Internetworking Profile @ Level 5',
2453
				0x27 => 'Mobile Audio Internetworking Profile @ Level 6',
2454
				0x28 => 'AAC Profile @ Level 1',
2455
				0x29 => 'AAC Profile @ Level 2',
2456
				0x2A => 'AAC Profile @ Level 4',
2457
				0x2B => 'AAC Profile @ Level 5',
2458
				0x2C => 'High Efficiency AAC Profile @ Level 2',
2459
				0x2D => 'High Efficiency AAC Profile @ Level 3',
2460
				0x2E => 'High Efficiency AAC Profile @ Level 4',
2461
				0x2F => 'High Efficiency AAC Profile @ Level 5',
2462
				0xFE => 'Not part of MPEG-4 audio profiles',
2463
				0xFF => 'No audio capability required',
2464
			);
2465
		}
2466
		return (isset($QuicktimeIODSaudioProfileNameLookup[$audio_profile_id]) ? $QuicktimeIODSaudioProfileNameLookup[$audio_profile_id] : 'ISO Reserved / User Private');
2467
	}
2468
2469
	/**
2470
	 * @param int $video_profile_id
2471
	 *
2472
	 * @return string
2473
	 */
2474
	public function QuicktimeIODSvideoProfileName($video_profile_id) {
2475
		static $QuicktimeIODSvideoProfileNameLookup = array();
2476
		if (empty($QuicktimeIODSvideoProfileNameLookup)) {
2477
			$QuicktimeIODSvideoProfileNameLookup = array(
2478
				0x00 => 'Reserved (0x00) Profile',
2479
				0x01 => 'Simple Profile @ Level 1',
2480
				0x02 => 'Simple Profile @ Level 2',
2481
				0x03 => 'Simple Profile @ Level 3',
2482
				0x08 => 'Simple Profile @ Level 0',
2483
				0x10 => 'Simple Scalable Profile @ Level 0',
2484
				0x11 => 'Simple Scalable Profile @ Level 1',
2485
				0x12 => 'Simple Scalable Profile @ Level 2',
2486
				0x15 => 'AVC/H264 Profile',
2487
				0x21 => 'Core Profile @ Level 1',
2488
				0x22 => 'Core Profile @ Level 2',
2489
				0x32 => 'Main Profile @ Level 2',
2490
				0x33 => 'Main Profile @ Level 3',
2491
				0x34 => 'Main Profile @ Level 4',
2492
				0x42 => 'N-bit Profile @ Level 2',
2493
				0x51 => 'Scalable Texture Profile @ Level 1',
2494
				0x61 => 'Simple Face Animation Profile @ Level 1',
2495
				0x62 => 'Simple Face Animation Profile @ Level 2',
2496
				0x63 => 'Simple FBA Profile @ Level 1',
2497
				0x64 => 'Simple FBA Profile @ Level 2',
2498
				0x71 => 'Basic Animated Texture Profile @ Level 1',
2499
				0x72 => 'Basic Animated Texture Profile @ Level 2',
2500
				0x81 => 'Hybrid Profile @ Level 1',
2501
				0x82 => 'Hybrid Profile @ Level 2',
2502
				0x91 => 'Advanced Real Time Simple Profile @ Level 1',
2503
				0x92 => 'Advanced Real Time Simple Profile @ Level 2',
2504
				0x93 => 'Advanced Real Time Simple Profile @ Level 3',
2505
				0x94 => 'Advanced Real Time Simple Profile @ Level 4',
2506
				0xA1 => 'Core Scalable Profile @ Level1',
2507
				0xA2 => 'Core Scalable Profile @ Level2',
2508
				0xA3 => 'Core Scalable Profile @ Level3',
2509
				0xB1 => 'Advanced Coding Efficiency Profile @ Level 1',
2510
				0xB2 => 'Advanced Coding Efficiency Profile @ Level 2',
2511
				0xB3 => 'Advanced Coding Efficiency Profile @ Level 3',
2512
				0xB4 => 'Advanced Coding Efficiency Profile @ Level 4',
2513
				0xC1 => 'Advanced Core Profile @ Level 1',
2514
				0xC2 => 'Advanced Core Profile @ Level 2',
2515
				0xD1 => 'Advanced Scalable Texture @ Level1',
2516
				0xD2 => 'Advanced Scalable Texture @ Level2',
2517
				0xE1 => 'Simple Studio Profile @ Level 1',
2518
				0xE2 => 'Simple Studio Profile @ Level 2',
2519
				0xE3 => 'Simple Studio Profile @ Level 3',
2520
				0xE4 => 'Simple Studio Profile @ Level 4',
2521
				0xE5 => 'Core Studio Profile @ Level 1',
2522
				0xE6 => 'Core Studio Profile @ Level 2',
2523
				0xE7 => 'Core Studio Profile @ Level 3',
2524
				0xE8 => 'Core Studio Profile @ Level 4',
2525
				0xF0 => 'Advanced Simple Profile @ Level 0',
2526
				0xF1 => 'Advanced Simple Profile @ Level 1',
2527
				0xF2 => 'Advanced Simple Profile @ Level 2',
2528
				0xF3 => 'Advanced Simple Profile @ Level 3',
2529
				0xF4 => 'Advanced Simple Profile @ Level 4',
2530
				0xF5 => 'Advanced Simple Profile @ Level 5',
2531
				0xF7 => 'Advanced Simple Profile @ Level 3b',
2532
				0xF8 => 'Fine Granularity Scalable Profile @ Level 0',
2533
				0xF9 => 'Fine Granularity Scalable Profile @ Level 1',
2534
				0xFA => 'Fine Granularity Scalable Profile @ Level 2',
2535
				0xFB => 'Fine Granularity Scalable Profile @ Level 3',
2536
				0xFC => 'Fine Granularity Scalable Profile @ Level 4',
2537
				0xFD => 'Fine Granularity Scalable Profile @ Level 5',
2538
				0xFE => 'Not part of MPEG-4 Visual profiles',
2539
				0xFF => 'No visual capability required',
2540
			);
2541
		}
2542
		return (isset($QuicktimeIODSvideoProfileNameLookup[$video_profile_id]) ? $QuicktimeIODSvideoProfileNameLookup[$video_profile_id] : 'ISO Reserved Profile');
2543
	}
2544
2545
	/**
2546
	 * @param int $rtng
2547
	 *
2548
	 * @return string
2549
	 */
2550 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...
2551
		static $QuicktimeContentRatingLookup = array();
2552
		if (empty($QuicktimeContentRatingLookup)) {
2553
			$QuicktimeContentRatingLookup[0]  = 'None';
2554
			$QuicktimeContentRatingLookup[2]  = 'Clean';
2555
			$QuicktimeContentRatingLookup[4]  = 'Explicit';
2556
		}
2557
		return (isset($QuicktimeContentRatingLookup[$rtng]) ? $QuicktimeContentRatingLookup[$rtng] : 'invalid');
2558
	}
2559
2560
	/**
2561
	 * @param int $akid
2562
	 *
2563
	 * @return string
2564
	 */
2565
	public function QuicktimeStoreAccountTypeLookup($akid) {
2566
		static $QuicktimeStoreAccountTypeLookup = array();
2567
		if (empty($QuicktimeStoreAccountTypeLookup)) {
2568
			$QuicktimeStoreAccountTypeLookup[0] = 'iTunes';
2569
			$QuicktimeStoreAccountTypeLookup[1] = 'AOL';
2570
		}
2571
		return (isset($QuicktimeStoreAccountTypeLookup[$akid]) ? $QuicktimeStoreAccountTypeLookup[$akid] : 'invalid');
2572
	}
2573
2574
	/**
2575
	 * @param int $sfid
2576
	 *
2577
	 * @return string
2578
	 */
2579
	public function QuicktimeStoreFrontCodeLookup($sfid) {
2580
		static $QuicktimeStoreFrontCodeLookup = array();
2581
		if (empty($QuicktimeStoreFrontCodeLookup)) {
2582
			$QuicktimeStoreFrontCodeLookup[143460] = 'Australia';
2583
			$QuicktimeStoreFrontCodeLookup[143445] = 'Austria';
2584
			$QuicktimeStoreFrontCodeLookup[143446] = 'Belgium';
2585
			$QuicktimeStoreFrontCodeLookup[143455] = 'Canada';
2586
			$QuicktimeStoreFrontCodeLookup[143458] = 'Denmark';
2587
			$QuicktimeStoreFrontCodeLookup[143447] = 'Finland';
2588
			$QuicktimeStoreFrontCodeLookup[143442] = 'France';
2589
			$QuicktimeStoreFrontCodeLookup[143443] = 'Germany';
2590
			$QuicktimeStoreFrontCodeLookup[143448] = 'Greece';
2591
			$QuicktimeStoreFrontCodeLookup[143449] = 'Ireland';
2592
			$QuicktimeStoreFrontCodeLookup[143450] = 'Italy';
2593
			$QuicktimeStoreFrontCodeLookup[143462] = 'Japan';
2594
			$QuicktimeStoreFrontCodeLookup[143451] = 'Luxembourg';
2595
			$QuicktimeStoreFrontCodeLookup[143452] = 'Netherlands';
2596
			$QuicktimeStoreFrontCodeLookup[143461] = 'New Zealand';
2597
			$QuicktimeStoreFrontCodeLookup[143457] = 'Norway';
2598
			$QuicktimeStoreFrontCodeLookup[143453] = 'Portugal';
2599
			$QuicktimeStoreFrontCodeLookup[143454] = 'Spain';
2600
			$QuicktimeStoreFrontCodeLookup[143456] = 'Sweden';
2601
			$QuicktimeStoreFrontCodeLookup[143459] = 'Switzerland';
2602
			$QuicktimeStoreFrontCodeLookup[143444] = 'United Kingdom';
2603
			$QuicktimeStoreFrontCodeLookup[143441] = 'United States';
2604
		}
2605
		return (isset($QuicktimeStoreFrontCodeLookup[$sfid]) ? $QuicktimeStoreFrontCodeLookup[$sfid] : 'invalid');
2606
	}
2607
2608
	/**
2609
	 * @param string $atom_data
2610
	 *
2611
	 * @return array
2612
	 */
2613
	public function QuicktimeParseNikonNCTG($atom_data) {
2614
		// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
2615
		// Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
2616
		// Data is stored as records of:
2617
		// * 4 bytes record type
2618
		// * 2 bytes size of data field type:
2619
		//     0x0001 = flag   (size field *= 1-byte)
2620
		//     0x0002 = char   (size field *= 1-byte)
2621
		//     0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB
2622
		//     0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD
2623
		//     0x0005 = float  (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together
2624
		//     0x0007 = bytes  (size field *= 1-byte), values are stored as ??????
2625
		//     0x0008 = ?????  (size field *= 2-byte), values are stored as ??????
2626
		// * 2 bytes data size field
2627
		// * ? bytes data (string data may be null-padded; datestamp fields are in the format "2011:05:25 20:24:15")
2628
		// all integers are stored BigEndian
2629
2630
		$NCTGtagName = array(
2631
			0x00000001 => 'Make',
2632
			0x00000002 => 'Model',
2633
			0x00000003 => 'Software',
2634
			0x00000011 => 'CreateDate',
2635
			0x00000012 => 'DateTimeOriginal',
2636
			0x00000013 => 'FrameCount',
2637
			0x00000016 => 'FrameRate',
2638
			0x00000022 => 'FrameWidth',
2639
			0x00000023 => 'FrameHeight',
2640
			0x00000032 => 'AudioChannels',
2641
			0x00000033 => 'AudioBitsPerSample',
2642
			0x00000034 => 'AudioSampleRate',
2643
			0x02000001 => 'MakerNoteVersion',
2644
			0x02000005 => 'WhiteBalance',
2645
			0x0200000b => 'WhiteBalanceFineTune',
2646
			0x0200001e => 'ColorSpace',
2647
			0x02000023 => 'PictureControlData',
2648
			0x02000024 => 'WorldTime',
2649
			0x02000032 => 'UnknownInfo',
2650
			0x02000083 => 'LensType',
2651
			0x02000084 => 'Lens',
2652
		);
2653
2654
		$offset = 0;
2655
		$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...
2656
		$datalength = strlen($atom_data);
2657
		$parsed = array();
2658
		while ($offset < $datalength) {
2659
			$record_type       = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4));  $offset += 4;
2660
			$data_size_type    = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2));  $offset += 2;
2661
			$data_size         = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2));  $offset += 2;
2662
			switch ($data_size_type) {
2663
				case 0x0001: // 0x0001 = flag   (size field *= 1-byte)
2664
					$data = getid3_lib::BigEndian2Int(substr($atom_data, $offset, $data_size * 1));
2665
					$offset += ($data_size * 1);
2666
					break;
2667 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...
2668
					$data = substr($atom_data, $offset, $data_size * 1);
2669
					$offset += ($data_size * 1);
2670
					$data = rtrim($data, "\x00");
2671
					break;
2672 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...
2673
					$data = '';
2674
					for ($i = $data_size - 1; $i >= 0; $i--) {
2675
						$data .= substr($atom_data, $offset + ($i * 2), 2);
2676
					}
2677
					$data = getid3_lib::BigEndian2Int($data);
2678
					$offset += ($data_size * 2);
2679
					break;
2680 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...
2681
					$data = '';
2682
					for ($i = $data_size - 1; $i >= 0; $i--) {
2683
						$data .= substr($atom_data, $offset + ($i * 4), 4);
2684
					}
2685
					$data = getid3_lib::BigEndian2Int($data);
2686
					$offset += ($data_size * 4);
2687
					break;
2688
				case 0x0005: // 0x0005 = float  (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together
2689
					$data = array();
2690
					for ($i = 0; $i < $data_size; $i++) {
2691
						$numerator    = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 0, 4));
2692
						$denomninator = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 4, 4));
2693
						if ($denomninator == 0) {
2694
							$data[$i] = false;
2695
						} else {
2696
							$data[$i] = (double) $numerator / $denomninator;
2697
						}
2698
					}
2699
					$offset += (8 * $data_size);
2700
					if (count($data) == 1) {
2701
						$data = $data[0];
2702
					}
2703
					break;
2704 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...
2705
					$data = substr($atom_data, $offset, $data_size * 1);
2706
					$offset += ($data_size * 1);
2707
					break;
2708 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...
2709
					$data = substr($atom_data, $offset, $data_size * 2);
2710
					$offset += ($data_size * 2);
2711
					break;
2712
				default:
2713
					echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br>';
2714
					break 2;
2715
			}
2716
2717
			switch ($record_type) {
2718
				case 0x00000011: // CreateDate
2719
				case 0x00000012: // DateTimeOriginal
2720
					$data = strtotime($data);
2721
					break;
2722
				case 0x0200001e: // ColorSpace
2723
					switch ($data) {
2724
						case 1:
2725
							$data = 'sRGB';
2726
							break;
2727
						case 2:
2728
							$data = 'Adobe RGB';
2729
							break;
2730
					}
2731
					break;
2732
				case 0x02000023: // PictureControlData
2733
					$PictureControlAdjust = array(0=>'default', 1=>'quick', 2=>'full');
2734
					$FilterEffect = array(0x80=>'off', 0x81=>'yellow', 0x82=>'orange',    0x83=>'red', 0x84=>'green',  0xff=>'n/a');
2735
					$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');
2736
					$data = array(
2737
						'PictureControlVersion'     =>                           substr($data,  0,  4),
2738
						'PictureControlName'        =>                     rtrim(substr($data,  4, 20), "\x00"),
2739
						'PictureControlBase'        =>                     rtrim(substr($data, 24, 20), "\x00"),
2740
						//'?'                       =>                           substr($data, 44,  4),
2741
						'PictureControlAdjust'      => $PictureControlAdjust[ord(substr($data, 48,  1))],
2742
						'PictureControlQuickAdjust' =>                       ord(substr($data, 49,  1)),
2743
						'Sharpness'                 =>                       ord(substr($data, 50,  1)),
2744
						'Contrast'                  =>                       ord(substr($data, 51,  1)),
2745
						'Brightness'                =>                       ord(substr($data, 52,  1)),
2746
						'Saturation'                =>                       ord(substr($data, 53,  1)),
2747
						'HueAdjustment'             =>                       ord(substr($data, 54,  1)),
2748
						'FilterEffect'              =>         $FilterEffect[ord(substr($data, 55,  1))],
2749
						'ToningEffect'              =>         $ToningEffect[ord(substr($data, 56,  1))],
2750
						'ToningSaturation'          =>                       ord(substr($data, 57,  1)),
2751
					);
2752
					break;
2753
				case 0x02000024: // WorldTime
2754
					// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#WorldTime
2755
					// timezone is stored as offset from GMT in minutes
2756
					$timezone = getid3_lib::BigEndian2Int(substr($data, 0, 2));
2757
					if ($timezone & 0x8000) {
2758
						$timezone = 0 - (0x10000 - $timezone);
2759
					}
2760
					$timezone /= 60;
2761
2762
					$dst = (bool) getid3_lib::BigEndian2Int(substr($data, 2, 1));
2763
					switch (getid3_lib::BigEndian2Int(substr($data, 3, 1))) {
2764
						case 2:
2765
							$datedisplayformat = 'D/M/Y'; break;
2766
						case 1:
2767
							$datedisplayformat = 'M/D/Y'; break;
2768
						case 0:
2769
						default:
2770
							$datedisplayformat = 'Y/M/D'; break;
2771
					}
2772
2773
					$data = array('timezone'=>floatval($timezone), 'dst'=>$dst, 'display'=>$datedisplayformat);
2774
					break;
2775
				case 0x02000083: // LensType
2776
					$data = array(
2777
						//'_'  => $data,
2778
						'mf' => (bool) ($data & 0x01),
2779
						'd'  => (bool) ($data & 0x02),
2780
						'g'  => (bool) ($data & 0x04),
2781
						'vr' => (bool) ($data & 0x08),
2782
					);
2783
					break;
2784
			}
2785
			$tag_name = (isset($NCTGtagName[$record_type]) ? $NCTGtagName[$record_type] : '0x'.str_pad(dechex($record_type), 8, '0', STR_PAD_LEFT));
2786
			$parsed[$tag_name] = $data;
2787
		}
2788
		return $parsed;
2789
	}
2790
2791
	/**
2792
	 * @param string $keyname
2793
	 * @param string|array $data
2794
	 * @param string $boxname
2795
	 *
2796
	 * @return bool
2797
	 */
2798
	public function CopyToAppropriateCommentsSection($keyname, $data, $boxname='') {
2799
		static $handyatomtranslatorarray = array();
2800
		if (empty($handyatomtranslatorarray)) {
2801
			// http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt
2802
			// http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt
2803
			// http://atomicparsley.sourceforge.net/mpeg-4files.html
2804
			// https://code.google.com/p/mp4v2/wiki/iTunesMetadata
2805
			$handyatomtranslatorarray["\xA9".'alb'] = 'album';               // iTunes 4.0
2806
			$handyatomtranslatorarray["\xA9".'ART'] = 'artist';
2807
			$handyatomtranslatorarray["\xA9".'art'] = 'artist';              // iTunes 4.0
2808
			$handyatomtranslatorarray["\xA9".'aut'] = 'author';
2809
			$handyatomtranslatorarray["\xA9".'cmt'] = 'comment';             // iTunes 4.0
2810
			$handyatomtranslatorarray["\xA9".'com'] = 'comment';
2811
			$handyatomtranslatorarray["\xA9".'cpy'] = 'copyright';
2812
			$handyatomtranslatorarray["\xA9".'day'] = 'creation_date';       // iTunes 4.0
2813
			$handyatomtranslatorarray["\xA9".'dir'] = 'director';
2814
			$handyatomtranslatorarray["\xA9".'ed1'] = 'edit1';
2815
			$handyatomtranslatorarray["\xA9".'ed2'] = 'edit2';
2816
			$handyatomtranslatorarray["\xA9".'ed3'] = 'edit3';
2817
			$handyatomtranslatorarray["\xA9".'ed4'] = 'edit4';
2818
			$handyatomtranslatorarray["\xA9".'ed5'] = 'edit5';
2819
			$handyatomtranslatorarray["\xA9".'ed6'] = 'edit6';
2820
			$handyatomtranslatorarray["\xA9".'ed7'] = 'edit7';
2821
			$handyatomtranslatorarray["\xA9".'ed8'] = 'edit8';
2822
			$handyatomtranslatorarray["\xA9".'ed9'] = 'edit9';
2823
			$handyatomtranslatorarray["\xA9".'enc'] = 'encoded_by';
2824
			$handyatomtranslatorarray["\xA9".'fmt'] = 'format';
2825
			$handyatomtranslatorarray["\xA9".'gen'] = 'genre';               // iTunes 4.0
2826
			$handyatomtranslatorarray["\xA9".'grp'] = 'grouping';            // iTunes 4.2
2827
			$handyatomtranslatorarray["\xA9".'hst'] = 'host_computer';
2828
			$handyatomtranslatorarray["\xA9".'inf'] = 'information';
2829
			$handyatomtranslatorarray["\xA9".'lyr'] = 'lyrics';              // iTunes 5.0
2830
			$handyatomtranslatorarray["\xA9".'mak'] = 'make';
2831
			$handyatomtranslatorarray["\xA9".'mod'] = 'model';
2832
			$handyatomtranslatorarray["\xA9".'nam'] = 'title';               // iTunes 4.0
2833
			$handyatomtranslatorarray["\xA9".'ope'] = 'composer';
2834
			$handyatomtranslatorarray["\xA9".'prd'] = 'producer';
2835
			$handyatomtranslatorarray["\xA9".'PRD'] = 'product';
2836
			$handyatomtranslatorarray["\xA9".'prf'] = 'performers';
2837
			$handyatomtranslatorarray["\xA9".'req'] = 'system_requirements';
2838
			$handyatomtranslatorarray["\xA9".'src'] = 'source_credit';
2839
			$handyatomtranslatorarray["\xA9".'swr'] = 'software';
2840
			$handyatomtranslatorarray["\xA9".'too'] = 'encoding_tool';       // iTunes 4.0
2841
			$handyatomtranslatorarray["\xA9".'trk'] = 'track_number';
2842
			$handyatomtranslatorarray["\xA9".'url'] = 'url';
2843
			$handyatomtranslatorarray["\xA9".'wrn'] = 'warning';
2844
			$handyatomtranslatorarray["\xA9".'wrt'] = 'composer';
2845
			$handyatomtranslatorarray['aART'] = 'album_artist';
2846
			$handyatomtranslatorarray['apID'] = 'purchase_account';
2847
			$handyatomtranslatorarray['catg'] = 'category';            // iTunes 4.9
2848
			$handyatomtranslatorarray['covr'] = 'picture';             // iTunes 4.0
2849
			$handyatomtranslatorarray['cpil'] = 'compilation';         // iTunes 4.0
2850
			$handyatomtranslatorarray['cprt'] = 'copyright';           // iTunes 4.0?
2851
			$handyatomtranslatorarray['desc'] = 'description';         // iTunes 5.0
2852
			$handyatomtranslatorarray['disk'] = 'disc_number';         // iTunes 4.0
2853
			$handyatomtranslatorarray['egid'] = 'episode_guid';        // iTunes 4.9
2854
			$handyatomtranslatorarray['gnre'] = 'genre';               // iTunes 4.0
2855
			$handyatomtranslatorarray['hdvd'] = 'hd_video';            // iTunes 4.0
2856
			$handyatomtranslatorarray['ldes'] = 'description_long';    //
2857
			$handyatomtranslatorarray['keyw'] = 'keyword';             // iTunes 4.9
2858
			$handyatomtranslatorarray['pcst'] = 'podcast';             // iTunes 4.9
2859
			$handyatomtranslatorarray['pgap'] = 'gapless_playback';    // iTunes 7.0
2860
			$handyatomtranslatorarray['purd'] = 'purchase_date';       // iTunes 6.0.2
2861
			$handyatomtranslatorarray['purl'] = 'podcast_url';         // iTunes 4.9
2862
			$handyatomtranslatorarray['rtng'] = 'rating';              // iTunes 4.0
2863
			$handyatomtranslatorarray['soaa'] = 'sort_album_artist';   //
2864
			$handyatomtranslatorarray['soal'] = 'sort_album';          //
2865
			$handyatomtranslatorarray['soar'] = 'sort_artist';         //
2866
			$handyatomtranslatorarray['soco'] = 'sort_composer';       //
2867
			$handyatomtranslatorarray['sonm'] = 'sort_title';          //
2868
			$handyatomtranslatorarray['sosn'] = 'sort_show';           //
2869
			$handyatomtranslatorarray['stik'] = 'stik';                // iTunes 4.9
2870
			$handyatomtranslatorarray['tmpo'] = 'bpm';                 // iTunes 4.0
2871
			$handyatomtranslatorarray['trkn'] = 'track_number';        // iTunes 4.0
2872
			$handyatomtranslatorarray['tven'] = 'tv_episode_id';       //
2873
			$handyatomtranslatorarray['tves'] = 'tv_episode';          // iTunes 6.0
2874
			$handyatomtranslatorarray['tvnn'] = 'tv_network_name';     // iTunes 6.0
2875
			$handyatomtranslatorarray['tvsh'] = 'tv_show_name';        // iTunes 6.0
2876
			$handyatomtranslatorarray['tvsn'] = 'tv_season';           // iTunes 6.0
2877
2878
			// boxnames:
2879
			/*
2880
			$handyatomtranslatorarray['iTunSMPB']                    = 'iTunSMPB';
2881
			$handyatomtranslatorarray['iTunNORM']                    = 'iTunNORM';
2882
			$handyatomtranslatorarray['Encoding Params']             = 'Encoding Params';
2883
			$handyatomtranslatorarray['replaygain_track_gain']       = 'replaygain_track_gain';
2884
			$handyatomtranslatorarray['replaygain_track_peak']       = 'replaygain_track_peak';
2885
			$handyatomtranslatorarray['replaygain_track_minmax']     = 'replaygain_track_minmax';
2886
			$handyatomtranslatorarray['MusicIP PUID']                = 'MusicIP PUID';
2887
			$handyatomtranslatorarray['MusicBrainz Artist Id']       = 'MusicBrainz Artist Id';
2888
			$handyatomtranslatorarray['MusicBrainz Album Id']        = 'MusicBrainz Album Id';
2889
			$handyatomtranslatorarray['MusicBrainz Album Artist Id'] = 'MusicBrainz Album Artist Id';
2890
			$handyatomtranslatorarray['MusicBrainz Track Id']        = 'MusicBrainz Track Id';
2891
			$handyatomtranslatorarray['MusicBrainz Disc Id']         = 'MusicBrainz Disc Id';
2892
2893
			// http://age.hobba.nl/audio/tag_frame_reference.html
2894
			$handyatomtranslatorarray['PLAY_COUNTER']                = 'play_counter'; // Foobar2000 - https://www.getid3.org/phpBB3/viewtopic.php?t=1355
2895
			$handyatomtranslatorarray['MEDIATYPE']                   = 'mediatype';    // Foobar2000 - https://www.getid3.org/phpBB3/viewtopic.php?t=1355
2896
			*/
2897
		}
2898
		$info = &$this->getid3->info;
2899
		$comment_key = '';
2900
		if ($boxname && ($boxname != $keyname)) {
2901
			$comment_key = (isset($handyatomtranslatorarray[$boxname]) ? $handyatomtranslatorarray[$boxname] : $boxname);
2902
		} elseif (isset($handyatomtranslatorarray[$keyname])) {
2903
			$comment_key = $handyatomtranslatorarray[$keyname];
2904
		}
2905
		if ($comment_key) {
2906
			if ($comment_key == 'picture') {
2907
				// already copied directly into [comments][picture] elsewhere, do not re-copy here
2908
				return true;
2909
			}
2910
			$gooddata = array($data);
2911
			if ($comment_key == 'genre') {
2912
				// some other taggers separate multiple genres with semicolon, e.g. "Heavy Metal;Thrash Metal;Metal"
2913
				$gooddata = explode(';', $data);
2914
			}
2915
			foreach ($gooddata as $data) {
2916
				if (!empty($info['quicktime']['comments'][$comment_key]) && in_array($data, $info['quicktime']['comments'][$comment_key], true)) {
2917
					// avoid duplicate copies of identical data
2918
					continue;
2919
				}
2920
				$info['quicktime']['comments'][$comment_key][] = $data;
2921
			}
2922
		}
2923
		return true;
2924
	}
2925
2926
	/**
2927
	 * @param string $lstring
2928
	 * @param int    $count
2929
	 *
2930
	 * @return string
2931
	 */
2932
	public function LociString($lstring, &$count) {
2933
		// Loci strings are UTF-8 or UTF-16 and null (x00/x0000) terminated. UTF-16 has a BOM
2934
		// Also need to return the number of bytes the string occupied so additional fields can be extracted
2935
		$len = strlen($lstring);
2936
		if ($len == 0) {
2937
			$count = 0;
2938
			return '';
2939
		}
2940
		if ($lstring[0] == "\x00") {
2941
			$count = 1;
2942
			return '';
2943
		}
2944
		// check for BOM
2945
		if (($len > 2) && ((($lstring[0] == "\xFE") && ($lstring[1] == "\xFF")) || (($lstring[0] == "\xFF") && ($lstring[1] == "\xFE")))) {
2946
			// UTF-16
2947 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...
2948
				$count = strlen($lmatches[1]) * 2 + 2; //account for 2 byte characters and trailing \x0000
2949
				return getid3_lib::iconv_fallback_utf16_utf8($lmatches[1]);
2950
			} else {
2951
				return '';
2952
			}
2953
		}
2954
		// UTF-8
2955 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...
2956
			$count = strlen($lmatches[1]) + 1; //account for trailing \x00
2957
			return $lmatches[1];
2958
		}
2959
		return '';
2960
	}
2961
2962
	/**
2963
	 * @param string $nullterminatedstring
2964
	 *
2965
	 * @return string
2966
	 */
2967 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...
2968
		// remove the single null terminator on null terminated strings
2969
		if (substr($nullterminatedstring, strlen($nullterminatedstring) - 1, 1) === "\x00") {
2970
			return substr($nullterminatedstring, 0, strlen($nullterminatedstring) - 1);
2971
		}
2972
		return $nullterminatedstring;
2973
	}
2974
2975
	/**
2976
	 * @param string $pascalstring
2977
	 *
2978
	 * @return string
2979
	 */
2980
	public function Pascal2String($pascalstring) {
2981
		// Pascal strings have 1 unsigned byte at the beginning saying how many chars (1-255) are in the string
2982
		return substr($pascalstring, 1);
2983
	}
2984
2985
	/**
2986
	 * @param string $pascalstring
2987
	 *
2988
	 * @return string
2989
	 */
2990
	public function MaybePascal2String($pascalstring) {
2991
		// Pascal strings have 1 unsigned byte at the beginning saying how many chars (1-255) are in the string
2992
		// Check if string actually is in this format or written incorrectly, straight string, or null-terminated string
2993
		if (ord(substr($pascalstring, 0, 1)) == (strlen($pascalstring) - 1)) {
2994
			return substr($pascalstring, 1);
2995
		} elseif (substr($pascalstring, -1, 1) == "\x00") {
2996
			// appears to be null-terminated instead of Pascal-style
2997
			return substr($pascalstring, 0, -1);
2998
		}
2999
		return $pascalstring;
3000
	}
3001
3002
3003
	/**
3004
	 * Helper functions for m4b audiobook chapters
3005
	 * code by Steffen Hartmann 2015-Nov-08.
3006
	 *
3007
	 * @param array  $info
3008
	 * @param string $tag
3009
	 * @param string $history
3010
	 * @param array  $result
3011
	 */
3012
	public function search_tag_by_key($info, $tag, $history, &$result) {
3013
		foreach ($info as $key => $value) {
3014
			$key_history = $history.'/'.$key;
3015
			if ($key === $tag) {
3016
				$result[] = array($key_history, $info);
3017
			} else {
3018
				if (is_array($value)) {
3019
					$this->search_tag_by_key($value, $tag, $key_history, $result);
3020
				}
3021
			}
3022
		}
3023
	}
3024
3025
	/**
3026
	 * @param array  $info
3027
	 * @param string $k
3028
	 * @param string $v
3029
	 * @param string $history
3030
	 * @param array  $result
3031
	 */
3032
	public function search_tag_by_pair($info, $k, $v, $history, &$result) {
3033
		foreach ($info as $key => $value) {
3034
			$key_history = $history.'/'.$key;
3035
			if (($key === $k) && ($value === $v)) {
3036
				$result[] = array($key_history, $info);
3037
			} else {
3038
				if (is_array($value)) {
3039
					$this->search_tag_by_pair($value, $k, $v, $key_history, $result);
3040
				}
3041
			}
3042
		}
3043
	}
3044
3045
	/**
3046
	 * @param array $info
3047
	 *
3048
	 * @return array
3049
	 */
3050
	public function quicktime_time_to_sample_table($info) {
3051
		$res = array();
3052
		$this->search_tag_by_pair($info['quicktime']['moov'], 'name', 'stbl', 'quicktime/moov', $res);
3053
		foreach ($res as $value) {
3054
			$stbl_res = array();
3055
			$this->search_tag_by_pair($value[1], 'data_format', 'text', $value[0], $stbl_res);
3056
			if (count($stbl_res) > 0) {
3057
				$stts_res = array();
3058
				$this->search_tag_by_key($value[1], 'time_to_sample_table', $value[0], $stts_res);
3059
				if (count($stts_res) > 0) {
3060
					return $stts_res[0][1]['time_to_sample_table'];
3061
				}
3062
			}
3063
		}
3064
		return array();
3065
	}
3066
3067
	/**
3068
	 * @param array $info
3069
	 *
3070
	 * @return int
3071
	 */
3072
	public function quicktime_bookmark_time_scale($info) {
3073
		$time_scale = '';
3074
		$ts_prefix_len = 0;
3075
		$res = array();
3076
		$this->search_tag_by_pair($info['quicktime']['moov'], 'name', 'stbl', 'quicktime/moov', $res);
3077
		foreach ($res as $value) {
3078
			$stbl_res = array();
3079
			$this->search_tag_by_pair($value[1], 'data_format', 'text', $value[0], $stbl_res);
3080
			if (count($stbl_res) > 0) {
3081
				$ts_res = array();
3082
				$this->search_tag_by_key($info['quicktime']['moov'], 'time_scale', 'quicktime/moov', $ts_res);
3083
				foreach ($ts_res as $sub_value) {
3084
					$prefix = substr($sub_value[0], 0, -12);
3085
					if ((substr($stbl_res[0][0], 0, strlen($prefix)) === $prefix) && ($ts_prefix_len < strlen($prefix))) {
3086
						$time_scale = $sub_value[1]['time_scale'];
3087
						$ts_prefix_len = strlen($prefix);
3088
					}
3089
				}
3090
			}
3091
		}
3092
		return $time_scale;
3093
	}
3094
	/*
3095
	// END helper functions for m4b audiobook chapters
3096
	*/
3097
3098
3099
}
3100