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

getid3_id3v2::RemoveStringTerminator()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 2
dl 0
loc 9
rs 9.9666
c 0
b 0
f 0
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.tag.id3v2.php                                        //
12
// module for analyzing ID3v2 tags                             //
13
// dependencies: module.tag.id3v1.php                          //
14
//                                                            ///
15
/////////////////////////////////////////////////////////////////
16
17
getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v1.php', __FILE__, true);
18
19
class getid3_id3v2 extends getid3_handler
20
{
21
	public $StartingOffset = 0;
22
23
	/**
24
	 * @return bool
25
	 */
26
	public function Analyze() {
27
		$info = &$this->getid3->info;
28
29
		//    Overall tag structure:
30
		//        +-----------------------------+
31
		//        |      Header (10 bytes)      |
32
		//        +-----------------------------+
33
		//        |       Extended Header       |
34
		//        | (variable length, OPTIONAL) |
35
		//        +-----------------------------+
36
		//        |   Frames (variable length)  |
37
		//        +-----------------------------+
38
		//        |           Padding           |
39
		//        | (variable length, OPTIONAL) |
40
		//        +-----------------------------+
41
		//        | Footer (10 bytes, OPTIONAL) |
42
		//        +-----------------------------+
43
44
		//    Header
45
		//        ID3v2/file identifier      "ID3"
46
		//        ID3v2 version              $04 00
47
		//        ID3v2 flags                (%ab000000 in v2.2, %abc00000 in v2.3, %abcd0000 in v2.4.x)
48
		//        ID3v2 size             4 * %0xxxxxxx
49
50
51
		// shortcuts
52
		$info['id3v2']['header'] = true;
53
		$thisfile_id3v2                  = &$info['id3v2'];
54
		$thisfile_id3v2['flags']         =  array();
55
		$thisfile_id3v2_flags            = &$thisfile_id3v2['flags'];
56
57
58
		$this->fseek($this->StartingOffset);
59
		$header = $this->fread(10);
60
		if (substr($header, 0, 3) == 'ID3'  &&  strlen($header) == 10) {
61
62
			$thisfile_id3v2['majorversion'] = ord($header[3]);
63
			$thisfile_id3v2['minorversion'] = ord($header[4]);
64
65
			// shortcut
66
			$id3v2_majorversion = &$thisfile_id3v2['majorversion'];
67
68
		} else {
69
70
			unset($info['id3v2']);
71
			return false;
72
73
		}
74
75
		if ($id3v2_majorversion > 4) { // this script probably won't correctly parse ID3v2.5.x and above (if it ever exists)
76
77
			$this->error('this script only parses up to ID3v2.4.x - this tag is ID3v2.'.$id3v2_majorversion.'.'.$thisfile_id3v2['minorversion']);
78
			return false;
79
80
		}
81
82
		$id3_flags = ord($header[5]);
83
		switch ($id3v2_majorversion) {
84
			case 2:
85
				// %ab000000 in v2.2
86
				$thisfile_id3v2_flags['unsynch']     = (bool) ($id3_flags & 0x80); // a - Unsynchronisation
87
				$thisfile_id3v2_flags['compression'] = (bool) ($id3_flags & 0x40); // b - Compression
88
				break;
89
90
			case 3:
91
				// %abc00000 in v2.3
92
				$thisfile_id3v2_flags['unsynch']     = (bool) ($id3_flags & 0x80); // a - Unsynchronisation
93
				$thisfile_id3v2_flags['exthead']     = (bool) ($id3_flags & 0x40); // b - Extended header
94
				$thisfile_id3v2_flags['experim']     = (bool) ($id3_flags & 0x20); // c - Experimental indicator
95
				break;
96
97
			case 4:
98
				// %abcd0000 in v2.4
99
				$thisfile_id3v2_flags['unsynch']     = (bool) ($id3_flags & 0x80); // a - Unsynchronisation
100
				$thisfile_id3v2_flags['exthead']     = (bool) ($id3_flags & 0x40); // b - Extended header
101
				$thisfile_id3v2_flags['experim']     = (bool) ($id3_flags & 0x20); // c - Experimental indicator
102
				$thisfile_id3v2_flags['isfooter']    = (bool) ($id3_flags & 0x10); // d - Footer present
103
				break;
104
		}
105
106
		$thisfile_id3v2['headerlength'] = getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length
0 ignored issues
show
Documentation introduced by
1 is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
107
108
		$thisfile_id3v2['tag_offset_start'] = $this->StartingOffset;
109
		$thisfile_id3v2['tag_offset_end']   = $thisfile_id3v2['tag_offset_start'] + $thisfile_id3v2['headerlength'];
110
111
112
113
		// create 'encoding' key - used by getid3::HandleAllTags()
114
		// in ID3v2 every field can have it's own encoding type
115
		// so force everything to UTF-8 so it can be handled consistantly
116
		$thisfile_id3v2['encoding'] = 'UTF-8';
117
118
119
	//    Frames
120
121
	//        All ID3v2 frames consists of one frame header followed by one or more
122
	//        fields containing the actual information. The header is always 10
123
	//        bytes and laid out as follows:
124
	//
125
	//        Frame ID      $xx xx xx xx  (four characters)
126
	//        Size      4 * %0xxxxxxx
127
	//        Flags         $xx xx
128
129
		$sizeofframes = $thisfile_id3v2['headerlength'] - 10; // not including 10-byte initial header
130
		if (!empty($thisfile_id3v2['exthead']['length'])) {
131
			$sizeofframes -= ($thisfile_id3v2['exthead']['length'] + 4);
132
		}
133
		if (!empty($thisfile_id3v2_flags['isfooter'])) {
134
			$sizeofframes -= 10; // footer takes last 10 bytes of ID3v2 header, after frame data, before audio
135
		}
136
		if ($sizeofframes > 0) {
137
138
			$framedata = $this->fread($sizeofframes); // read all frames from file into $framedata variable
139
140
			//    if entire frame data is unsynched, de-unsynch it now (ID3v2.3.x)
141
			if (!empty($thisfile_id3v2_flags['unsynch']) && ($id3v2_majorversion <= 3)) {
142
				$framedata = $this->DeUnsynchronise($framedata);
0 ignored issues
show
Security Bug introduced by
It seems like $framedata can also be of type false; however, getid3_id3v2::DeUnsynchronise() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
143
			}
144
			//        [in ID3v2.4.0] Unsynchronisation [S:6.1] is done on frame level, instead
145
			//        of on tag level, making it easier to skip frames, increasing the streamability
146
			//        of the tag. The unsynchronisation flag in the header [S:3.1] indicates that
147
			//        there exists an unsynchronised frame, while the new unsynchronisation flag in
148
			//        the frame header [S:4.1.2] indicates unsynchronisation.
149
150
151
			//$framedataoffset = 10 + ($thisfile_id3v2['exthead']['length'] ? $thisfile_id3v2['exthead']['length'] + 4 : 0); // how many bytes into the stream - start from after the 10-byte header (and extended header length+4, if present)
152
			$framedataoffset = 10; // how many bytes into the stream - start from after the 10-byte header
153
154
155
			//    Extended Header
156
			if (!empty($thisfile_id3v2_flags['exthead'])) {
157
				$extended_header_offset = 0;
158
159
				if ($id3v2_majorversion == 3) {
160
161
					// v2.3 definition:
162
					//Extended header size  $xx xx xx xx   // 32-bit integer
163
					//Extended Flags        $xx xx
164
					//     %x0000000 %00000000 // v2.3
165
					//     x - CRC data present
166
					//Size of padding       $xx xx xx xx
167
168
					$thisfile_id3v2['exthead']['length'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4), 0);
0 ignored issues
show
Documentation introduced by
0 is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
169
					$extended_header_offset += 4;
170
171
					$thisfile_id3v2['exthead']['flag_bytes'] = 2;
172
					$thisfile_id3v2['exthead']['flag_raw'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $thisfile_id3v2['exthead']['flag_bytes']));
173
					$extended_header_offset += $thisfile_id3v2['exthead']['flag_bytes'];
174
175
					$thisfile_id3v2['exthead']['flags']['crc'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x8000);
176
177
					$thisfile_id3v2['exthead']['padding_size'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4));
178
					$extended_header_offset += 4;
179
180 View Code Duplication
					if ($thisfile_id3v2['exthead']['flags']['crc']) {
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...
181
						$thisfile_id3v2['exthead']['flag_data']['crc'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4));
182
						$extended_header_offset += 4;
183
					}
184
					$extended_header_offset += $thisfile_id3v2['exthead']['padding_size'];
185
186
				} elseif ($id3v2_majorversion == 4) {
187
188
					// v2.4 definition:
189
					//Extended header size   4 * %0xxxxxxx // 28-bit synchsafe integer
190
					//Number of flag bytes       $01
191
					//Extended Flags             $xx
192
					//     %0bcd0000 // v2.4
193
					//     b - Tag is an update
194
					//         Flag data length       $00
195
					//     c - CRC data present
196
					//         Flag data length       $05
197
					//         Total frame CRC    5 * %0xxxxxxx
198
					//     d - Tag restrictions
199
					//         Flag data length       $01
200
201
					$thisfile_id3v2['exthead']['length'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4), true);
202
					$extended_header_offset += 4;
203
204
					$thisfile_id3v2['exthead']['flag_bytes'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should always be 1
205
					$extended_header_offset += 1;
206
207
					$thisfile_id3v2['exthead']['flag_raw'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $thisfile_id3v2['exthead']['flag_bytes']));
208
					$extended_header_offset += $thisfile_id3v2['exthead']['flag_bytes'];
209
210
					$thisfile_id3v2['exthead']['flags']['update']       = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x40);
211
					$thisfile_id3v2['exthead']['flags']['crc']          = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x20);
212
					$thisfile_id3v2['exthead']['flags']['restrictions'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x10);
213
214
					if ($thisfile_id3v2['exthead']['flags']['update']) {
215
						$ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should be 0
0 ignored issues
show
Unused Code introduced by
$ext_header_chunk_length 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...
216
						$extended_header_offset += 1;
217
					}
218
219
					if ($thisfile_id3v2['exthead']['flags']['crc']) {
220
						$ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should be 5
221
						$extended_header_offset += 1;
222
						$thisfile_id3v2['exthead']['flag_data']['crc'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $ext_header_chunk_length), true, false);
223
						$extended_header_offset += $ext_header_chunk_length;
224
					}
225
226
					if ($thisfile_id3v2['exthead']['flags']['restrictions']) {
227
						$ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should be 1
0 ignored issues
show
Unused Code introduced by
$ext_header_chunk_length 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...
228
						$extended_header_offset += 1;
229
230
						// %ppqrrstt
231
						$restrictions_raw = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1));
232
						$extended_header_offset += 1;
233
						$thisfile_id3v2['exthead']['flags']['restrictions']['tagsize']  = ($restrictions_raw & 0xC0) >> 6; // p - Tag size restrictions
234
						$thisfile_id3v2['exthead']['flags']['restrictions']['textenc']  = ($restrictions_raw & 0x20) >> 5; // q - Text encoding restrictions
235
						$thisfile_id3v2['exthead']['flags']['restrictions']['textsize'] = ($restrictions_raw & 0x18) >> 3; // r - Text fields size restrictions
236
						$thisfile_id3v2['exthead']['flags']['restrictions']['imgenc']   = ($restrictions_raw & 0x04) >> 2; // s - Image encoding restrictions
237
						$thisfile_id3v2['exthead']['flags']['restrictions']['imgsize']  = ($restrictions_raw & 0x03) >> 0; // t - Image size restrictions
238
239
						$thisfile_id3v2['exthead']['flags']['restrictions_text']['tagsize']  = $this->LookupExtendedHeaderRestrictionsTagSizeLimits($thisfile_id3v2['exthead']['flags']['restrictions']['tagsize']);
240
						$thisfile_id3v2['exthead']['flags']['restrictions_text']['textenc']  = $this->LookupExtendedHeaderRestrictionsTextEncodings($thisfile_id3v2['exthead']['flags']['restrictions']['textenc']);
241
						$thisfile_id3v2['exthead']['flags']['restrictions_text']['textsize'] = $this->LookupExtendedHeaderRestrictionsTextFieldSize($thisfile_id3v2['exthead']['flags']['restrictions']['textsize']);
242
						$thisfile_id3v2['exthead']['flags']['restrictions_text']['imgenc']   = $this->LookupExtendedHeaderRestrictionsImageEncoding($thisfile_id3v2['exthead']['flags']['restrictions']['imgenc']);
243
						$thisfile_id3v2['exthead']['flags']['restrictions_text']['imgsize']  = $this->LookupExtendedHeaderRestrictionsImageSizeSize($thisfile_id3v2['exthead']['flags']['restrictions']['imgsize']);
244
					}
245
246
					if ($thisfile_id3v2['exthead']['length'] != $extended_header_offset) {
247
						$this->warning('ID3v2.4 extended header length mismatch (expecting '.intval($thisfile_id3v2['exthead']['length']).', found '.intval($extended_header_offset).')');
248
					}
249
				}
250
251
				$framedataoffset += $extended_header_offset;
252
				$framedata = substr($framedata, $extended_header_offset);
253
			} // end extended header
254
255
256
			while (isset($framedata) && (strlen($framedata) > 0)) { // cycle through until no more frame data is left to parse
257
				if (strlen($framedata) <= $this->ID3v2HeaderLength($id3v2_majorversion)) {
258
					// insufficient room left in ID3v2 header for actual data - must be padding
259
					$thisfile_id3v2['padding']['start']  = $framedataoffset;
260
					$thisfile_id3v2['padding']['length'] = strlen($framedata);
261
					$thisfile_id3v2['padding']['valid']  = true;
262 View Code Duplication
					for ($i = 0; $i < $thisfile_id3v2['padding']['length']; $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...
263
						if ($framedata[$i] != "\x00") {
264
							$thisfile_id3v2['padding']['valid'] = false;
265
							$thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i;
266
							$this->warning('Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)');
267
							break;
268
						}
269
					}
270
					break; // skip rest of ID3v2 header
271
				}
272
				$frame_header = null;
273
				$frame_name   = null;
274
				$frame_size   = null;
275
				$frame_flags  = null;
276
				if ($id3v2_majorversion == 2) {
277
					// Frame ID  $xx xx xx (three characters)
278
					// Size      $xx xx xx (24-bit integer)
279
					// Flags     $xx xx
280
281
					$frame_header = substr($framedata, 0, 6); // take next 6 bytes for header
282
					$framedata    = substr($framedata, 6);    // and leave the rest in $framedata
283
					$frame_name   = substr($frame_header, 0, 3);
284
					$frame_size   = getid3_lib::BigEndian2Int(substr($frame_header, 3, 3), 0);
0 ignored issues
show
Documentation introduced by
0 is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
285
					$frame_flags  = 0; // not used for anything in ID3v2.2, just set to avoid E_NOTICEs
286
287
				} elseif ($id3v2_majorversion > 2) {
288
289
					// Frame ID  $xx xx xx xx (four characters)
290
					// Size      $xx xx xx xx (32-bit integer in v2.3, 28-bit synchsafe in v2.4+)
291
					// Flags     $xx xx
292
293
					$frame_header = substr($framedata, 0, 10); // take next 10 bytes for header
294
					$framedata    = substr($framedata, 10);    // and leave the rest in $framedata
295
296
					$frame_name = substr($frame_header, 0, 4);
297
					if ($id3v2_majorversion == 3) {
298
						$frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0); // 32-bit integer
0 ignored issues
show
Documentation introduced by
0 is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
299
					} else { // ID3v2.4+
300
						$frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 1); // 32-bit synchsafe integer (28-bit value)
0 ignored issues
show
Documentation introduced by
1 is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
301
					}
302
303
					if ($frame_size < (strlen($framedata) + 4)) {
304
						$nextFrameID = substr($framedata, $frame_size, 4);
305
						if ($this->IsValidID3v2FrameName($nextFrameID, $id3v2_majorversion)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->IsValidID3v2Frame...D, $id3v2_majorversion) of type integer|false is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
306
							// next frame is OK
307
						} elseif (($frame_name == "\x00".'MP3') || ($frame_name == "\x00\x00".'MP') || ($frame_name == ' MP3') || ($frame_name == 'MP3e')) {
308
							// MP3ext known broken frames - "ok" for the purposes of this test
309
						} elseif (($id3v2_majorversion == 4) && ($this->IsValidID3v2FrameName(substr($framedata, getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0), 4), 3))) {
0 ignored issues
show
Documentation introduced by
0 is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug Best Practice introduced by
The expression $this->IsValidID3v2Frame...ader, 4, 4), 0), 4), 3) of type integer|false is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
310
							$this->warning('ID3v2 tag written as ID3v2.4, but with non-synchsafe integers (ID3v2.3 style). Older versions of (Helium2; iTunes) are known culprits of this. Tag has been parsed as ID3v2.3');
311
							$id3v2_majorversion = 3;
312
							$frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0); // 32-bit integer
0 ignored issues
show
Documentation introduced by
0 is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
313
						}
314
					}
315
316
317
					$frame_flags = getid3_lib::BigEndian2Int(substr($frame_header, 8, 2));
318
				}
319
320
				if ((($id3v2_majorversion == 2) && ($frame_name == "\x00\x00\x00")) || ($frame_name == "\x00\x00\x00\x00")) {
321
					// padding encountered
322
323
					$thisfile_id3v2['padding']['start']  = $framedataoffset;
324
					$thisfile_id3v2['padding']['length'] = strlen($frame_header) + strlen($framedata);
325
					$thisfile_id3v2['padding']['valid']  = true;
326
327
					$len = strlen($framedata);
328 View Code Duplication
					for ($i = 0; $i < $len; $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...
329
						if ($framedata[$i] != "\x00") {
330
							$thisfile_id3v2['padding']['valid'] = false;
331
							$thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i;
332
							$this->warning('Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)');
333
							break;
334
						}
335
					}
336
					break; // skip rest of ID3v2 header
337
				}
338
339
				if ($iTunesBrokenFrameNameFixed = self::ID3v22iTunesBrokenFrameName($frame_name)) {
340
					$this->warning('error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))). [Note: this particular error has been known to happen with tags edited by iTunes (versions "X v2.0.3", "v3.0.1", "v7.0.0.70" are known-guilty, probably others too)]. Translated frame name from "'.str_replace("\x00", ' ', $frame_name).'" to "'.$iTunesBrokenFrameNameFixed.'" for parsing.');
341
					$frame_name = $iTunesBrokenFrameNameFixed;
342
				}
343
				if (($frame_size <= strlen($framedata)) && ($this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion))) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->IsValidID3v2Frame...e, $id3v2_majorversion) of type integer|false is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
344
345
					unset($parsedFrame);
346
					$parsedFrame['frame_name']      = $frame_name;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$parsedFrame was never initialized. Although not strictly required by PHP, it is generally a good practice to add $parsedFrame = 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...
347
					$parsedFrame['frame_flags_raw'] = $frame_flags;
0 ignored issues
show
Bug introduced by
The variable $parsedFrame does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
348
					$parsedFrame['data']            = substr($framedata, 0, $frame_size);
349
					$parsedFrame['datalength']      = getid3_lib::CastAsInt($frame_size);
0 ignored issues
show
Bug introduced by
It seems like $frame_size can also be of type false or null; however, getid3_lib::CastAsInt() does only seem to accept integer|double, 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...
350
					$parsedFrame['dataoffset']      = $framedataoffset;
351
352
					$this->ParseID3v2Frame($parsedFrame);
353
					$thisfile_id3v2[$frame_name][] = $parsedFrame;
354
355
					$framedata = substr($framedata, $frame_size);
356
357
				} else { // invalid frame length or FrameID
358
359
					if ($frame_size <= strlen($framedata)) {
360
361
						if ($this->IsValidID3v2FrameName(substr($framedata, $frame_size, 4), $id3v2_majorversion)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->IsValidID3v2Frame...), $id3v2_majorversion) of type integer|false is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
362
363
							// next frame is valid, just skip the current frame
364
							$framedata = substr($framedata, $frame_size);
365
							$this->warning('Next ID3v2 frame is valid, skipping current frame.');
366
367
						} else {
368
369
							// next frame is invalid too, abort processing
370
							//unset($framedata);
371
							$framedata = null;
372
							$this->error('Next ID3v2 frame is also invalid, aborting processing.');
373
374
						}
375
376
					} elseif ($frame_size == strlen($framedata)) {
377
378
						// this is the last frame, just skip
379
						$this->warning('This was the last ID3v2 frame.');
380
381
					} else {
382
383
						// next frame is invalid too, abort processing
384
						//unset($framedata);
385
						$framedata = null;
386
						$this->warning('Invalid ID3v2 frame size, aborting.');
387
388
					}
389
					if (!$this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->IsValidID3v2Frame...e, $id3v2_majorversion) of type integer|false is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
390
391
						switch ($frame_name) {
392
							case "\x00\x00".'MP':
393
							case "\x00".'MP3':
394
							case ' MP3':
395
							case 'MP3e':
396
							case "\x00".'MP':
397
							case ' MP':
398 View Code Duplication
							case 'MP3':
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...
399
								$this->warning('error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))). [Note: this particular error has been known to happen with tags edited by "MP3ext (www.mutschler.de/mp3ext/)"]');
400
								break;
401
402 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...
403
								$this->warning('error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))).');
404
								break;
405
						}
406
407
					} elseif (!isset($framedata) || ($frame_size > strlen($framedata))) {
408
409
						$this->error('error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: $frame_size ('.$frame_size.') > strlen($framedata) ('.(isset($framedata) ? strlen($framedata) : 'null').')).');
410
411
					} else {
412
413
						$this->error('error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag).');
414
415
					}
416
417
				}
418
				$framedataoffset += ($frame_size + $this->ID3v2HeaderLength($id3v2_majorversion));
419
420
			}
421
422
		}
423
424
425
	//    Footer
426
427
	//    The footer is a copy of the header, but with a different identifier.
428
	//        ID3v2 identifier           "3DI"
429
	//        ID3v2 version              $04 00
430
	//        ID3v2 flags                %abcd0000
431
	//        ID3v2 size             4 * %0xxxxxxx
432
433
		if (isset($thisfile_id3v2_flags['isfooter']) && $thisfile_id3v2_flags['isfooter']) {
434
			$footer = $this->fread(10);
435
			if (substr($footer, 0, 3) == '3DI') {
436
				$thisfile_id3v2['footer'] = true;
437
				$thisfile_id3v2['majorversion_footer'] = ord($footer[3]);
438
				$thisfile_id3v2['minorversion_footer'] = ord($footer[4]);
439
			}
440
			if ($thisfile_id3v2['majorversion_footer'] <= 4) {
441
				$id3_flags = ord($footer[5]);
442
				$thisfile_id3v2_flags['unsynch_footer']  = (bool) ($id3_flags & 0x80);
443
				$thisfile_id3v2_flags['extfoot_footer']  = (bool) ($id3_flags & 0x40);
444
				$thisfile_id3v2_flags['experim_footer']  = (bool) ($id3_flags & 0x20);
445
				$thisfile_id3v2_flags['isfooter_footer'] = (bool) ($id3_flags & 0x10);
446
447
				$thisfile_id3v2['footerlength'] = getid3_lib::BigEndian2Int(substr($footer, 6, 4), 1);
0 ignored issues
show
Documentation introduced by
1 is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
448
			}
449
		} // end footer
450
451
		if (isset($thisfile_id3v2['comments']['genre'])) {
452
			$genres = array();
453
			foreach ($thisfile_id3v2['comments']['genre'] as $key => $value) {
454
				foreach ($this->ParseID3v2GenreString($value) as $genre) {
455
					$genres[] = $genre;
456
				}
457
			}
458
			$thisfile_id3v2['comments']['genre'] = array_unique($genres);
459
			unset($key, $value, $genres, $genre);
460
		}
461
462
		if (isset($thisfile_id3v2['comments']['track_number'])) {
463
			foreach ($thisfile_id3v2['comments']['track_number'] as $key => $value) {
464
				if (strstr($value, '/')) {
465
					list($thisfile_id3v2['comments']['track_number'][$key], $thisfile_id3v2['comments']['totaltracks'][$key]) = explode('/', $thisfile_id3v2['comments']['track_number'][$key]);
466
				}
467
			}
468
		}
469
470
		if (!isset($thisfile_id3v2['comments']['year']) && !empty($thisfile_id3v2['comments']['recording_time'][0]) && preg_match('#^([0-9]{4})#', trim($thisfile_id3v2['comments']['recording_time'][0]), $matches)) {
471
			$thisfile_id3v2['comments']['year'] = array($matches[1]);
472
		}
473
474
475
		if (!empty($thisfile_id3v2['TXXX'])) {
476
			// MediaMonkey does this, maybe others: write a blank RGAD frame, but put replay-gain adjustment values in TXXX frames
477
			foreach ($thisfile_id3v2['TXXX'] as $txxx_array) {
478
				switch ($txxx_array['description']) {
479 View Code Duplication
					case 'replaygain_track_gain':
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...
480
						if (empty($info['replay_gain']['track']['adjustment']) && !empty($txxx_array['data'])) {
481
							$info['replay_gain']['track']['adjustment'] = floatval(trim(str_replace('dB', '', $txxx_array['data'])));
482
						}
483
						break;
484
					case 'replaygain_track_peak':
485
						if (empty($info['replay_gain']['track']['peak']) && !empty($txxx_array['data'])) {
486
							$info['replay_gain']['track']['peak'] = floatval($txxx_array['data']);
487
						}
488
						break;
489 View Code Duplication
					case 'replaygain_album_gain':
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...
490
						if (empty($info['replay_gain']['album']['adjustment']) && !empty($txxx_array['data'])) {
491
							$info['replay_gain']['album']['adjustment'] = floatval(trim(str_replace('dB', '', $txxx_array['data'])));
492
						}
493
						break;
494
				}
495
			}
496
		}
497
498
499
		// Set avdataoffset
500
		$info['avdataoffset'] = $thisfile_id3v2['headerlength'];
501
		if (isset($thisfile_id3v2['footer'])) {
502
			$info['avdataoffset'] += 10;
503
		}
504
505
		return true;
506
	}
507
508
	/**
509
	 * @param string $genrestring
510
	 *
511
	 * @return array
512
	 */
513
	public function ParseID3v2GenreString($genrestring) {
514
		// Parse genres into arrays of genreName and genreID
515
		// ID3v2.2.x, ID3v2.3.x: '(21)' or '(4)Eurodisco' or '(51)(39)' or '(55)((I think...)'
516
		// ID3v2.4.x: '21' $00 'Eurodisco' $00
517
		$clean_genres = array();
518
519
		// hack-fixes for some badly-written ID3v2.3 taggers, while trying not to break correctly-written tags
520
		if (($this->getid3->info['id3v2']['majorversion'] == 3) && !preg_match('#[\x00]#', $genrestring)) {
521
			// note: MusicBrainz Picard incorrectly stores plaintext genres separated by "/" when writing in ID3v2.3 mode, hack-fix here:
522
			// replace / with NULL, then replace back the two ID3v1 genres that legitimately have "/" as part of the single genre name
523
			if (preg_match('#/#', $genrestring)) {
524
				$genrestring = str_replace('/', "\x00", $genrestring);
525
				$genrestring = str_replace('Pop'."\x00".'Funk', 'Pop/Funk', $genrestring);
526
				$genrestring = str_replace('Rock'."\x00".'Rock', 'Folk/Rock', $genrestring);
527
			}
528
529
			// some other taggers separate multiple genres with semicolon, e.g. "Heavy Metal;Thrash Metal;Metal"
530
			if (preg_match('#;#', $genrestring)) {
531
				$genrestring = str_replace(';', "\x00", $genrestring);
532
			}
533
		}
534
535
536
		if (strpos($genrestring, "\x00") === false) {
537
			$genrestring = preg_replace('#\(([0-9]{1,3})\)#', '$1'."\x00", $genrestring);
538
		}
539
540
		$genre_elements = explode("\x00", $genrestring);
541
		foreach ($genre_elements as $element) {
542
			$element = trim($element);
543
			if ($element) {
544
				if (preg_match('#^[0-9]{1,3}$#', $element)) {
545
					$clean_genres[] = getid3_id3v1::LookupGenreName($element);
546
				} else {
547
					$clean_genres[] = str_replace('((', '(', $element);
548
				}
549
			}
550
		}
551
		return $clean_genres;
552
	}
553
554
	/**
555
	 * @param array $parsedFrame
556
	 *
557
	 * @return bool
558
	 */
559
	public function ParseID3v2Frame(&$parsedFrame) {
560
561
		// shortcuts
562
		$info = &$this->getid3->info;
563
		$id3v2_majorversion = $info['id3v2']['majorversion'];
564
565
		$parsedFrame['framenamelong']  = $this->FrameNameLongLookup($parsedFrame['frame_name']);
566
		if (empty($parsedFrame['framenamelong'])) {
567
			unset($parsedFrame['framenamelong']);
568
		}
569
		$parsedFrame['framenameshort'] = $this->FrameNameShortLookup($parsedFrame['frame_name']);
570
		if (empty($parsedFrame['framenameshort'])) {
571
			unset($parsedFrame['framenameshort']);
572
		}
573
574
		if ($id3v2_majorversion >= 3) { // frame flags are not part of the ID3v2.2 standard
575
			if ($id3v2_majorversion == 3) {
576
				//    Frame Header Flags
577
				//    %abc00000 %ijk00000
578
				$parsedFrame['flags']['TagAlterPreservation']  = (bool) ($parsedFrame['frame_flags_raw'] & 0x8000); // a - Tag alter preservation
579
				$parsedFrame['flags']['FileAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x4000); // b - File alter preservation
580
				$parsedFrame['flags']['ReadOnly']              = (bool) ($parsedFrame['frame_flags_raw'] & 0x2000); // c - Read only
581
				$parsedFrame['flags']['compression']           = (bool) ($parsedFrame['frame_flags_raw'] & 0x0080); // i - Compression
582
				$parsedFrame['flags']['Encryption']            = (bool) ($parsedFrame['frame_flags_raw'] & 0x0040); // j - Encryption
583
				$parsedFrame['flags']['GroupingIdentity']      = (bool) ($parsedFrame['frame_flags_raw'] & 0x0020); // k - Grouping identity
584
585
			} elseif ($id3v2_majorversion == 4) {
586
				//    Frame Header Flags
587
				//    %0abc0000 %0h00kmnp
588
				$parsedFrame['flags']['TagAlterPreservation']  = (bool) ($parsedFrame['frame_flags_raw'] & 0x4000); // a - Tag alter preservation
589
				$parsedFrame['flags']['FileAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x2000); // b - File alter preservation
590
				$parsedFrame['flags']['ReadOnly']              = (bool) ($parsedFrame['frame_flags_raw'] & 0x1000); // c - Read only
591
				$parsedFrame['flags']['GroupingIdentity']      = (bool) ($parsedFrame['frame_flags_raw'] & 0x0040); // h - Grouping identity
592
				$parsedFrame['flags']['compression']           = (bool) ($parsedFrame['frame_flags_raw'] & 0x0008); // k - Compression
593
				$parsedFrame['flags']['Encryption']            = (bool) ($parsedFrame['frame_flags_raw'] & 0x0004); // m - Encryption
594
				$parsedFrame['flags']['Unsynchronisation']     = (bool) ($parsedFrame['frame_flags_raw'] & 0x0002); // n - Unsynchronisation
595
				$parsedFrame['flags']['DataLengthIndicator']   = (bool) ($parsedFrame['frame_flags_raw'] & 0x0001); // p - Data length indicator
596
597
				// Frame-level de-unsynchronisation - ID3v2.4
598
				if ($parsedFrame['flags']['Unsynchronisation']) {
599
					$parsedFrame['data'] = $this->DeUnsynchronise($parsedFrame['data']);
600
				}
601
602 View Code Duplication
				if ($parsedFrame['flags']['DataLengthIndicator']) {
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...
603
					$parsedFrame['data_length_indicator'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 4), 1);
0 ignored issues
show
Documentation introduced by
1 is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
604
					$parsedFrame['data']                  =                           substr($parsedFrame['data'], 4);
605
				}
606
			}
607
608
			//    Frame-level de-compression
609
			if ($parsedFrame['flags']['compression']) {
610
				$parsedFrame['decompressed_size'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 4));
611
				if (!function_exists('gzuncompress')) {
612
					$this->warning('gzuncompress() support required to decompress ID3v2 frame "'.$parsedFrame['frame_name'].'"');
613
				} else {
614
					if ($decompresseddata = @gzuncompress(substr($parsedFrame['data'], 4))) {
615
					//if ($decompresseddata = @gzuncompress($parsedFrame['data'])) {
616
						$parsedFrame['data'] = $decompresseddata;
617
						unset($decompresseddata);
618
					} else {
619
						$this->warning('gzuncompress() failed on compressed contents of ID3v2 frame "'.$parsedFrame['frame_name'].'"');
620
					}
621
				}
622
			}
623
		}
624
625
		if (!empty($parsedFrame['flags']['DataLengthIndicator'])) {
626
			if ($parsedFrame['data_length_indicator'] != strlen($parsedFrame['data'])) {
627
				$this->warning('ID3v2 frame "'.$parsedFrame['frame_name'].'" should be '.$parsedFrame['data_length_indicator'].' bytes long according to DataLengthIndicator, but found '.strlen($parsedFrame['data']).' bytes of data');
628
			}
629
		}
630
631
		if (isset($parsedFrame['datalength']) && ($parsedFrame['datalength'] == 0)) {
632
633
			$warning = 'Frame "'.$parsedFrame['frame_name'].'" at offset '.$parsedFrame['dataoffset'].' has no data portion';
634
			switch ($parsedFrame['frame_name']) {
635
				case 'WCOM':
636
					$warning .= ' (this is known to happen with files tagged by RioPort)';
637
					break;
638
639
				default:
640
					break;
641
			}
642
			$this->warning($warning);
643
644
		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'UFID')) || // 4.1   UFID Unique file identifier
645
			(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'UFI'))) {  // 4.1   UFI  Unique file identifier
646
			//   There may be more than one 'UFID' frame in a tag,
647
			//   but only one with the same 'Owner identifier'.
648
			// <Header for 'Unique file identifier', ID: 'UFID'>
649
			// Owner identifier        <text string> $00
650
			// Identifier              <up to 64 bytes binary data>
651
			$exploded = explode("\x00", $parsedFrame['data'], 2);
652
			$parsedFrame['ownerid'] = (isset($exploded[0]) ? $exploded[0] : '');
653
			$parsedFrame['data']    = (isset($exploded[1]) ? $exploded[1] : '');
654
655
		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'TXXX')) || // 4.2.2 TXXX User defined text information frame
656
				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'TXX'))) {    // 4.2.2 TXX  User defined text information frame
657
			//   There may be more than one 'TXXX' frame in each tag,
658
			//   but only one with the same description.
659
			// <Header for 'User defined text information frame', ID: 'TXXX'>
660
			// Text encoding     $xx
661
			// Description       <text string according to encoding> $00 (00)
662
			// Value             <text string according to encoding>
663
664
			$frame_offset = 0;
665
			$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
666
			$frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
667 View Code Duplication
			if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 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...
668
				$this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding');
669
				$frame_textencoding_terminator = "\x00";
670
			}
671
			$frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
672 View Code Duplication
			if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
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...
673
				$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
674
			}
675
			$parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
676
			$parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
677
			$parsedFrame['encodingid']  = $frame_textencoding;
678
			$parsedFrame['encoding']    = $this->TextEncodingNameLookup($frame_textencoding);
679
680
			$parsedFrame['description'] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['description']));
681
			$parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
682
			$parsedFrame['data'] = $this->RemoveStringTerminator($parsedFrame['data'], $frame_textencoding_terminator);
683
			if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
684
				$commentkey = ($parsedFrame['description'] ? $parsedFrame['description'] : (isset($info['id3v2']['comments'][$parsedFrame['framenameshort']]) ? count($info['id3v2']['comments'][$parsedFrame['framenameshort']]) : 0));
685 View Code Duplication
				if (!isset($info['id3v2']['comments'][$parsedFrame['framenameshort']]) || !array_key_exists($commentkey, $info['id3v2']['comments'][$parsedFrame['framenameshort']])) {
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...
686
					$info['id3v2']['comments'][$parsedFrame['framenameshort']][$commentkey] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']));
687
				} else {
688
					$info['id3v2']['comments'][$parsedFrame['framenameshort']][]            = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']));
689
				}
690
			}
691
			//unset($parsedFrame['data']); do not unset, may be needed elsewhere, e.g. for replaygain
692
693
694
		} elseif ($parsedFrame['frame_name'][0] == 'T') { // 4.2. T??[?] Text information frame
695
			//   There may only be one text information frame of its kind in an tag.
696
			// <Header for 'Text information frame', ID: 'T000' - 'TZZZ',
697
			// excluding 'TXXX' described in 4.2.6.>
698
			// Text encoding                $xx
699
			// Information                  <text string(s) according to encoding>
700
701
			$frame_offset = 0;
702
			$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
703
			if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
704
				$this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding');
705
			}
706
707
			$parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
708
			$parsedFrame['data'] = $this->RemoveStringTerminator($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding));
709
710
			$parsedFrame['encodingid'] = $frame_textencoding;
711
			$parsedFrame['encoding']   = $this->TextEncodingNameLookup($frame_textencoding);
712
			if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
713
				// ID3v2.3 specs say that TPE1 (and others) can contain multiple artist values separated with /
714
				// This of course breaks when an artist name contains slash character, e.g. "AC/DC"
715
				// MP3tag (maybe others) implement alternative system where multiple artists are null-separated, which makes more sense
716
				// getID3 will split null-separated artists into multiple artists and leave slash-separated ones to the user
717
				switch ($parsedFrame['encoding']) {
718
					case 'UTF-16':
719
					case 'UTF-16BE':
720
					case 'UTF-16LE':
721
						$wordsize = 2;
722
						break;
723
					case 'ISO-8859-1':
724
					case 'UTF-8':
725
					default:
726
						$wordsize = 1;
727
						break;
728
				}
729
				$Txxx_elements = array();
730
				$Txxx_elements_start_offset = 0;
731
				for ($i = 0; $i < strlen($parsedFrame['data']); $i += $wordsize) {
732
					if (substr($parsedFrame['data'], $i, $wordsize) == str_repeat("\x00", $wordsize)) {
733
						$Txxx_elements[] = substr($parsedFrame['data'], $Txxx_elements_start_offset, $i - $Txxx_elements_start_offset);
734
						$Txxx_elements_start_offset = $i + $wordsize;
735
					}
736
				}
737
				$Txxx_elements[] = substr($parsedFrame['data'], $Txxx_elements_start_offset, $i - $Txxx_elements_start_offset);
738
				foreach ($Txxx_elements as $Txxx_element) {
739
					$string = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $Txxx_element);
740
					if (!empty($string)) {
741
						$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $string;
742
					}
743
				}
744
				unset($string, $wordsize, $i, $Txxx_elements, $Txxx_element, $Txxx_elements_start_offset);
745
			}
746
747
		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'WXXX')) || // 4.3.2 WXXX User defined URL link frame
748
				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'WXX'))) {    // 4.3.2 WXX  User defined URL link frame
749
			//   There may be more than one 'WXXX' frame in each tag,
750
			//   but only one with the same description
751
			// <Header for 'User defined URL link frame', ID: 'WXXX'>
752
			// Text encoding     $xx
753
			// Description       <text string according to encoding> $00 (00)
754
			// URL               <text string>
755
756
			$frame_offset = 0;
757
			$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
758
			$frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
759 View Code Duplication
			if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 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...
760
				$this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding');
761
				$frame_textencoding_terminator = "\x00";
762
			}
763
			$frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
764 View Code Duplication
			if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
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...
765
				$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
766
			}
767
			$parsedFrame['encodingid']  = $frame_textencoding;
768
			$parsedFrame['encoding']    = $this->TextEncodingNameLookup($frame_textencoding);
769
			$parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);           // according to the frame text encoding
770
			$parsedFrame['url']         = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator)); // always ISO-8859-1
771
			$parsedFrame['description'] = $this->RemoveStringTerminator($parsedFrame['description'], $frame_textencoding_terminator);
772
			$parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
773
774 View Code Duplication
			if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
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...
775
				$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback('ISO-8859-1', $info['id3v2']['encoding'], $parsedFrame['url']);
776
			}
777
			unset($parsedFrame['data']);
778
779
780
		} elseif ($parsedFrame['frame_name'][0] == 'W') { // 4.3. W??? URL link frames
781
			//   There may only be one URL link frame of its kind in a tag,
782
			//   except when stated otherwise in the frame description
783
			// <Header for 'URL link frame', ID: 'W000' - 'WZZZ', excluding 'WXXX'
784
			// described in 4.3.2.>
785
			// URL              <text string>
786
787
			$parsedFrame['url'] = trim($parsedFrame['data']); // always ISO-8859-1
788 View Code Duplication
			if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
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...
789
				$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback('ISO-8859-1', $info['id3v2']['encoding'], $parsedFrame['url']);
790
			}
791
			unset($parsedFrame['data']);
792
793
794
		} elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'IPLS')) || // 4.4  IPLS Involved people list (ID3v2.3 only)
795
				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'IPL'))) {     // 4.4  IPL  Involved people list (ID3v2.2 only)
796
			// http://id3.org/id3v2.3.0#sec4.4
797
			//   There may only be one 'IPL' frame in each tag
798
			// <Header for 'User defined URL link frame', ID: 'IPL'>
799
			// Text encoding     $xx
800
			// People list strings    <textstrings>
801
802
			$frame_offset = 0;
803
			$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
804
			if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
805
				$this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding');
806
			}
807
			$parsedFrame['encodingid'] = $frame_textencoding;
808
			$parsedFrame['encoding']   = $this->TextEncodingNameLookup($parsedFrame['encodingid']);
809
			$parsedFrame['data_raw']   = (string) substr($parsedFrame['data'], $frame_offset);
810
811
			// https://www.getid3.org/phpBB3/viewtopic.php?t=1369
812
			// "this tag typically contains null terminated strings, which are associated in pairs"
813
			// "there are users that use the tag incorrectly"
814
			$IPLS_parts = array();
815
			if (strpos($parsedFrame['data_raw'], "\x00") !== false) {
816
				$IPLS_parts_unsorted = array();
817
				if (((strlen($parsedFrame['data_raw']) % 2) == 0) && ((substr($parsedFrame['data_raw'], 0, 2) == "\xFF\xFE") || (substr($parsedFrame['data_raw'], 0, 2) == "\xFE\xFF"))) {
818
					// UTF-16, be careful looking for null bytes since most 2-byte characters may contain one; you need to find twin null bytes, and on even padding
819
					$thisILPS  = '';
820
					for ($i = 0; $i < strlen($parsedFrame['data_raw']); $i += 2) {
821
						$twobytes = substr($parsedFrame['data_raw'], $i, 2);
822
						if ($twobytes === "\x00\x00") {
823
							$IPLS_parts_unsorted[] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $thisILPS);
824
							$thisILPS  = '';
825
						} else {
826
							$thisILPS .= $twobytes;
827
						}
828
					}
829
					if (strlen($thisILPS) > 2) { // 2-byte BOM
830
						$IPLS_parts_unsorted[] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $thisILPS);
831
					}
832
				} else {
833
					// ISO-8859-1 or UTF-8 or other single-byte-null character set
834
					$IPLS_parts_unsorted = explode("\x00", $parsedFrame['data_raw']);
835
				}
836
				if (count($IPLS_parts_unsorted) == 1) {
837
					// just a list of names, e.g. "Dino Baptiste, Jimmy Copley, John Gordon, Bernie Marsden, Sharon Watson"
838
					foreach ($IPLS_parts_unsorted as $key => $value) {
839
						$IPLS_parts_sorted = preg_split('#[;,\\r\\n\\t]#', $value);
840
						$position = '';
841
						foreach ($IPLS_parts_sorted as $person) {
842
							$IPLS_parts[] = array('position'=>$position, 'person'=>$person);
843
						}
844
					}
845
				} elseif ((count($IPLS_parts_unsorted) % 2) == 0) {
846
					$position = '';
847
					$person   = '';
0 ignored issues
show
Unused Code introduced by
$person 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...
848
					foreach ($IPLS_parts_unsorted as $key => $value) {
849
						if (($key % 2) == 0) {
850
							$position = $value;
851
						} else {
852
							$person   = $value;
853
							$IPLS_parts[] = array('position'=>$position, 'person'=>$person);
854
							$position = '';
855
							$person   = '';
0 ignored issues
show
Unused Code introduced by
$person 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...
856
						}
857
					}
858
				} else {
859
					foreach ($IPLS_parts_unsorted as $key => $value) {
860
						$IPLS_parts[] = array($value);
861
					}
862
				}
863
864
			} else {
865
				$IPLS_parts = preg_split('#[;,\\r\\n\\t]#', $parsedFrame['data_raw']);
866
			}
867
			$parsedFrame['data'] = $IPLS_parts;
868
869 View Code Duplication
			if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
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...
870
				$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['data'];
871
			}
872
873
874
		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'MCDI')) || // 4.4   MCDI Music CD identifier
875
				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'MCI'))) {     // 4.5   MCI  Music CD identifier
876
			//   There may only be one 'MCDI' frame in each tag
877
			// <Header for 'Music CD identifier', ID: 'MCDI'>
878
			// CD TOC                <binary data>
879
880 View Code Duplication
			if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
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...
881
				$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['data'];
882
			}
883
884
885
		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'ETCO')) || // 4.5   ETCO Event timing codes
886
				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ETC'))) {     // 4.6   ETC  Event timing codes
887
			//   There may only be one 'ETCO' frame in each tag
888
			// <Header for 'Event timing codes', ID: 'ETCO'>
889
			// Time stamp format    $xx
890
			//   Where time stamp format is:
891
			// $01  (32-bit value) MPEG frames from beginning of file
892
			// $02  (32-bit value) milliseconds from beginning of file
893
			//   Followed by a list of key events in the following format:
894
			// Type of event   $xx
895
			// Time stamp      $xx (xx ...)
896
			//   The 'Time stamp' is set to zero if directly at the beginning of the sound
897
			//   or after the previous event. All events MUST be sorted in chronological order.
898
899
			$frame_offset = 0;
900
			$parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
901
902
			while ($frame_offset < strlen($parsedFrame['data'])) {
903
				$parsedFrame['typeid']    = substr($parsedFrame['data'], $frame_offset++, 1);
904
				$parsedFrame['type']      = $this->ETCOEventLookup($parsedFrame['typeid']);
905
				$parsedFrame['timestamp'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
906
				$frame_offset += 4;
907
			}
908
			unset($parsedFrame['data']);
909
910
911
		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'MLLT')) || // 4.6   MLLT MPEG location lookup table
912
				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'MLL'))) {     // 4.7   MLL MPEG location lookup table
913
			//   There may only be one 'MLLT' frame in each tag
914
			// <Header for 'Location lookup table', ID: 'MLLT'>
915
			// MPEG frames between reference  $xx xx
916
			// Bytes between reference        $xx xx xx
917
			// Milliseconds between reference $xx xx xx
918
			// Bits for bytes deviation       $xx
919
			// Bits for milliseconds dev.     $xx
920
			//   Then for every reference the following data is included;
921
			// Deviation in bytes         %xxx....
922
			// Deviation in milliseconds  %xxx....
923
924
			$frame_offset = 0;
925
			$parsedFrame['framesbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 2));
926
			$parsedFrame['bytesbetweenreferences']  = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 2, 3));
927
			$parsedFrame['msbetweenreferences']     = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 5, 3));
928
			$parsedFrame['bitsforbytesdeviation']   = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 8, 1));
929
			$parsedFrame['bitsformsdeviation']      = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 9, 1));
930
			$parsedFrame['data'] = substr($parsedFrame['data'], 10);
931
			$deviationbitstream = '';
932
			while ($frame_offset < strlen($parsedFrame['data'])) {
933
				$deviationbitstream .= getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
934
			}
935
			$reference_counter = 0;
936
			while (strlen($deviationbitstream) > 0) {
937
				$parsedFrame[$reference_counter]['bytedeviation'] = bindec(substr($deviationbitstream, 0, $parsedFrame['bitsforbytesdeviation']));
938
				$parsedFrame[$reference_counter]['msdeviation']   = bindec(substr($deviationbitstream, $parsedFrame['bitsforbytesdeviation'], $parsedFrame['bitsformsdeviation']));
939
				$deviationbitstream = substr($deviationbitstream, $parsedFrame['bitsforbytesdeviation'] + $parsedFrame['bitsformsdeviation']);
940
				$reference_counter++;
941
			}
942
			unset($parsedFrame['data']);
943
944
945
		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'SYTC')) || // 4.7   SYTC Synchronised tempo codes
946
				  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'STC'))) {  // 4.8   STC  Synchronised tempo codes
947
			//   There may only be one 'SYTC' frame in each tag
948
			// <Header for 'Synchronised tempo codes', ID: 'SYTC'>
949
			// Time stamp format   $xx
950
			// Tempo data          <binary data>
951
			//   Where time stamp format is:
952
			// $01  (32-bit value) MPEG frames from beginning of file
953
			// $02  (32-bit value) milliseconds from beginning of file
954
955
			$frame_offset = 0;
956
			$parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
957
			$timestamp_counter = 0;
958
			while ($frame_offset < strlen($parsedFrame['data'])) {
959
				$parsedFrame[$timestamp_counter]['tempo'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
960
				if ($parsedFrame[$timestamp_counter]['tempo'] == 255) {
961
					$parsedFrame[$timestamp_counter]['tempo'] += ord(substr($parsedFrame['data'], $frame_offset++, 1));
962
				}
963
				$parsedFrame[$timestamp_counter]['timestamp'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
964
				$frame_offset += 4;
965
				$timestamp_counter++;
966
			}
967
			unset($parsedFrame['data']);
968
969
970
		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USLT')) || // 4.8   USLT Unsynchronised lyric/text transcription
971
				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ULT'))) {     // 4.9   ULT  Unsynchronised lyric/text transcription
972
			//   There may be more than one 'Unsynchronised lyrics/text transcription' frame
973
			//   in each tag, but only one with the same language and content descriptor.
974
			// <Header for 'Unsynchronised lyrics/text transcription', ID: 'USLT'>
975
			// Text encoding        $xx
976
			// Language             $xx xx xx
977
			// Content descriptor   <text string according to encoding> $00 (00)
978
			// Lyrics/text          <full text string according to encoding>
979
980
			$frame_offset = 0;
981
			$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
982
			$frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
983 View Code Duplication
			if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 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...
984
				$this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding');
985
				$frame_textencoding_terminator = "\x00";
986
			}
987
			$frame_language = substr($parsedFrame['data'], $frame_offset, 3);
988
			$frame_offset += 3;
989
			$frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
990 View Code Duplication
			if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
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...
991
				$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
992
			}
993
			$parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
994
			$parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
995
			$parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
996
			$parsedFrame['data'] = $this->RemoveStringTerminator($parsedFrame['data'], $frame_textencoding_terminator);
997
998
			$parsedFrame['encodingid']   = $frame_textencoding;
999
			$parsedFrame['encoding']     = $this->TextEncodingNameLookup($frame_textencoding);
1000
1001
			$parsedFrame['language']     = $frame_language;
1002
			$parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
1003 View Code Duplication
			if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
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...
1004
				$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
1005
			}
1006
			unset($parsedFrame['data']);
1007
1008
1009
		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'SYLT')) || // 4.9   SYLT Synchronised lyric/text
1010
				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'SLT'))) {     // 4.10  SLT  Synchronised lyric/text
1011
			//   There may be more than one 'SYLT' frame in each tag,
1012
			//   but only one with the same language and content descriptor.
1013
			// <Header for 'Synchronised lyrics/text', ID: 'SYLT'>
1014
			// Text encoding        $xx
1015
			// Language             $xx xx xx
1016
			// Time stamp format    $xx
1017
			//   $01  (32-bit value) MPEG frames from beginning of file
1018
			//   $02  (32-bit value) milliseconds from beginning of file
1019
			// Content type         $xx
1020
			// Content descriptor   <text string according to encoding> $00 (00)
1021
			//   Terminated text to be synced (typically a syllable)
1022
			//   Sync identifier (terminator to above string)   $00 (00)
1023
			//   Time stamp                                     $xx (xx ...)
1024
1025
			$frame_offset = 0;
1026
			$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1027
			$frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
1028 View Code Duplication
			if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 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...
1029
				$this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding');
1030
				$frame_textencoding_terminator = "\x00";
1031
			}
1032
			$frame_language = substr($parsedFrame['data'], $frame_offset, 3);
1033
			$frame_offset += 3;
1034
			$parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1035
			$parsedFrame['contenttypeid']   = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1036
			$parsedFrame['contenttype']     = $this->SYTLContentTypeLookup($parsedFrame['contenttypeid']);
1037
			$parsedFrame['encodingid']      = $frame_textencoding;
1038
			$parsedFrame['encoding']        = $this->TextEncodingNameLookup($frame_textencoding);
1039
1040
			$parsedFrame['language']        = $frame_language;
1041
			$parsedFrame['languagename']    = $this->LanguageLookup($frame_language, false);
1042
1043
			$timestampindex = 0;
1044
			$frame_remainingdata = substr($parsedFrame['data'], $frame_offset);
1045
			while (strlen($frame_remainingdata)) {
1046
				$frame_offset = 0;
1047
				$frame_terminatorpos = strpos($frame_remainingdata, $frame_textencoding_terminator);
1048
				if ($frame_terminatorpos === false) {
1049
					$frame_remainingdata = '';
1050
				} else {
1051 View Code Duplication
					if (ord(substr($frame_remainingdata, $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
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...
1052
						$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1053
					}
1054
					$parsedFrame['lyrics'][$timestampindex]['data'] = substr($frame_remainingdata, $frame_offset, $frame_terminatorpos - $frame_offset);
1055
1056
					$frame_remainingdata = substr($frame_remainingdata, $frame_terminatorpos + strlen($frame_textencoding_terminator));
1057
					if (($timestampindex == 0) && (ord($frame_remainingdata[0]) != 0)) {
1058
						// timestamp probably omitted for first data item
1059
					} else {
1060
						$parsedFrame['lyrics'][$timestampindex]['timestamp'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 0, 4));
1061
						$frame_remainingdata = substr($frame_remainingdata, 4);
1062
					}
1063
					$timestampindex++;
1064
				}
1065
			}
1066
			unset($parsedFrame['data']);
1067
1068
1069
		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'COMM')) || // 4.10  COMM Comments
1070
				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'COM'))) {     // 4.11  COM  Comments
1071
			//   There may be more than one comment frame in each tag,
1072
			//   but only one with the same language and content descriptor.
1073
			// <Header for 'Comment', ID: 'COMM'>
1074
			// Text encoding          $xx
1075
			// Language               $xx xx xx
1076
			// Short content descrip. <text string according to encoding> $00 (00)
1077
			// The actual text        <full text string according to encoding>
1078
1079
			if (strlen($parsedFrame['data']) < 5) {
1080
1081
				$this->warning('Invalid data (too short) for "'.$parsedFrame['frame_name'].'" frame at offset '.$parsedFrame['dataoffset']);
1082
1083
			} else {
1084
1085
				$frame_offset = 0;
1086
				$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1087
				$frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
1088 View Code Duplication
				if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 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...
1089
					$this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding');
1090
					$frame_textencoding_terminator = "\x00";
1091
				}
1092
				$frame_language = substr($parsedFrame['data'], $frame_offset, 3);
1093
				$frame_offset += 3;
1094
				$frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
1095 View Code Duplication
				if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
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...
1096
					$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1097
				}
1098
				$parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1099
				$parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
1100
				$frame_text = (string) substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
1101
				$frame_text = $this->RemoveStringTerminator($frame_text, $frame_textencoding_terminator);
1102
1103
				$parsedFrame['encodingid']   = $frame_textencoding;
1104
				$parsedFrame['encoding']     = $this->TextEncodingNameLookup($frame_textencoding);
1105
1106
				$parsedFrame['language']     = $frame_language;
1107
				$parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
1108
				$parsedFrame['data']         = $frame_text;
1109
				if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
1110
					$commentkey = ($parsedFrame['description'] ? $parsedFrame['description'] : (!empty($info['id3v2']['comments'][$parsedFrame['framenameshort']]) ? count($info['id3v2']['comments'][$parsedFrame['framenameshort']]) : 0));
1111 View Code Duplication
					if (!isset($info['id3v2']['comments'][$parsedFrame['framenameshort']]) || !array_key_exists($commentkey, $info['id3v2']['comments'][$parsedFrame['framenameshort']])) {
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...
1112
						$info['id3v2']['comments'][$parsedFrame['framenameshort']][$commentkey] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
1113
					} else {
1114
						$info['id3v2']['comments'][$parsedFrame['framenameshort']][]            = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
1115
					}
1116
				}
1117
1118
			}
1119
1120
		} elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'RVA2')) { // 4.11  RVA2 Relative volume adjustment (2) (ID3v2.4+ only)
1121
			//   There may be more than one 'RVA2' frame in each tag,
1122
			//   but only one with the same identification string
1123
			// <Header for 'Relative volume adjustment (2)', ID: 'RVA2'>
1124
			// Identification          <text string> $00
1125
			//   The 'identification' string is used to identify the situation and/or
1126
			//   device where this adjustment should apply. The following is then
1127
			//   repeated for every channel:
1128
			// Type of channel         $xx
1129
			// Volume adjustment       $xx xx
1130
			// Bits representing peak  $xx
1131
			// Peak volume             $xx (xx ...)
1132
1133
			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00");
1134
			$frame_idstring = substr($parsedFrame['data'], 0, $frame_terminatorpos);
1135
			if (ord($frame_idstring) === 0) {
1136
				$frame_idstring = '';
1137
			}
1138
			$frame_remainingdata = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00"));
1139
			$parsedFrame['description'] = $frame_idstring;
1140
			$RVA2channelcounter = 0;
1141
			while (strlen($frame_remainingdata) >= 5) {
1142
				$frame_offset = 0;
1143
				$frame_channeltypeid = ord(substr($frame_remainingdata, $frame_offset++, 1));
1144
				$parsedFrame[$RVA2channelcounter]['channeltypeid']  = $frame_channeltypeid;
1145
				$parsedFrame[$RVA2channelcounter]['channeltype']    = $this->RVA2ChannelTypeLookup($frame_channeltypeid);
1146
				$parsedFrame[$RVA2channelcounter]['volumeadjust']   = getid3_lib::BigEndian2Int(substr($frame_remainingdata, $frame_offset, 2), false, true); // 16-bit signed
1147
				$frame_offset += 2;
1148
				$parsedFrame[$RVA2channelcounter]['bitspeakvolume'] = ord(substr($frame_remainingdata, $frame_offset++, 1));
1149
				if (($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] < 1) || ($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] > 4)) {
1150
					$this->warning('ID3v2::RVA2 frame['.$RVA2channelcounter.'] contains invalid '.$parsedFrame[$RVA2channelcounter]['bitspeakvolume'].'-byte bits-representing-peak value');
1151
					break;
1152
				}
1153
				$frame_bytespeakvolume = ceil($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] / 8);
1154
				$parsedFrame[$RVA2channelcounter]['peakvolume']     = getid3_lib::BigEndian2Int(substr($frame_remainingdata, $frame_offset, $frame_bytespeakvolume));
1155
				$frame_remainingdata = substr($frame_remainingdata, $frame_offset + $frame_bytespeakvolume);
1156
				$RVA2channelcounter++;
1157
			}
1158
			unset($parsedFrame['data']);
1159
1160
1161
		} elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'RVAD')) || // 4.12  RVAD Relative volume adjustment (ID3v2.3 only)
1162
				  (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'RVA'))) {  // 4.12  RVA  Relative volume adjustment (ID3v2.2 only)
1163
			//   There may only be one 'RVA' frame in each tag
1164
			// <Header for 'Relative volume adjustment', ID: 'RVA'>
1165
			// ID3v2.2 => Increment/decrement     %000000ba
1166
			// ID3v2.3 => Increment/decrement     %00fedcba
1167
			// Bits used for volume descr.        $xx
1168
			// Relative volume change, right      $xx xx (xx ...) // a
1169
			// Relative volume change, left       $xx xx (xx ...) // b
1170
			// Peak volume right                  $xx xx (xx ...)
1171
			// Peak volume left                   $xx xx (xx ...)
1172
			//   ID3v2.3 only, optional (not present in ID3v2.2):
1173
			// Relative volume change, right back $xx xx (xx ...) // c
1174
			// Relative volume change, left back  $xx xx (xx ...) // d
1175
			// Peak volume right back             $xx xx (xx ...)
1176
			// Peak volume left back              $xx xx (xx ...)
1177
			//   ID3v2.3 only, optional (not present in ID3v2.2):
1178
			// Relative volume change, center     $xx xx (xx ...) // e
1179
			// Peak volume center                 $xx xx (xx ...)
1180
			//   ID3v2.3 only, optional (not present in ID3v2.2):
1181
			// Relative volume change, bass       $xx xx (xx ...) // f
1182
			// Peak volume bass                   $xx xx (xx ...)
1183
1184
			$frame_offset = 0;
1185
			$frame_incrdecrflags = getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
1186
			$parsedFrame['incdec']['right'] = (bool) substr($frame_incrdecrflags, 6, 1);
1187
			$parsedFrame['incdec']['left']  = (bool) substr($frame_incrdecrflags, 7, 1);
1188
			$parsedFrame['bitsvolume'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1189
			$frame_bytesvolume = ceil($parsedFrame['bitsvolume'] / 8);
1190
			$parsedFrame['volumechange']['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1191
			if ($parsedFrame['incdec']['right'] === false) {
1192
				$parsedFrame['volumechange']['right'] *= -1;
1193
			}
1194
			$frame_offset += $frame_bytesvolume;
1195
			$parsedFrame['volumechange']['left'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1196
			if ($parsedFrame['incdec']['left'] === false) {
1197
				$parsedFrame['volumechange']['left'] *= -1;
1198
			}
1199
			$frame_offset += $frame_bytesvolume;
1200
			$parsedFrame['peakvolume']['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1201
			$frame_offset += $frame_bytesvolume;
1202
			$parsedFrame['peakvolume']['left']  = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1203
			$frame_offset += $frame_bytesvolume;
1204
			if ($id3v2_majorversion == 3) {
1205
				$parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
1206
				if (strlen($parsedFrame['data']) > 0) {
1207
					$parsedFrame['incdec']['rightrear'] = (bool) substr($frame_incrdecrflags, 4, 1);
1208
					$parsedFrame['incdec']['leftrear']  = (bool) substr($frame_incrdecrflags, 5, 1);
1209
					$parsedFrame['volumechange']['rightrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1210
					if ($parsedFrame['incdec']['rightrear'] === false) {
1211
						$parsedFrame['volumechange']['rightrear'] *= -1;
1212
					}
1213
					$frame_offset += $frame_bytesvolume;
1214
					$parsedFrame['volumechange']['leftrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1215
					if ($parsedFrame['incdec']['leftrear'] === false) {
1216
						$parsedFrame['volumechange']['leftrear'] *= -1;
1217
					}
1218
					$frame_offset += $frame_bytesvolume;
1219
					$parsedFrame['peakvolume']['rightrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1220
					$frame_offset += $frame_bytesvolume;
1221
					$parsedFrame['peakvolume']['leftrear']  = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1222
					$frame_offset += $frame_bytesvolume;
1223
				}
1224
				$parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
1225 View Code Duplication
				if (strlen($parsedFrame['data']) > 0) {
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...
1226
					$parsedFrame['incdec']['center'] = (bool) substr($frame_incrdecrflags, 3, 1);
1227
					$parsedFrame['volumechange']['center'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1228
					if ($parsedFrame['incdec']['center'] === false) {
1229
						$parsedFrame['volumechange']['center'] *= -1;
1230
					}
1231
					$frame_offset += $frame_bytesvolume;
1232
					$parsedFrame['peakvolume']['center'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1233
					$frame_offset += $frame_bytesvolume;
1234
				}
1235
				$parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
1236 View Code Duplication
				if (strlen($parsedFrame['data']) > 0) {
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...
1237
					$parsedFrame['incdec']['bass'] = (bool) substr($frame_incrdecrflags, 2, 1);
1238
					$parsedFrame['volumechange']['bass'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1239
					if ($parsedFrame['incdec']['bass'] === false) {
1240
						$parsedFrame['volumechange']['bass'] *= -1;
1241
					}
1242
					$frame_offset += $frame_bytesvolume;
1243
					$parsedFrame['peakvolume']['bass'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
1244
					$frame_offset += $frame_bytesvolume;
1245
				}
1246
			}
1247
			unset($parsedFrame['data']);
1248
1249
1250
		} elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'EQU2')) { // 4.12  EQU2 Equalisation (2) (ID3v2.4+ only)
1251
			//   There may be more than one 'EQU2' frame in each tag,
1252
			//   but only one with the same identification string
1253
			// <Header of 'Equalisation (2)', ID: 'EQU2'>
1254
			// Interpolation method  $xx
1255
			//   $00  Band
1256
			//   $01  Linear
1257
			// Identification        <text string> $00
1258
			//   The following is then repeated for every adjustment point
1259
			// Frequency          $xx xx
1260
			// Volume adjustment  $xx xx
1261
1262
			$frame_offset = 0;
1263
			$frame_interpolationmethod = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1264
			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1265
			$frame_idstring = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1266
			if (ord($frame_idstring) === 0) {
1267
				$frame_idstring = '';
1268
			}
1269
			$parsedFrame['description'] = $frame_idstring;
1270
			$frame_remainingdata = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00"));
1271
			while (strlen($frame_remainingdata)) {
1272
				$frame_frequency = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 0, 2)) / 2;
1273
				$parsedFrame['data'][$frame_frequency] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 2, 2), false, true);
1274
				$frame_remainingdata = substr($frame_remainingdata, 4);
1275
			}
1276
			$parsedFrame['interpolationmethod'] = $frame_interpolationmethod;
1277
			unset($parsedFrame['data']);
1278
1279
1280
		} elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'EQUA')) || // 4.12  EQUA Equalisation (ID3v2.3 only)
1281
				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'EQU'))) {     // 4.13  EQU  Equalisation (ID3v2.2 only)
1282
			//   There may only be one 'EQUA' frame in each tag
1283
			// <Header for 'Relative volume adjustment', ID: 'EQU'>
1284
			// Adjustment bits    $xx
1285
			//   This is followed by 2 bytes + ('adjustment bits' rounded up to the
1286
			//   nearest byte) for every equalisation band in the following format,
1287
			//   giving a frequency range of 0 - 32767Hz:
1288
			// Increment/decrement   %x (MSB of the Frequency)
1289
			// Frequency             (lower 15 bits)
1290
			// Adjustment            $xx (xx ...)
1291
1292
			$frame_offset = 0;
1293
			$parsedFrame['adjustmentbits'] = substr($parsedFrame['data'], $frame_offset++, 1);
1294
			$frame_adjustmentbytes = ceil($parsedFrame['adjustmentbits'] / 8);
1295
1296
			$frame_remainingdata = (string) substr($parsedFrame['data'], $frame_offset);
1297
			while (strlen($frame_remainingdata) > 0) {
1298
				$frame_frequencystr = getid3_lib::BigEndian2Bin(substr($frame_remainingdata, 0, 2));
1299
				$frame_incdec    = (bool) substr($frame_frequencystr, 0, 1);
1300
				$frame_frequency = bindec(substr($frame_frequencystr, 1, 15));
1301
				$parsedFrame[$frame_frequency]['incdec'] = $frame_incdec;
1302
				$parsedFrame[$frame_frequency]['adjustment'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 2, $frame_adjustmentbytes));
1303
				if ($parsedFrame[$frame_frequency]['incdec'] === false) {
1304
					$parsedFrame[$frame_frequency]['adjustment'] *= -1;
1305
				}
1306
				$frame_remainingdata = substr($frame_remainingdata, 2 + $frame_adjustmentbytes);
1307
			}
1308
			unset($parsedFrame['data']);
1309
1310
1311
		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RVRB')) || // 4.13  RVRB Reverb
1312
				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'REV'))) {     // 4.14  REV  Reverb
1313
			//   There may only be one 'RVRB' frame in each tag.
1314
			// <Header for 'Reverb', ID: 'RVRB'>
1315
			// Reverb left (ms)                 $xx xx
1316
			// Reverb right (ms)                $xx xx
1317
			// Reverb bounces, left             $xx
1318
			// Reverb bounces, right            $xx
1319
			// Reverb feedback, left to left    $xx
1320
			// Reverb feedback, left to right   $xx
1321
			// Reverb feedback, right to right  $xx
1322
			// Reverb feedback, right to left   $xx
1323
			// Premix left to right             $xx
1324
			// Premix right to left             $xx
1325
1326
			$frame_offset = 0;
1327
			$parsedFrame['left']  = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1328
			$frame_offset += 2;
1329
			$parsedFrame['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1330
			$frame_offset += 2;
1331
			$parsedFrame['bouncesL']      = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1332
			$parsedFrame['bouncesR']      = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1333
			$parsedFrame['feedbackLL']    = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1334
			$parsedFrame['feedbackLR']    = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1335
			$parsedFrame['feedbackRR']    = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1336
			$parsedFrame['feedbackRL']    = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1337
			$parsedFrame['premixLR']      = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1338
			$parsedFrame['premixRL']      = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1339
			unset($parsedFrame['data']);
1340
1341
1342
		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'APIC')) || // 4.14  APIC Attached picture
1343
				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'PIC'))) {     // 4.15  PIC  Attached picture
1344
			//   There may be several pictures attached to one file,
1345
			//   each in their individual 'APIC' frame, but only one
1346
			//   with the same content descriptor
1347
			// <Header for 'Attached picture', ID: 'APIC'>
1348
			// Text encoding      $xx
1349
			// ID3v2.3+ => MIME type          <text string> $00
1350
			// ID3v2.2  => Image format       $xx xx xx
1351
			// Picture type       $xx
1352
			// Description        <text string according to encoding> $00 (00)
1353
			// Picture data       <binary data>
1354
1355
			$frame_offset = 0;
1356
			$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1357
			$frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
1358 View Code Duplication
			if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 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...
1359
				$this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding');
1360
				$frame_textencoding_terminator = "\x00";
1361
			}
1362
1363
			if ($id3v2_majorversion == 2 && strlen($parsedFrame['data']) > $frame_offset) {
1364
				$frame_imagetype = substr($parsedFrame['data'], $frame_offset, 3);
1365
				if (strtolower($frame_imagetype) == 'ima') {
1366
					// complete hack for mp3Rage (www.chaoticsoftware.com) that puts ID3v2.3-formatted
1367
					// MIME type instead of 3-char ID3v2.2-format image type  (thanks xbhoffØpacbell*net)
1368
					$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1369
					$frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1370
					if (ord($frame_mimetype) === 0) {
1371
						$frame_mimetype = '';
1372
					}
1373
					$frame_imagetype = strtoupper(str_replace('image/', '', strtolower($frame_mimetype)));
1374
					if ($frame_imagetype == 'JPEG') {
1375
						$frame_imagetype = 'JPG';
1376
					}
1377
					$frame_offset = $frame_terminatorpos + strlen("\x00");
1378
				} else {
1379
					$frame_offset += 3;
1380
				}
1381
			}
1382
			if ($id3v2_majorversion > 2 && strlen($parsedFrame['data']) > $frame_offset) {
1383
				$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1384
				$frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1385
				if (ord($frame_mimetype) === 0) {
1386
					$frame_mimetype = '';
1387
				}
1388
				$frame_offset = $frame_terminatorpos + strlen("\x00");
1389
			}
1390
1391
			$frame_picturetype = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1392
1393
			if ($frame_offset >= $parsedFrame['datalength']) {
1394
				$this->warning('data portion of APIC frame is missing at offset '.($parsedFrame['dataoffset'] + 8 + $frame_offset));
1395
			} else {
1396
				$frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
1397 View Code Duplication
				if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
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...
1398
					$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1399
				}
1400
				$parsedFrame['description']   = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1401
				$parsedFrame['description']   = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
1402
				$parsedFrame['encodingid']    = $frame_textencoding;
1403
				$parsedFrame['encoding']      = $this->TextEncodingNameLookup($frame_textencoding);
1404
1405
				if ($id3v2_majorversion == 2) {
1406
					$parsedFrame['imagetype'] = isset($frame_imagetype) ? $frame_imagetype : null;
1407
				} else {
1408
					$parsedFrame['mime']      = isset($frame_mimetype) ? $frame_mimetype : null;
1409
				}
1410
				$parsedFrame['picturetypeid'] = $frame_picturetype;
1411
				$parsedFrame['picturetype']   = $this->APICPictureTypeLookup($frame_picturetype);
1412
				$parsedFrame['data']          = substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator));
1413
				$parsedFrame['datalength']    = strlen($parsedFrame['data']);
1414
1415
				$parsedFrame['image_mime']    = '';
1416
				$imageinfo = array();
1417
				if ($imagechunkcheck = getid3_lib::GetDataImageSize($parsedFrame['data'], $imageinfo)) {
1418
					if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) {
1419
						$parsedFrame['image_mime']       = image_type_to_mime_type($imagechunkcheck[2]);
1420
						if ($imagechunkcheck[0]) {
1421
							$parsedFrame['image_width']  = $imagechunkcheck[0];
1422
						}
1423
						if ($imagechunkcheck[1]) {
1424
							$parsedFrame['image_height'] = $imagechunkcheck[1];
1425
						}
1426
					}
1427
				}
1428
1429
				do {
1430
					if ($this->getid3->option_save_attachments === false) {
1431
						// skip entirely
1432
						unset($parsedFrame['data']);
1433
						break;
1434
					}
1435
					$dir = '';
1436
					if ($this->getid3->option_save_attachments === true) {
1437
						// great
1438
/*
1439
					} elseif (is_int($this->getid3->option_save_attachments)) {
1440
						if ($this->getid3->option_save_attachments < $parsedFrame['data_length']) {
1441
							// too big, skip
1442
							$this->warning('attachment at '.$frame_offset.' is too large to process inline ('.number_format($parsedFrame['data_length']).' bytes)');
1443
							unset($parsedFrame['data']);
1444
							break;
1445
						}
1446
*/
1447
					} elseif (is_string($this->getid3->option_save_attachments)) {
1448
						$dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->getid3->option_save_attachments), DIRECTORY_SEPARATOR);
1449
						if (!is_dir($dir) || !getID3::is_writable($dir)) {
1450
							// cannot write, skip
1451
							$this->warning('attachment at '.$frame_offset.' cannot be saved to "'.$dir.'" (not writable)');
1452
							unset($parsedFrame['data']);
1453
							break;
1454
						}
1455
					}
1456
					// if we get this far, must be OK
1457
					if (is_string($this->getid3->option_save_attachments)) {
1458
						$destination_filename = $dir.DIRECTORY_SEPARATOR.md5($info['filenamepath']).'_'.$frame_offset;
1459 View Code Duplication
						if (!file_exists($destination_filename) || getID3::is_writable($destination_filename)) {
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...
1460
							file_put_contents($destination_filename, $parsedFrame['data']);
1461
						} else {
1462
							$this->warning('attachment at '.$frame_offset.' cannot be saved to "'.$destination_filename.'" (not writable)');
1463
						}
1464
						$parsedFrame['data_filename'] = $destination_filename;
1465
						unset($parsedFrame['data']);
1466 View Code Duplication
					} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1467
						if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
1468
							if (!isset($info['id3v2']['comments']['picture'])) {
1469
								$info['id3v2']['comments']['picture'] = array();
1470
							}
1471
							$comments_picture_data = array();
1472
							foreach (array('data', 'image_mime', 'image_width', 'image_height', 'imagetype', 'picturetype', 'description', 'datalength') as $picture_key) {
1473
								if (isset($parsedFrame[$picture_key])) {
1474
									$comments_picture_data[$picture_key] = $parsedFrame[$picture_key];
1475
								}
1476
							}
1477
							$info['id3v2']['comments']['picture'][] = $comments_picture_data;
1478
							unset($comments_picture_data);
1479
						}
1480
					}
1481
				} while (false);
1482
			}
1483
1484
		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GEOB')) || // 4.15  GEOB General encapsulated object
1485
				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'GEO'))) {     // 4.16  GEO  General encapsulated object
1486
			//   There may be more than one 'GEOB' frame in each tag,
1487
			//   but only one with the same content descriptor
1488
			// <Header for 'General encapsulated object', ID: 'GEOB'>
1489
			// Text encoding          $xx
1490
			// MIME type              <text string> $00
1491
			// Filename               <text string according to encoding> $00 (00)
1492
			// Content description    <text string according to encoding> $00 (00)
1493
			// Encapsulated object    <binary data>
1494
1495
			$frame_offset = 0;
1496
			$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1497
			$frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
1498 View Code Duplication
			if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 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...
1499
				$this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding');
1500
				$frame_textencoding_terminator = "\x00";
1501
			}
1502
			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1503
			$frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1504
			if (ord($frame_mimetype) === 0) {
1505
				$frame_mimetype = '';
1506
			}
1507
			$frame_offset = $frame_terminatorpos + strlen("\x00");
1508
1509
			$frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
1510 View Code Duplication
			if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
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...
1511
				$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1512
			}
1513
			$frame_filename = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1514
			if (ord($frame_filename) === 0) {
1515
				$frame_filename = '';
1516
			}
1517
			$frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
1518
1519
			$frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
1520 View Code Duplication
			if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
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...
1521
				$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1522
			}
1523
			$parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1524
			$parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
1525
			$frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
1526
1527
			$parsedFrame['objectdata']  = (string) substr($parsedFrame['data'], $frame_offset);
1528
			$parsedFrame['encodingid']  = $frame_textencoding;
1529
			$parsedFrame['encoding']    = $this->TextEncodingNameLookup($frame_textencoding);
1530
1531
			$parsedFrame['mime']        = $frame_mimetype;
1532
			$parsedFrame['filename']    = $frame_filename;
1533
			unset($parsedFrame['data']);
1534
1535
1536
		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'PCNT')) || // 4.16  PCNT Play counter
1537
				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CNT'))) {     // 4.17  CNT  Play counter
1538
			//   There may only be one 'PCNT' frame in each tag.
1539
			//   When the counter reaches all one's, one byte is inserted in
1540
			//   front of the counter thus making the counter eight bits bigger
1541
			// <Header for 'Play counter', ID: 'PCNT'>
1542
			// Counter        $xx xx xx xx (xx ...)
1543
1544
			$parsedFrame['data']          = getid3_lib::BigEndian2Int($parsedFrame['data']);
1545
1546
1547
		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'POPM')) || // 4.17  POPM Popularimeter
1548
				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'POP'))) {    // 4.18  POP  Popularimeter
1549
			//   There may be more than one 'POPM' frame in each tag,
1550
			//   but only one with the same email address
1551
			// <Header for 'Popularimeter', ID: 'POPM'>
1552
			// Email to user   <text string> $00
1553
			// Rating          $xx
1554
			// Counter         $xx xx xx xx (xx ...)
1555
1556
			$frame_offset = 0;
1557
			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1558
			$frame_emailaddress = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1559
			if (ord($frame_emailaddress) === 0) {
1560
				$frame_emailaddress = '';
1561
			}
1562
			$frame_offset = $frame_terminatorpos + strlen("\x00");
1563
			$frame_rating = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1564
			$parsedFrame['counter'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset));
1565
			$parsedFrame['email']   = $frame_emailaddress;
1566
			$parsedFrame['rating']  = $frame_rating;
1567
			unset($parsedFrame['data']);
1568
1569
1570
		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RBUF')) || // 4.18  RBUF Recommended buffer size
1571
				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'BUF'))) {     // 4.19  BUF  Recommended buffer size
1572
			//   There may only be one 'RBUF' frame in each tag
1573
			// <Header for 'Recommended buffer size', ID: 'RBUF'>
1574
			// Buffer size               $xx xx xx
1575
			// Embedded info flag        %0000000x
1576
			// Offset to next tag        $xx xx xx xx
1577
1578
			$frame_offset = 0;
1579
			$parsedFrame['buffersize'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 3));
1580
			$frame_offset += 3;
1581
1582
			$frame_embeddedinfoflags = getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
1583
			$parsedFrame['flags']['embededinfo'] = (bool) substr($frame_embeddedinfoflags, 7, 1);
1584
			$parsedFrame['nexttagoffset'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1585
			unset($parsedFrame['data']);
1586
1587
1588
		} elseif (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CRM')) { // 4.20  Encrypted meta frame (ID3v2.2 only)
1589
			//   There may be more than one 'CRM' frame in a tag,
1590
			//   but only one with the same 'owner identifier'
1591
			// <Header for 'Encrypted meta frame', ID: 'CRM'>
1592
			// Owner identifier      <textstring> $00 (00)
1593
			// Content/explanation   <textstring> $00 (00)
1594
			// Encrypted datablock   <binary data>
1595
1596
			$frame_offset = 0;
1597
			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1598
			$frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1599
			$frame_offset = $frame_terminatorpos + strlen("\x00");
1600
1601
			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1602
			$parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1603
			$parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
1604
			$frame_offset = $frame_terminatorpos + strlen("\x00");
1605
1606
			$parsedFrame['ownerid']     = $frame_ownerid;
1607
			$parsedFrame['data']        = (string) substr($parsedFrame['data'], $frame_offset);
1608
			unset($parsedFrame['data']);
1609
1610
1611
		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'AENC')) || // 4.19  AENC Audio encryption
1612
				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CRA'))) {     // 4.21  CRA  Audio encryption
1613
			//   There may be more than one 'AENC' frames in a tag,
1614
			//   but only one with the same 'Owner identifier'
1615
			// <Header for 'Audio encryption', ID: 'AENC'>
1616
			// Owner identifier   <text string> $00
1617
			// Preview start      $xx xx
1618
			// Preview length     $xx xx
1619
			// Encryption info    <binary data>
1620
1621
			$frame_offset = 0;
1622
			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1623
			$frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1624
			if (ord($frame_ownerid) === 0) {
1625
				$frame_ownerid = '';
1626
			}
1627
			$frame_offset = $frame_terminatorpos + strlen("\x00");
1628
			$parsedFrame['ownerid'] = $frame_ownerid;
1629
			$parsedFrame['previewstart'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1630
			$frame_offset += 2;
1631
			$parsedFrame['previewlength'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1632
			$frame_offset += 2;
1633
			$parsedFrame['encryptioninfo'] = (string) substr($parsedFrame['data'], $frame_offset);
1634
			unset($parsedFrame['data']);
1635
1636
1637
		} elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'LINK')) || // 4.20  LINK Linked information
1638
				(($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'LNK'))) {    // 4.22  LNK  Linked information
1639
			//   There may be more than one 'LINK' frame in a tag,
1640
			//   but only one with the same contents
1641
			// <Header for 'Linked information', ID: 'LINK'>
1642
			// ID3v2.3+ => Frame identifier   $xx xx xx xx
1643
			// ID3v2.2  => Frame identifier   $xx xx xx
1644
			// URL                            <text string> $00
1645
			// ID and additional data         <text string(s)>
1646
1647
			$frame_offset = 0;
1648
			if ($id3v2_majorversion == 2) {
1649
				$parsedFrame['frameid'] = substr($parsedFrame['data'], $frame_offset, 3);
1650
				$frame_offset += 3;
1651
			} else {
1652
				$parsedFrame['frameid'] = substr($parsedFrame['data'], $frame_offset, 4);
1653
				$frame_offset += 4;
1654
			}
1655
1656
			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1657
			$frame_url = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1658
			if (ord($frame_url) === 0) {
1659
				$frame_url = '';
1660
			}
1661
			$frame_offset = $frame_terminatorpos + strlen("\x00");
1662
			$parsedFrame['url'] = $frame_url;
1663
1664
			$parsedFrame['additionaldata'] = (string) substr($parsedFrame['data'], $frame_offset);
1665 View Code Duplication
			if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
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...
1666
				$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback_iso88591_utf8($parsedFrame['url']);
1667
			}
1668
			unset($parsedFrame['data']);
1669
1670
1671
		} elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'POSS')) { // 4.21  POSS Position synchronisation frame (ID3v2.3+ only)
1672
			//   There may only be one 'POSS' frame in each tag
1673
			// <Head for 'Position synchronisation', ID: 'POSS'>
1674
			// Time stamp format         $xx
1675
			// Position                  $xx (xx ...)
1676
1677
			$frame_offset = 0;
1678
			$parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1679
			$parsedFrame['position']        = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset));
1680
			unset($parsedFrame['data']);
1681
1682
1683
		} elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USER')) { // 4.22  USER Terms of use (ID3v2.3+ only)
1684
			//   There may be more than one 'Terms of use' frame in a tag,
1685
			//   but only one with the same 'Language'
1686
			// <Header for 'Terms of use frame', ID: 'USER'>
1687
			// Text encoding        $xx
1688
			// Language             $xx xx xx
1689
			// The actual text      <text string according to encoding>
1690
1691
			$frame_offset = 0;
1692
			$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1693
			if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1694
				$this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding');
1695
			}
1696
			$frame_language = substr($parsedFrame['data'], $frame_offset, 3);
1697
			$frame_offset += 3;
1698
			$parsedFrame['language']     = $frame_language;
1699
			$parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
1700
			$parsedFrame['encodingid']   = $frame_textencoding;
1701
			$parsedFrame['encoding']     = $this->TextEncodingNameLookup($frame_textencoding);
1702
1703
			$parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
1704
			$parsedFrame['data'] = $this->RemoveStringTerminator($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding));
1705 View Code Duplication
			if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
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...
1706
				$info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
1707
			}
1708
			unset($parsedFrame['data']);
1709
1710
1711
		} elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'OWNE')) { // 4.23  OWNE Ownership frame (ID3v2.3+ only)
1712
			//   There may only be one 'OWNE' frame in a tag
1713
			// <Header for 'Ownership frame', ID: 'OWNE'>
1714
			// Text encoding     $xx
1715
			// Price paid        <text string> $00
1716
			// Date of purch.    <text string>
1717
			// Seller            <text string according to encoding>
1718
1719
			$frame_offset = 0;
1720
			$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1721
			if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
1722
				$this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding');
1723
			}
1724
			$parsedFrame['encodingid'] = $frame_textencoding;
1725
			$parsedFrame['encoding']   = $this->TextEncodingNameLookup($frame_textencoding);
1726
1727
			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1728
			$frame_pricepaid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1729
			$frame_offset = $frame_terminatorpos + strlen("\x00");
1730
1731
			$parsedFrame['pricepaid']['currencyid'] = substr($frame_pricepaid, 0, 3);
1732
			$parsedFrame['pricepaid']['currency']   = $this->LookupCurrencyUnits($parsedFrame['pricepaid']['currencyid']);
1733
			$parsedFrame['pricepaid']['value']      = substr($frame_pricepaid, 3);
1734
1735
			$parsedFrame['purchasedate'] = substr($parsedFrame['data'], $frame_offset, 8);
1736
			if ($this->IsValidDateStampString($parsedFrame['purchasedate'])) {
1737
				$parsedFrame['purchasedateunix'] = mktime (0, 0, 0, substr($parsedFrame['purchasedate'], 4, 2), substr($parsedFrame['purchasedate'], 6, 2), substr($parsedFrame['purchasedate'], 0, 4));
1738
			}
1739
			$frame_offset += 8;
1740
1741
			$parsedFrame['seller'] = (string) substr($parsedFrame['data'], $frame_offset);
1742
			$parsedFrame['seller'] = $this->RemoveStringTerminator($parsedFrame['seller'], $this->TextEncodingTerminatorLookup($frame_textencoding));
1743
			unset($parsedFrame['data']);
1744
1745
1746
		} elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'COMR')) { // 4.24  COMR Commercial frame (ID3v2.3+ only)
1747
			//   There may be more than one 'commercial frame' in a tag,
1748
			//   but no two may be identical
1749
			// <Header for 'Commercial frame', ID: 'COMR'>
1750
			// Text encoding      $xx
1751
			// Price string       <text string> $00
1752
			// Valid until        <text string>
1753
			// Contact URL        <text string> $00
1754
			// Received as        $xx
1755
			// Name of seller     <text string according to encoding> $00 (00)
1756
			// Description        <text string according to encoding> $00 (00)
1757
			// Picture MIME type  <string> $00
1758
			// Seller logo        <binary data>
1759
1760
			$frame_offset = 0;
1761
			$frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1762
			$frame_textencoding_terminator = $this->TextEncodingTerminatorLookup($frame_textencoding);
1763 View Code Duplication
			if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 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...
1764
				$this->warning('Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding');
1765
				$frame_textencoding_terminator = "\x00";
1766
			}
1767
1768
			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1769
			$frame_pricestring = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1770
			$frame_offset = $frame_terminatorpos + strlen("\x00");
1771
			$frame_rawpricearray = explode('/', $frame_pricestring);
1772
			foreach ($frame_rawpricearray as $key => $val) {
1773
				$frame_currencyid = substr($val, 0, 3);
1774
				$parsedFrame['price'][$frame_currencyid]['currency'] = $this->LookupCurrencyUnits($frame_currencyid);
1775
				$parsedFrame['price'][$frame_currencyid]['value']    = substr($val, 3);
1776
			}
1777
1778
			$frame_datestring = substr($parsedFrame['data'], $frame_offset, 8);
1779
			$frame_offset += 8;
1780
1781
			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1782
			$frame_contacturl = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1783
			$frame_offset = $frame_terminatorpos + strlen("\x00");
1784
1785
			$frame_receivedasid = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1786
1787
			$frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
1788 View Code Duplication
			if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
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...
1789
				$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1790
			}
1791
			$frame_sellername = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1792
			if (ord($frame_sellername) === 0) {
1793
				$frame_sellername = '';
1794
			}
1795
			$frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
1796
1797
			$frame_terminatorpos = strpos($parsedFrame['data'], $frame_textencoding_terminator, $frame_offset);
1798 View Code Duplication
			if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($frame_textencoding_terminator), 1)) === 0) {
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...
1799
				$frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
1800
			}
1801
			$parsedFrame['description'] = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1802
			$parsedFrame['description'] = $this->MakeUTF16emptyStringEmpty($parsedFrame['description']);
1803
			$frame_offset = $frame_terminatorpos + strlen($frame_textencoding_terminator);
1804
1805
			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1806
			$frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1807
			$frame_offset = $frame_terminatorpos + strlen("\x00");
1808
1809
			$frame_sellerlogo = substr($parsedFrame['data'], $frame_offset);
1810
1811
			$parsedFrame['encodingid']        = $frame_textencoding;
1812
			$parsedFrame['encoding']          = $this->TextEncodingNameLookup($frame_textencoding);
1813
1814
			$parsedFrame['pricevaliduntil']   = $frame_datestring;
1815
			$parsedFrame['contacturl']        = $frame_contacturl;
1816
			$parsedFrame['receivedasid']      = $frame_receivedasid;
1817
			$parsedFrame['receivedas']        = $this->COMRReceivedAsLookup($frame_receivedasid);
1818
			$parsedFrame['sellername']        = $frame_sellername;
1819
			$parsedFrame['mime']              = $frame_mimetype;
1820
			$parsedFrame['logo']              = $frame_sellerlogo;
1821
			unset($parsedFrame['data']);
1822
1823
1824
		} elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'ENCR')) { // 4.25  ENCR Encryption method registration (ID3v2.3+ only)
1825
			//   There may be several 'ENCR' frames in a tag,
1826
			//   but only one containing the same symbol
1827
			//   and only one containing the same owner identifier
1828
			// <Header for 'Encryption method registration', ID: 'ENCR'>
1829
			// Owner identifier    <text string> $00
1830
			// Method symbol       $xx
1831
			// Encryption data     <binary data>
1832
1833
			$frame_offset = 0;
1834
			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1835
			$frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1836
			if (ord($frame_ownerid) === 0) {
1837
				$frame_ownerid = '';
1838
			}
1839
			$frame_offset = $frame_terminatorpos + strlen("\x00");
1840
1841
			$parsedFrame['ownerid']      = $frame_ownerid;
1842
			$parsedFrame['methodsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1843
			$parsedFrame['data']         = (string) substr($parsedFrame['data'], $frame_offset);
1844
1845
1846
		} elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GRID')) { // 4.26  GRID Group identification registration (ID3v2.3+ only)
1847
1848
			//   There may be several 'GRID' frames in a tag,
1849
			//   but only one containing the same symbol
1850
			//   and only one containing the same owner identifier
1851
			// <Header for 'Group ID registration', ID: 'GRID'>
1852
			// Owner identifier      <text string> $00
1853
			// Group symbol          $xx
1854
			// Group dependent data  <binary data>
1855
1856
			$frame_offset = 0;
1857
			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1858
			$frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1859
			if (ord($frame_ownerid) === 0) {
1860
				$frame_ownerid = '';
1861
			}
1862
			$frame_offset = $frame_terminatorpos + strlen("\x00");
1863
1864
			$parsedFrame['ownerid']       = $frame_ownerid;
1865
			$parsedFrame['groupsymbol']   = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1866
			$parsedFrame['data']          = (string) substr($parsedFrame['data'], $frame_offset);
1867
1868
1869
		} elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'PRIV')) { // 4.27  PRIV Private frame (ID3v2.3+ only)
1870
			//   The tag may contain more than one 'PRIV' frame
1871
			//   but only with different contents
1872
			// <Header for 'Private frame', ID: 'PRIV'>
1873
			// Owner identifier      <text string> $00
1874
			// The private data      <binary data>
1875
1876
			$frame_offset = 0;
1877
			$frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
1878
			$frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
1879
			if (ord($frame_ownerid) === 0) {
1880
				$frame_ownerid = '';
1881
			}
1882
			$frame_offset = $frame_terminatorpos + strlen("\x00");
1883
1884
			$parsedFrame['ownerid'] = $frame_ownerid;
1885
			$parsedFrame['data']    = (string) substr($parsedFrame['data'], $frame_offset);
1886
1887
1888
		} elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'SIGN')) { // 4.28  SIGN Signature frame (ID3v2.4+ only)
1889
			//   There may be more than one 'signature frame' in a tag,
1890
			//   but no two may be identical
1891
			// <Header for 'Signature frame', ID: 'SIGN'>
1892
			// Group symbol      $xx
1893
			// Signature         <binary data>
1894
1895
			$frame_offset = 0;
1896
			$parsedFrame['groupsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1897
			$parsedFrame['data']        = (string) substr($parsedFrame['data'], $frame_offset);
1898
1899
1900
		} elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'SEEK')) { // 4.29  SEEK Seek frame (ID3v2.4+ only)
1901
			//   There may only be one 'seek frame' in a tag
1902
			// <Header for 'Seek frame', ID: 'SEEK'>
1903
			// Minimum offset to next tag       $xx xx xx xx
1904
1905
			$frame_offset = 0;
1906
			$parsedFrame['data']          = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1907
1908
1909
		} elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'ASPI')) { // 4.30  ASPI Audio seek point index (ID3v2.4+ only)
1910
			//   There may only be one 'audio seek point index' frame in a tag
1911
			// <Header for 'Seek Point Index', ID: 'ASPI'>
1912
			// Indexed data start (S)         $xx xx xx xx
1913
			// Indexed data length (L)        $xx xx xx xx
1914
			// Number of index points (N)     $xx xx
1915
			// Bits per index point (b)       $xx
1916
			//   Then for every index point the following data is included:
1917
			// Fraction at index (Fi)          $xx (xx)
1918
1919
			$frame_offset = 0;
1920
			$parsedFrame['datastart'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1921
			$frame_offset += 4;
1922
			$parsedFrame['indexeddatalength'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1923
			$frame_offset += 4;
1924
			$parsedFrame['indexpoints'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
1925
			$frame_offset += 2;
1926
			$parsedFrame['bitsperpoint'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
1927
			$frame_bytesperpoint = ceil($parsedFrame['bitsperpoint'] / 8);
1928
			for ($i = 0; $i < $parsedFrame['indexpoints']; $i++) {
1929
				$parsedFrame['indexes'][$i] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesperpoint));
1930
				$frame_offset += $frame_bytesperpoint;
1931
			}
1932
			unset($parsedFrame['data']);
1933
1934
		} elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RGAD')) { // Replay Gain Adjustment
1935
			// http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html
1936
			//   There may only be one 'RGAD' frame in a tag
1937
			// <Header for 'Replay Gain Adjustment', ID: 'RGAD'>
1938
			// Peak Amplitude                      $xx $xx $xx $xx
1939
			// Radio Replay Gain Adjustment        %aaabbbcd %dddddddd
1940
			// Audiophile Replay Gain Adjustment   %aaabbbcd %dddddddd
1941
			//   a - name code
1942
			//   b - originator code
1943
			//   c - sign bit
1944
			//   d - replay gain adjustment
1945
1946
			$frame_offset = 0;
1947
			$parsedFrame['peakamplitude'] = getid3_lib::BigEndian2Float(substr($parsedFrame['data'], $frame_offset, 4));
1948
			$frame_offset += 4;
1949
			$rg_track_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2));
1950
			$frame_offset += 2;
1951
			$rg_album_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2));
1952
			$frame_offset += 2;
1953
			$parsedFrame['raw']['track']['name']       = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 0, 3));
1954
			$parsedFrame['raw']['track']['originator'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 3, 3));
1955
			$parsedFrame['raw']['track']['signbit']    = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 6, 1));
1956
			$parsedFrame['raw']['track']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 7, 9));
1957
			$parsedFrame['raw']['album']['name']       = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 0, 3));
1958
			$parsedFrame['raw']['album']['originator'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 3, 3));
1959
			$parsedFrame['raw']['album']['signbit']    = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 6, 1));
1960
			$parsedFrame['raw']['album']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 7, 9));
1961
			$parsedFrame['track']['name']       = getid3_lib::RGADnameLookup($parsedFrame['raw']['track']['name']);
1962
			$parsedFrame['track']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['track']['originator']);
1963
			$parsedFrame['track']['adjustment'] = getid3_lib::RGADadjustmentLookup($parsedFrame['raw']['track']['adjustment'], $parsedFrame['raw']['track']['signbit']);
1964
			$parsedFrame['album']['name']       = getid3_lib::RGADnameLookup($parsedFrame['raw']['album']['name']);
1965
			$parsedFrame['album']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['album']['originator']);
1966
			$parsedFrame['album']['adjustment'] = getid3_lib::RGADadjustmentLookup($parsedFrame['raw']['album']['adjustment'], $parsedFrame['raw']['album']['signbit']);
1967
1968
			$info['replay_gain']['track']['peak']       = $parsedFrame['peakamplitude'];
1969
			$info['replay_gain']['track']['originator'] = $parsedFrame['track']['originator'];
1970
			$info['replay_gain']['track']['adjustment'] = $parsedFrame['track']['adjustment'];
1971
			$info['replay_gain']['album']['originator'] = $parsedFrame['album']['originator'];
1972
			$info['replay_gain']['album']['adjustment'] = $parsedFrame['album']['adjustment'];
1973
1974
			unset($parsedFrame['data']);
1975
1976
		} elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'CHAP')) { // CHAP Chapters frame (ID3v2.3+ only)
1977
			// http://id3.org/id3v2-chapters-1.0
1978
			// <ID3v2.3 or ID3v2.4 frame header, ID: "CHAP">           (10 bytes)
1979
			// Element ID      <text string> $00
1980
			// Start time      $xx xx xx xx
1981
			// End time        $xx xx xx xx
1982
			// Start offset    $xx xx xx xx
1983
			// End offset      $xx xx xx xx
1984
			// <Optional embedded sub-frames>
1985
1986
			$frame_offset = 0;
1987
			@list($parsedFrame['element_id']) = explode("\x00", $parsedFrame['data'], 2);
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...
1988
			$frame_offset += strlen($parsedFrame['element_id']."\x00");
1989
			$parsedFrame['time_begin'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1990
			$frame_offset += 4;
1991
			$parsedFrame['time_end']   = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1992
			$frame_offset += 4;
1993 View Code Duplication
			if (substr($parsedFrame['data'], $frame_offset, 4) != "\xFF\xFF\xFF\xFF") {
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...
1994
				// "If these bytes are all set to 0xFF then the value should be ignored and the start time value should be utilized."
1995
				$parsedFrame['offset_begin'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
1996
			}
1997
			$frame_offset += 4;
1998 View Code Duplication
			if (substr($parsedFrame['data'], $frame_offset, 4) != "\xFF\xFF\xFF\xFF") {
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...
1999
				// "If these bytes are all set to 0xFF then the value should be ignored and the start time value should be utilized."
2000
				$parsedFrame['offset_end']   = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
2001
			}
2002
			$frame_offset += 4;
2003
2004
			if ($frame_offset < strlen($parsedFrame['data'])) {
2005
				$parsedFrame['subframes'] = array();
2006
				while ($frame_offset < strlen($parsedFrame['data'])) {
2007
					// <Optional embedded sub-frames>
2008
					$subframe = array();
2009
					$subframe['name']      =                           substr($parsedFrame['data'], $frame_offset, 4);
2010
					$frame_offset += 4;
2011
					$subframe['size']      = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
2012
					$frame_offset += 4;
2013
					$subframe['flags_raw'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
2014
					$frame_offset += 2;
2015 View Code Duplication
					if ($subframe['size'] > (strlen($parsedFrame['data']) - $frame_offset)) {
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...
2016
						$this->warning('CHAP subframe "'.$subframe['name'].'" at frame offset '.$frame_offset.' claims to be "'.$subframe['size'].'" bytes, which is more than the available data ('.(strlen($parsedFrame['data']) - $frame_offset).' bytes)');
2017
						break;
2018
					}
2019
					$subframe_rawdata = substr($parsedFrame['data'], $frame_offset, $subframe['size']);
2020
					$frame_offset += $subframe['size'];
2021
2022
					$subframe['encodingid'] = ord(substr($subframe_rawdata, 0, 1));
2023
					$subframe['text']       =     substr($subframe_rawdata, 1);
2024
					$subframe['encoding']   = $this->TextEncodingNameLookup($subframe['encodingid']);
2025
					$encoding_converted_text = trim(getid3_lib::iconv_fallback($subframe['encoding'], $info['encoding'], $subframe['text']));
2026 View Code Duplication
					switch (substr($encoding_converted_text, 0, 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...
2027
						case "\xFF\xFE":
2028
						case "\xFE\xFF":
2029
							switch (strtoupper($info['id3v2']['encoding'])) {
2030
								case 'ISO-8859-1':
2031
								case 'UTF-8':
2032
									$encoding_converted_text = substr($encoding_converted_text, 2);
2033
									// remove unwanted byte-order-marks
2034
									break;
2035
								default:
2036
									// ignore
2037
									break;
2038
							}
2039
							break;
2040
						default:
2041
							// do not remove BOM
2042
							break;
2043
					}
2044
2045
					switch ($subframe['name']) {
2046
						case 'TIT2':
2047
							$parsedFrame['chapter_name']        = $encoding_converted_text;
2048
							$parsedFrame['subframes'][] = $subframe;
2049
							break;
2050
						case 'TIT3':
2051
							$parsedFrame['chapter_description'] = $encoding_converted_text;
2052
							$parsedFrame['subframes'][] = $subframe;
2053
							break;
2054
						case 'WXXX':
2055
							list($subframe['chapter_url_description'], $subframe['chapter_url']) = explode("\x00", $encoding_converted_text, 2);
2056
							$parsedFrame['chapter_url'][$subframe['chapter_url_description']] = $subframe['chapter_url'];
2057
							$parsedFrame['subframes'][] = $subframe;
2058
							break;
2059
						case 'APIC':
2060
							if (preg_match('#^([^\\x00]+)*\\x00(.)([^\\x00]+)*\\x00(.+)$#s', $subframe['text'], $matches)) {
2061
								list($dummy, $subframe_apic_mime, $subframe_apic_picturetype, $subframe_apic_description, $subframe_apic_picturedata) = $matches;
2062
								$subframe['image_mime']   = trim(getid3_lib::iconv_fallback($subframe['encoding'], $info['encoding'], $subframe_apic_mime));
2063
								$subframe['picture_type'] = $this->APICPictureTypeLookup($subframe_apic_picturetype);
2064
								$subframe['description']  = trim(getid3_lib::iconv_fallback($subframe['encoding'], $info['encoding'], $subframe_apic_description));
2065
								if (strlen($this->TextEncodingTerminatorLookup($subframe['encoding'])) == 2) {
2066
									// the null terminator between "description" and "picture data" could be either 1 byte (ISO-8859-1, UTF-8) or two bytes (UTF-16)
2067
									// the above regex assumes one byte, if it's actually two then strip the second one here
2068
									$subframe_apic_picturedata = substr($subframe_apic_picturedata, 1);
2069
								}
2070
								$subframe['data'] = $subframe_apic_picturedata;
2071
								unset($dummy, $subframe_apic_mime, $subframe_apic_picturetype, $subframe_apic_description, $subframe_apic_picturedata);
2072
								unset($subframe['text'], $parsedFrame['text']);
2073
								$parsedFrame['subframes'][] = $subframe;
2074
								$parsedFrame['picture_present'] = true;
2075
							} else {
2076
								$this->warning('ID3v2.CHAP subframe #'.(count($parsedFrame['subframes']) + 1).' "'.$subframe['name'].'" not in expected format');
2077
							}
2078
							break;
2079
						default:
2080
							$this->warning('ID3v2.CHAP subframe "'.$subframe['name'].'" not handled (supported: TIT2, TIT3, WXXX, APIC)');
2081
							break;
2082
					}
2083
				}
2084
				unset($subframe_rawdata, $subframe, $encoding_converted_text);
2085
				unset($parsedFrame['data']); // debatable whether this this be here, without it the returned structure may contain a large amount of duplicate data if chapters contain APIC
2086
			}
2087
2088
			$id3v2_chapter_entry = array();
2089
			foreach (array('id', 'time_begin', 'time_end', 'offset_begin', 'offset_end', 'chapter_name', 'chapter_description', 'chapter_url', 'picture_present') as $id3v2_chapter_key) {
2090
				if (isset($parsedFrame[$id3v2_chapter_key])) {
2091
					$id3v2_chapter_entry[$id3v2_chapter_key] = $parsedFrame[$id3v2_chapter_key];
2092
				}
2093
			}
2094
			if (!isset($info['id3v2']['chapters'])) {
2095
				$info['id3v2']['chapters'] = array();
2096
			}
2097
			$info['id3v2']['chapters'][] = $id3v2_chapter_entry;
2098
			unset($id3v2_chapter_entry, $id3v2_chapter_key);
2099
2100
2101
		} elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'CTOC')) { // CTOC Chapters Table Of Contents frame (ID3v2.3+ only)
2102
			// http://id3.org/id3v2-chapters-1.0
2103
			// <ID3v2.3 or ID3v2.4 frame header, ID: "CTOC">           (10 bytes)
2104
			// Element ID      <text string> $00
2105
			// CTOC flags        %xx
2106
			// Entry count       $xx
2107
			// Child Element ID  <string>$00   /* zero or more child CHAP or CTOC entries */
2108
			// <Optional embedded sub-frames>
2109
2110
			$frame_offset = 0;
2111
			@list($parsedFrame['element_id']) = explode("\x00", $parsedFrame['data'], 2);
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...
2112
			$frame_offset += strlen($parsedFrame['element_id']."\x00");
2113
			$ctoc_flags_raw = ord(substr($parsedFrame['data'], $frame_offset, 1));
2114
			$frame_offset += 1;
2115
			$parsedFrame['entry_count'] = ord(substr($parsedFrame['data'], $frame_offset, 1));
2116
			$frame_offset += 1;
2117
2118
			$terminator_position = null;
2119
			for ($i = 0; $i < $parsedFrame['entry_count']; $i++) {
2120
				$terminator_position = strpos($parsedFrame['data'], "\x00", $frame_offset);
2121
				$parsedFrame['child_element_ids'][$i] = substr($parsedFrame['data'], $frame_offset, $terminator_position - $frame_offset);
2122
				$frame_offset = $terminator_position + 1;
2123
			}
2124
2125
			$parsedFrame['ctoc_flags']['ordered']   = (bool) ($ctoc_flags_raw & 0x01);
2126
			$parsedFrame['ctoc_flags']['top_level'] = (bool) ($ctoc_flags_raw & 0x03);
2127
2128
			unset($ctoc_flags_raw, $terminator_position);
2129
2130
			if ($frame_offset < strlen($parsedFrame['data'])) {
2131
				$parsedFrame['subframes'] = array();
2132
				while ($frame_offset < strlen($parsedFrame['data'])) {
2133
					// <Optional embedded sub-frames>
2134
					$subframe = array();
2135
					$subframe['name']      =                           substr($parsedFrame['data'], $frame_offset, 4);
2136
					$frame_offset += 4;
2137
					$subframe['size']      = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
2138
					$frame_offset += 4;
2139
					$subframe['flags_raw'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
2140
					$frame_offset += 2;
2141 View Code Duplication
					if ($subframe['size'] > (strlen($parsedFrame['data']) - $frame_offset)) {
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...
2142
						$this->warning('CTOS subframe "'.$subframe['name'].'" at frame offset '.$frame_offset.' claims to be "'.$subframe['size'].'" bytes, which is more than the available data ('.(strlen($parsedFrame['data']) - $frame_offset).' bytes)');
2143
						break;
2144
					}
2145
					$subframe_rawdata = substr($parsedFrame['data'], $frame_offset, $subframe['size']);
2146
					$frame_offset += $subframe['size'];
2147
2148
					$subframe['encodingid'] = ord(substr($subframe_rawdata, 0, 1));
2149
					$subframe['text']       =     substr($subframe_rawdata, 1);
2150
					$subframe['encoding']   = $this->TextEncodingNameLookup($subframe['encodingid']);
2151
					$encoding_converted_text = trim(getid3_lib::iconv_fallback($subframe['encoding'], $info['encoding'], $subframe['text']));;
2152 View Code Duplication
					switch (substr($encoding_converted_text, 0, 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...
2153
						case "\xFF\xFE":
2154
						case "\xFE\xFF":
2155
							switch (strtoupper($info['id3v2']['encoding'])) {
2156
								case 'ISO-8859-1':
2157
								case 'UTF-8':
2158
									$encoding_converted_text = substr($encoding_converted_text, 2);
2159
									// remove unwanted byte-order-marks
2160
									break;
2161
								default:
2162
									// ignore
2163
									break;
2164
							}
2165
							break;
2166
						default:
2167
							// do not remove BOM
2168
							break;
2169
					}
2170
2171
					if (($subframe['name'] == 'TIT2') || ($subframe['name'] == 'TIT3')) {
2172
						if ($subframe['name'] == 'TIT2') {
2173
							$parsedFrame['toc_name']        = $encoding_converted_text;
2174
						} elseif ($subframe['name'] == 'TIT3') {
2175
							$parsedFrame['toc_description'] = $encoding_converted_text;
2176
						}
2177
						$parsedFrame['subframes'][] = $subframe;
2178
					} else {
2179
						$this->warning('ID3v2.CTOC subframe "'.$subframe['name'].'" not handled (only TIT2 and TIT3)');
2180
					}
2181
				}
2182
				unset($subframe_rawdata, $subframe, $encoding_converted_text);
2183
			}
2184
2185
		}
2186
2187
		return true;
2188
	}
2189
2190
	/**
2191
	 * @param string $data
2192
	 *
2193
	 * @return string
2194
	 */
2195
	public function DeUnsynchronise($data) {
2196
		return str_replace("\xFF\x00", "\xFF", $data);
2197
	}
2198
2199
	/**
2200
	 * @param int $index
2201
	 *
2202
	 * @return string
2203
	 */
2204 View Code Duplication
	public function LookupExtendedHeaderRestrictionsTagSizeLimits($index) {
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...
2205
		static $LookupExtendedHeaderRestrictionsTagSizeLimits = array(
2206
			0x00 => 'No more than 128 frames and 1 MB total tag size',
2207
			0x01 => 'No more than 64 frames and 128 KB total tag size',
2208
			0x02 => 'No more than 32 frames and 40 KB total tag size',
2209
			0x03 => 'No more than 32 frames and 4 KB total tag size',
2210
		);
2211
		return (isset($LookupExtendedHeaderRestrictionsTagSizeLimits[$index]) ? $LookupExtendedHeaderRestrictionsTagSizeLimits[$index] : '');
2212
	}
2213
2214
	/**
2215
	 * @param int $index
2216
	 *
2217
	 * @return string
2218
	 */
2219
	public function LookupExtendedHeaderRestrictionsTextEncodings($index) {
2220
		static $LookupExtendedHeaderRestrictionsTextEncodings = array(
2221
			0x00 => 'No restrictions',
2222
			0x01 => 'Strings are only encoded with ISO-8859-1 or UTF-8',
2223
		);
2224
		return (isset($LookupExtendedHeaderRestrictionsTextEncodings[$index]) ? $LookupExtendedHeaderRestrictionsTextEncodings[$index] : '');
2225
	}
2226
2227
	/**
2228
	 * @param int $index
2229
	 *
2230
	 * @return string
2231
	 */
2232 View Code Duplication
	public function LookupExtendedHeaderRestrictionsTextFieldSize($index) {
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...
2233
		static $LookupExtendedHeaderRestrictionsTextFieldSize = array(
2234
			0x00 => 'No restrictions',
2235
			0x01 => 'No string is longer than 1024 characters',
2236
			0x02 => 'No string is longer than 128 characters',
2237
			0x03 => 'No string is longer than 30 characters',
2238
		);
2239
		return (isset($LookupExtendedHeaderRestrictionsTextFieldSize[$index]) ? $LookupExtendedHeaderRestrictionsTextFieldSize[$index] : '');
2240
	}
2241
2242
	/**
2243
	 * @param int $index
2244
	 *
2245
	 * @return string
2246
	 */
2247
	public function LookupExtendedHeaderRestrictionsImageEncoding($index) {
2248
		static $LookupExtendedHeaderRestrictionsImageEncoding = array(
2249
			0x00 => 'No restrictions',
2250
			0x01 => 'Images are encoded only with PNG or JPEG',
2251
		);
2252
		return (isset($LookupExtendedHeaderRestrictionsImageEncoding[$index]) ? $LookupExtendedHeaderRestrictionsImageEncoding[$index] : '');
2253
	}
2254
2255
	/**
2256
	 * @param int $index
2257
	 *
2258
	 * @return string
2259
	 */
2260 View Code Duplication
	public function LookupExtendedHeaderRestrictionsImageSizeSize($index) {
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...
2261
		static $LookupExtendedHeaderRestrictionsImageSizeSize = array(
2262
			0x00 => 'No restrictions',
2263
			0x01 => 'All images are 256x256 pixels or smaller',
2264
			0x02 => 'All images are 64x64 pixels or smaller',
2265
			0x03 => 'All images are exactly 64x64 pixels, unless required otherwise',
2266
		);
2267
		return (isset($LookupExtendedHeaderRestrictionsImageSizeSize[$index]) ? $LookupExtendedHeaderRestrictionsImageSizeSize[$index] : '');
2268
	}
2269
2270
	/**
2271
	 * @param string $currencyid
2272
	 *
2273
	 * @return string
2274
	 */
2275
	public function LookupCurrencyUnits($currencyid) {
2276
2277
		$begin = __LINE__;
2278
2279
		/** This is not a comment!
2280
2281
2282
			AED	Dirhams
2283
			AFA	Afghanis
2284
			ALL	Leke
2285
			AMD	Drams
2286
			ANG	Guilders
2287
			AOA	Kwanza
2288
			ARS	Pesos
2289
			ATS	Schillings
2290
			AUD	Dollars
2291
			AWG	Guilders
2292
			AZM	Manats
2293
			BAM	Convertible Marka
2294
			BBD	Dollars
2295
			BDT	Taka
2296
			BEF	Francs
2297
			BGL	Leva
2298
			BHD	Dinars
2299
			BIF	Francs
2300
			BMD	Dollars
2301
			BND	Dollars
2302
			BOB	Bolivianos
2303
			BRL	Brazil Real
2304
			BSD	Dollars
2305
			BTN	Ngultrum
2306
			BWP	Pulas
2307
			BYR	Rubles
2308
			BZD	Dollars
2309
			CAD	Dollars
2310
			CDF	Congolese Francs
2311
			CHF	Francs
2312
			CLP	Pesos
2313
			CNY	Yuan Renminbi
2314
			COP	Pesos
2315
			CRC	Colones
2316
			CUP	Pesos
2317
			CVE	Escudos
2318
			CYP	Pounds
2319
			CZK	Koruny
2320
			DEM	Deutsche Marks
2321
			DJF	Francs
2322
			DKK	Kroner
2323
			DOP	Pesos
2324
			DZD	Algeria Dinars
2325
			EEK	Krooni
2326
			EGP	Pounds
2327
			ERN	Nakfa
2328
			ESP	Pesetas
2329
			ETB	Birr
2330
			EUR	Euro
2331
			FIM	Markkaa
2332
			FJD	Dollars
2333
			FKP	Pounds
2334
			FRF	Francs
2335
			GBP	Pounds
2336
			GEL	Lari
2337
			GGP	Pounds
2338
			GHC	Cedis
2339
			GIP	Pounds
2340
			GMD	Dalasi
2341
			GNF	Francs
2342
			GRD	Drachmae
2343
			GTQ	Quetzales
2344
			GYD	Dollars
2345
			HKD	Dollars
2346
			HNL	Lempiras
2347
			HRK	Kuna
2348
			HTG	Gourdes
2349
			HUF	Forints
2350
			IDR	Rupiahs
2351
			IEP	Pounds
2352
			ILS	New Shekels
2353
			IMP	Pounds
2354
			INR	Rupees
2355
			IQD	Dinars
2356
			IRR	Rials
2357
			ISK	Kronur
2358
			ITL	Lire
2359
			JEP	Pounds
2360
			JMD	Dollars
2361
			JOD	Dinars
2362
			JPY	Yen
2363
			KES	Shillings
2364
			KGS	Soms
2365
			KHR	Riels
2366
			KMF	Francs
2367
			KPW	Won
2368
			KWD	Dinars
2369
			KYD	Dollars
2370
			KZT	Tenge
2371
			LAK	Kips
2372
			LBP	Pounds
2373
			LKR	Rupees
2374
			LRD	Dollars
2375
			LSL	Maloti
2376
			LTL	Litai
2377
			LUF	Francs
2378
			LVL	Lati
2379
			LYD	Dinars
2380
			MAD	Dirhams
2381
			MDL	Lei
2382
			MGF	Malagasy Francs
2383
			MKD	Denars
2384
			MMK	Kyats
2385
			MNT	Tugriks
2386
			MOP	Patacas
2387
			MRO	Ouguiyas
2388
			MTL	Liri
2389
			MUR	Rupees
2390
			MVR	Rufiyaa
2391
			MWK	Kwachas
2392
			MXN	Pesos
2393
			MYR	Ringgits
2394
			MZM	Meticais
2395
			NAD	Dollars
2396
			NGN	Nairas
2397
			NIO	Gold Cordobas
2398
			NLG	Guilders
2399
			NOK	Krone
2400
			NPR	Nepal Rupees
2401
			NZD	Dollars
2402
			OMR	Rials
2403
			PAB	Balboa
2404
			PEN	Nuevos Soles
2405
			PGK	Kina
2406
			PHP	Pesos
2407
			PKR	Rupees
2408
			PLN	Zlotych
2409
			PTE	Escudos
2410
			PYG	Guarani
2411
			QAR	Rials
2412
			ROL	Lei
2413
			RUR	Rubles
2414
			RWF	Rwanda Francs
2415
			SAR	Riyals
2416
			SBD	Dollars
2417
			SCR	Rupees
2418
			SDD	Dinars
2419
			SEK	Kronor
2420
			SGD	Dollars
2421
			SHP	Pounds
2422
			SIT	Tolars
2423
			SKK	Koruny
2424
			SLL	Leones
2425
			SOS	Shillings
2426
			SPL	Luigini
2427
			SRG	Guilders
2428
			STD	Dobras
2429
			SVC	Colones
2430
			SYP	Pounds
2431
			SZL	Emalangeni
2432
			THB	Baht
2433
			TJR	Rubles
2434
			TMM	Manats
2435
			TND	Dinars
2436
			TOP	Pa'anga
2437
			TRL	Liras
2438
			TTD	Dollars
2439
			TVD	Tuvalu Dollars
2440
			TWD	New Dollars
2441
			TZS	Shillings
2442
			UAH	Hryvnia
2443
			UGX	Shillings
2444
			USD	Dollars
2445
			UYU	Pesos
2446
			UZS	Sums
2447
			VAL	Lire
2448
			VEB	Bolivares
2449
			VND	Dong
2450
			VUV	Vatu
2451
			WST	Tala
2452
			XAF	Francs
2453
			XAG	Ounces
2454
			XAU	Ounces
2455
			XCD	Dollars
2456
			XDR	Special Drawing Rights
2457
			XPD	Ounces
2458
			XPF	Francs
2459
			XPT	Ounces
2460
			YER	Rials
2461
			YUM	New Dinars
2462
			ZAR	Rand
2463
			ZMK	Kwacha
2464
			ZWD	Zimbabwe Dollars
2465
2466
		*/
2467
2468
		return getid3_lib::EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-units');
2469
	}
2470
2471
	/**
2472
	 * @param string $currencyid
2473
	 *
2474
	 * @return string
2475
	 */
2476
	public function LookupCurrencyCountry($currencyid) {
2477
2478
		$begin = __LINE__;
2479
2480
		/** This is not a comment!
2481
2482
			AED	United Arab Emirates
2483
			AFA	Afghanistan
2484
			ALL	Albania
2485
			AMD	Armenia
2486
			ANG	Netherlands Antilles
2487
			AOA	Angola
2488
			ARS	Argentina
2489
			ATS	Austria
2490
			AUD	Australia
2491
			AWG	Aruba
2492
			AZM	Azerbaijan
2493
			BAM	Bosnia and Herzegovina
2494
			BBD	Barbados
2495
			BDT	Bangladesh
2496
			BEF	Belgium
2497
			BGL	Bulgaria
2498
			BHD	Bahrain
2499
			BIF	Burundi
2500
			BMD	Bermuda
2501
			BND	Brunei Darussalam
2502
			BOB	Bolivia
2503
			BRL	Brazil
2504
			BSD	Bahamas
2505
			BTN	Bhutan
2506
			BWP	Botswana
2507
			BYR	Belarus
2508
			BZD	Belize
2509
			CAD	Canada
2510
			CDF	Congo/Kinshasa
2511
			CHF	Switzerland
2512
			CLP	Chile
2513
			CNY	China
2514
			COP	Colombia
2515
			CRC	Costa Rica
2516
			CUP	Cuba
2517
			CVE	Cape Verde
2518
			CYP	Cyprus
2519
			CZK	Czech Republic
2520
			DEM	Germany
2521
			DJF	Djibouti
2522
			DKK	Denmark
2523
			DOP	Dominican Republic
2524
			DZD	Algeria
2525
			EEK	Estonia
2526
			EGP	Egypt
2527
			ERN	Eritrea
2528
			ESP	Spain
2529
			ETB	Ethiopia
2530
			EUR	Euro Member Countries
2531
			FIM	Finland
2532
			FJD	Fiji
2533
			FKP	Falkland Islands (Malvinas)
2534
			FRF	France
2535
			GBP	United Kingdom
2536
			GEL	Georgia
2537
			GGP	Guernsey
2538
			GHC	Ghana
2539
			GIP	Gibraltar
2540
			GMD	Gambia
2541
			GNF	Guinea
2542
			GRD	Greece
2543
			GTQ	Guatemala
2544
			GYD	Guyana
2545
			HKD	Hong Kong
2546
			HNL	Honduras
2547
			HRK	Croatia
2548
			HTG	Haiti
2549
			HUF	Hungary
2550
			IDR	Indonesia
2551
			IEP	Ireland (Eire)
2552
			ILS	Israel
2553
			IMP	Isle of Man
2554
			INR	India
2555
			IQD	Iraq
2556
			IRR	Iran
2557
			ISK	Iceland
2558
			ITL	Italy
2559
			JEP	Jersey
2560
			JMD	Jamaica
2561
			JOD	Jordan
2562
			JPY	Japan
2563
			KES	Kenya
2564
			KGS	Kyrgyzstan
2565
			KHR	Cambodia
2566
			KMF	Comoros
2567
			KPW	Korea
2568
			KWD	Kuwait
2569
			KYD	Cayman Islands
2570
			KZT	Kazakstan
2571
			LAK	Laos
2572
			LBP	Lebanon
2573
			LKR	Sri Lanka
2574
			LRD	Liberia
2575
			LSL	Lesotho
2576
			LTL	Lithuania
2577
			LUF	Luxembourg
2578
			LVL	Latvia
2579
			LYD	Libya
2580
			MAD	Morocco
2581
			MDL	Moldova
2582
			MGF	Madagascar
2583
			MKD	Macedonia
2584
			MMK	Myanmar (Burma)
2585
			MNT	Mongolia
2586
			MOP	Macau
2587
			MRO	Mauritania
2588
			MTL	Malta
2589
			MUR	Mauritius
2590
			MVR	Maldives (Maldive Islands)
2591
			MWK	Malawi
2592
			MXN	Mexico
2593
			MYR	Malaysia
2594
			MZM	Mozambique
2595
			NAD	Namibia
2596
			NGN	Nigeria
2597
			NIO	Nicaragua
2598
			NLG	Netherlands (Holland)
2599
			NOK	Norway
2600
			NPR	Nepal
2601
			NZD	New Zealand
2602
			OMR	Oman
2603
			PAB	Panama
2604
			PEN	Peru
2605
			PGK	Papua New Guinea
2606
			PHP	Philippines
2607
			PKR	Pakistan
2608
			PLN	Poland
2609
			PTE	Portugal
2610
			PYG	Paraguay
2611
			QAR	Qatar
2612
			ROL	Romania
2613
			RUR	Russia
2614
			RWF	Rwanda
2615
			SAR	Saudi Arabia
2616
			SBD	Solomon Islands
2617
			SCR	Seychelles
2618
			SDD	Sudan
2619
			SEK	Sweden
2620
			SGD	Singapore
2621
			SHP	Saint Helena
2622
			SIT	Slovenia
2623
			SKK	Slovakia
2624
			SLL	Sierra Leone
2625
			SOS	Somalia
2626
			SPL	Seborga
2627
			SRG	Suriname
2628
			STD	São Tome and Principe
2629
			SVC	El Salvador
2630
			SYP	Syria
2631
			SZL	Swaziland
2632
			THB	Thailand
2633
			TJR	Tajikistan
2634
			TMM	Turkmenistan
2635
			TND	Tunisia
2636
			TOP	Tonga
2637
			TRL	Turkey
2638
			TTD	Trinidad and Tobago
2639
			TVD	Tuvalu
2640
			TWD	Taiwan
2641
			TZS	Tanzania
2642
			UAH	Ukraine
2643
			UGX	Uganda
2644
			USD	United States of America
2645
			UYU	Uruguay
2646
			UZS	Uzbekistan
2647
			VAL	Vatican City
2648
			VEB	Venezuela
2649
			VND	Viet Nam
2650
			VUV	Vanuatu
2651
			WST	Samoa
2652
			XAF	Communauté Financière Africaine
2653
			XAG	Silver
2654
			XAU	Gold
2655
			XCD	East Caribbean
2656
			XDR	International Monetary Fund
2657
			XPD	Palladium
2658
			XPF	Comptoirs Français du Pacifique
2659
			XPT	Platinum
2660
			YER	Yemen
2661
			YUM	Yugoslavia
2662
			ZAR	South Africa
2663
			ZMK	Zambia
2664
			ZWD	Zimbabwe
2665
2666
		*/
2667
2668
		return getid3_lib::EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-country');
2669
	}
2670
2671
	/**
2672
	 * @param string $languagecode
2673
	 * @param bool   $casesensitive
2674
	 *
2675
	 * @return string
2676
	 */
2677
	public static function LanguageLookup($languagecode, $casesensitive=false) {
2678
2679
		if (!$casesensitive) {
2680
			$languagecode = strtolower($languagecode);
2681
		}
2682
2683
		// http://www.id3.org/id3v2.4.0-structure.txt
2684
		// [4.   ID3v2 frame overview]
2685
		// The three byte language field, present in several frames, is used to
2686
		// describe the language of the frame's content, according to ISO-639-2
2687
		// [ISO-639-2]. The language should be represented in lower case. If the
2688
		// language is not known the string "XXX" should be used.
2689
2690
2691
		// ISO 639-2 - http://www.id3.org/iso639-2.html
2692
2693
		$begin = __LINE__;
2694
2695
		/** This is not a comment!
2696
2697
			XXX	unknown
2698
			xxx	unknown
2699
			aar	Afar
2700
			abk	Abkhazian
2701
			ace	Achinese
2702
			ach	Acoli
2703
			ada	Adangme
2704
			afa	Afro-Asiatic (Other)
2705
			afh	Afrihili
2706
			afr	Afrikaans
2707
			aka	Akan
2708
			akk	Akkadian
2709
			alb	Albanian
2710
			ale	Aleut
2711
			alg	Algonquian Languages
2712
			amh	Amharic
2713
			ang	English, Old (ca. 450-1100)
2714
			apa	Apache Languages
2715
			ara	Arabic
2716
			arc	Aramaic
2717
			arm	Armenian
2718
			arn	Araucanian
2719
			arp	Arapaho
2720
			art	Artificial (Other)
2721
			arw	Arawak
2722
			asm	Assamese
2723
			ath	Athapascan Languages
2724
			ava	Avaric
2725
			ave	Avestan
2726
			awa	Awadhi
2727
			aym	Aymara
2728
			aze	Azerbaijani
2729
			bad	Banda
2730
			bai	Bamileke Languages
2731
			bak	Bashkir
2732
			bal	Baluchi
2733
			bam	Bambara
2734
			ban	Balinese
2735
			baq	Basque
2736
			bas	Basa
2737
			bat	Baltic (Other)
2738
			bej	Beja
2739
			bel	Byelorussian
2740
			bem	Bemba
2741
			ben	Bengali
2742
			ber	Berber (Other)
2743
			bho	Bhojpuri
2744
			bih	Bihari
2745
			bik	Bikol
2746
			bin	Bini
2747
			bis	Bislama
2748
			bla	Siksika
2749
			bnt	Bantu (Other)
2750
			bod	Tibetan
2751
			bra	Braj
2752
			bre	Breton
2753
			bua	Buriat
2754
			bug	Buginese
2755
			bul	Bulgarian
2756
			bur	Burmese
2757
			cad	Caddo
2758
			cai	Central American Indian (Other)
2759
			car	Carib
2760
			cat	Catalan
2761
			cau	Caucasian (Other)
2762
			ceb	Cebuano
2763
			cel	Celtic (Other)
2764
			ces	Czech
2765
			cha	Chamorro
2766
			chb	Chibcha
2767
			che	Chechen
2768
			chg	Chagatai
2769
			chi	Chinese
2770
			chm	Mari
2771
			chn	Chinook jargon
2772
			cho	Choctaw
2773
			chr	Cherokee
2774
			chu	Church Slavic
2775
			chv	Chuvash
2776
			chy	Cheyenne
2777
			cop	Coptic
2778
			cor	Cornish
2779
			cos	Corsican
2780
			cpe	Creoles and Pidgins, English-based (Other)
2781
			cpf	Creoles and Pidgins, French-based (Other)
2782
			cpp	Creoles and Pidgins, Portuguese-based (Other)
2783
			cre	Cree
2784
			crp	Creoles and Pidgins (Other)
2785
			cus	Cushitic (Other)
2786
			cym	Welsh
2787
			cze	Czech
2788
			dak	Dakota
2789
			dan	Danish
2790
			del	Delaware
2791
			deu	German
2792
			din	Dinka
2793
			div	Divehi
2794
			doi	Dogri
2795
			dra	Dravidian (Other)
2796
			dua	Duala
2797
			dum	Dutch, Middle (ca. 1050-1350)
2798
			dut	Dutch
2799
			dyu	Dyula
2800
			dzo	Dzongkha
2801
			efi	Efik
2802
			egy	Egyptian (Ancient)
2803
			eka	Ekajuk
2804
			ell	Greek, Modern (1453-)
2805
			elx	Elamite
2806
			eng	English
2807
			enm	English, Middle (ca. 1100-1500)
2808
			epo	Esperanto
2809
			esk	Eskimo (Other)
2810
			esl	Spanish
2811
			est	Estonian
2812
			eus	Basque
2813
			ewe	Ewe
2814
			ewo	Ewondo
2815
			fan	Fang
2816
			fao	Faroese
2817
			fas	Persian
2818
			fat	Fanti
2819
			fij	Fijian
2820
			fin	Finnish
2821
			fiu	Finno-Ugrian (Other)
2822
			fon	Fon
2823
			fra	French
2824
			fre	French
2825
			frm	French, Middle (ca. 1400-1600)
2826
			fro	French, Old (842- ca. 1400)
2827
			fry	Frisian
2828
			ful	Fulah
2829
			gaa	Ga
2830
			gae	Gaelic (Scots)
2831
			gai	Irish
2832
			gay	Gayo
2833
			gdh	Gaelic (Scots)
2834
			gem	Germanic (Other)
2835
			geo	Georgian
2836
			ger	German
2837
			gez	Geez
2838
			gil	Gilbertese
2839
			glg	Gallegan
2840
			gmh	German, Middle High (ca. 1050-1500)
2841
			goh	German, Old High (ca. 750-1050)
2842
			gon	Gondi
2843
			got	Gothic
2844
			grb	Grebo
2845
			grc	Greek, Ancient (to 1453)
2846
			gre	Greek, Modern (1453-)
2847
			grn	Guarani
2848
			guj	Gujarati
2849
			hai	Haida
2850
			hau	Hausa
2851
			haw	Hawaiian
2852
			heb	Hebrew
2853
			her	Herero
2854
			hil	Hiligaynon
2855
			him	Himachali
2856
			hin	Hindi
2857
			hmo	Hiri Motu
2858
			hun	Hungarian
2859
			hup	Hupa
2860
			hye	Armenian
2861
			iba	Iban
2862
			ibo	Igbo
2863
			ice	Icelandic
2864
			ijo	Ijo
2865
			iku	Inuktitut
2866
			ilo	Iloko
2867
			ina	Interlingua (International Auxiliary language Association)
2868
			inc	Indic (Other)
2869
			ind	Indonesian
2870
			ine	Indo-European (Other)
2871
			ine	Interlingue
2872
			ipk	Inupiak
2873
			ira	Iranian (Other)
2874
			iri	Irish
2875
			iro	Iroquoian uages
2876
			isl	Icelandic
2877
			ita	Italian
2878
			jav	Javanese
2879
			jaw	Javanese
2880
			jpn	Japanese
2881
			jpr	Judeo-Persian
2882
			jrb	Judeo-Arabic
2883
			kaa	Kara-Kalpak
2884
			kab	Kabyle
2885
			kac	Kachin
2886
			kal	Greenlandic
2887
			kam	Kamba
2888
			kan	Kannada
2889
			kar	Karen
2890
			kas	Kashmiri
2891
			kat	Georgian
2892
			kau	Kanuri
2893
			kaw	Kawi
2894
			kaz	Kazakh
2895
			kha	Khasi
2896
			khi	Khoisan (Other)
2897
			khm	Khmer
2898
			kho	Khotanese
2899
			kik	Kikuyu
2900
			kin	Kinyarwanda
2901
			kir	Kirghiz
2902
			kok	Konkani
2903
			kom	Komi
2904
			kon	Kongo
2905
			kor	Korean
2906
			kpe	Kpelle
2907
			kro	Kru
2908
			kru	Kurukh
2909
			kua	Kuanyama
2910
			kum	Kumyk
2911
			kur	Kurdish
2912
			kus	Kusaie
2913
			kut	Kutenai
2914
			lad	Ladino
2915
			lah	Lahnda
2916
			lam	Lamba
2917
			lao	Lao
2918
			lat	Latin
2919
			lav	Latvian
2920
			lez	Lezghian
2921
			lin	Lingala
2922
			lit	Lithuanian
2923
			lol	Mongo
2924
			loz	Lozi
2925
			ltz	Letzeburgesch
2926
			lub	Luba-Katanga
2927
			lug	Ganda
2928
			lui	Luiseno
2929
			lun	Lunda
2930
			luo	Luo (Kenya and Tanzania)
2931
			mac	Macedonian
2932
			mad	Madurese
2933
			mag	Magahi
2934
			mah	Marshall
2935
			mai	Maithili
2936
			mak	Macedonian
2937
			mak	Makasar
2938
			mal	Malayalam
2939
			man	Mandingo
2940
			mao	Maori
2941
			map	Austronesian (Other)
2942
			mar	Marathi
2943
			mas	Masai
2944
			max	Manx
2945
			may	Malay
2946
			men	Mende
2947
			mga	Irish, Middle (900 - 1200)
2948
			mic	Micmac
2949
			min	Minangkabau
2950
			mis	Miscellaneous (Other)
2951
			mkh	Mon-Kmer (Other)
2952
			mlg	Malagasy
2953
			mlt	Maltese
2954
			mni	Manipuri
2955
			mno	Manobo Languages
2956
			moh	Mohawk
2957
			mol	Moldavian
2958
			mon	Mongolian
2959
			mos	Mossi
2960
			mri	Maori
2961
			msa	Malay
2962
			mul	Multiple Languages
2963
			mun	Munda Languages
2964
			mus	Creek
2965
			mwr	Marwari
2966
			mya	Burmese
2967
			myn	Mayan Languages
2968
			nah	Aztec
2969
			nai	North American Indian (Other)
2970
			nau	Nauru
2971
			nav	Navajo
2972
			nbl	Ndebele, South
2973
			nde	Ndebele, North
2974
			ndo	Ndongo
2975
			nep	Nepali
2976
			new	Newari
2977
			nic	Niger-Kordofanian (Other)
2978
			niu	Niuean
2979
			nla	Dutch
2980
			nno	Norwegian (Nynorsk)
2981
			non	Norse, Old
2982
			nor	Norwegian
2983
			nso	Sotho, Northern
2984
			nub	Nubian Languages
2985
			nya	Nyanja
2986
			nym	Nyamwezi
2987
			nyn	Nyankole
2988
			nyo	Nyoro
2989
			nzi	Nzima
2990
			oci	Langue d'Oc (post 1500)
2991
			oji	Ojibwa
2992
			ori	Oriya
2993
			orm	Oromo
2994
			osa	Osage
2995
			oss	Ossetic
2996
			ota	Turkish, Ottoman (1500 - 1928)
2997
			oto	Otomian Languages
2998
			paa	Papuan-Australian (Other)
2999
			pag	Pangasinan
3000
			pal	Pahlavi
3001
			pam	Pampanga
3002
			pan	Panjabi
3003
			pap	Papiamento
3004
			pau	Palauan
3005
			peo	Persian, Old (ca 600 - 400 B.C.)
3006
			per	Persian
3007
			phn	Phoenician
3008
			pli	Pali
3009
			pol	Polish
3010
			pon	Ponape
3011
			por	Portuguese
3012
			pra	Prakrit uages
3013
			pro	Provencal, Old (to 1500)
3014
			pus	Pushto
3015
			que	Quechua
3016
			raj	Rajasthani
3017
			rar	Rarotongan
3018
			roa	Romance (Other)
3019
			roh	Rhaeto-Romance
3020
			rom	Romany
3021
			ron	Romanian
3022
			rum	Romanian
3023
			run	Rundi
3024
			rus	Russian
3025
			sad	Sandawe
3026
			sag	Sango
3027
			sah	Yakut
3028
			sai	South American Indian (Other)
3029
			sal	Salishan Languages
3030
			sam	Samaritan Aramaic
3031
			san	Sanskrit
3032
			sco	Scots
3033
			scr	Serbo-Croatian
3034
			sel	Selkup
3035
			sem	Semitic (Other)
3036
			sga	Irish, Old (to 900)
3037
			shn	Shan
3038
			sid	Sidamo
3039
			sin	Singhalese
3040
			sio	Siouan Languages
3041
			sit	Sino-Tibetan (Other)
3042
			sla	Slavic (Other)
3043
			slk	Slovak
3044
			slo	Slovak
3045
			slv	Slovenian
3046
			smi	Sami Languages
3047
			smo	Samoan
3048
			sna	Shona
3049
			snd	Sindhi
3050
			sog	Sogdian
3051
			som	Somali
3052
			son	Songhai
3053
			sot	Sotho, Southern
3054
			spa	Spanish
3055
			sqi	Albanian
3056
			srd	Sardinian
3057
			srr	Serer
3058
			ssa	Nilo-Saharan (Other)
3059
			ssw	Siswant
3060
			ssw	Swazi
3061
			suk	Sukuma
3062
			sun	Sudanese
3063
			sus	Susu
3064
			sux	Sumerian
3065
			sve	Swedish
3066
			swa	Swahili
3067
			swe	Swedish
3068
			syr	Syriac
3069
			tah	Tahitian
3070
			tam	Tamil
3071
			tat	Tatar
3072
			tel	Telugu
3073
			tem	Timne
3074
			ter	Tereno
3075
			tgk	Tajik
3076
			tgl	Tagalog
3077
			tha	Thai
3078
			tib	Tibetan
3079
			tig	Tigre
3080
			tir	Tigrinya
3081
			tiv	Tivi
3082
			tli	Tlingit
3083
			tmh	Tamashek
3084
			tog	Tonga (Nyasa)
3085
			ton	Tonga (Tonga Islands)
3086
			tru	Truk
3087
			tsi	Tsimshian
3088
			tsn	Tswana
3089
			tso	Tsonga
3090
			tuk	Turkmen
3091
			tum	Tumbuka
3092
			tur	Turkish
3093
			tut	Altaic (Other)
3094
			twi	Twi
3095
			tyv	Tuvinian
3096
			uga	Ugaritic
3097
			uig	Uighur
3098
			ukr	Ukrainian
3099
			umb	Umbundu
3100
			und	Undetermined
3101
			urd	Urdu
3102
			uzb	Uzbek
3103
			vai	Vai
3104
			ven	Venda
3105
			vie	Vietnamese
3106
			vol	Volapük
3107
			vot	Votic
3108
			wak	Wakashan Languages
3109
			wal	Walamo
3110
			war	Waray
3111
			was	Washo
3112
			wel	Welsh
3113
			wen	Sorbian Languages
3114
			wol	Wolof
3115
			xho	Xhosa
3116
			yao	Yao
3117
			yap	Yap
3118
			yid	Yiddish
3119
			yor	Yoruba
3120
			zap	Zapotec
3121
			zen	Zenaga
3122
			zha	Zhuang
3123
			zho	Chinese
3124
			zul	Zulu
3125
			zun	Zuni
3126
3127
		*/
3128
3129
		return getid3_lib::EmbeddedLookup($languagecode, $begin, __LINE__, __FILE__, 'id3v2-languagecode');
3130
	}
3131
3132
	/**
3133
	 * @param int $index
3134
	 *
3135
	 * @return string
3136
	 */
3137
	public static function ETCOEventLookup($index) {
3138
		if (($index >= 0x17) && ($index <= 0xDF)) {
3139
			return 'reserved for future use';
3140
		}
3141
		if (($index >= 0xE0) && ($index <= 0xEF)) {
3142
			return 'not predefined synch 0-F';
3143
		}
3144
		if (($index >= 0xF0) && ($index <= 0xFC)) {
3145
			return 'reserved for future use';
3146
		}
3147
3148
		static $EventLookup = array(
3149
			0x00 => 'padding (has no meaning)',
3150
			0x01 => 'end of initial silence',
3151
			0x02 => 'intro start',
3152
			0x03 => 'main part start',
3153
			0x04 => 'outro start',
3154
			0x05 => 'outro end',
3155
			0x06 => 'verse start',
3156
			0x07 => 'refrain start',
3157
			0x08 => 'interlude start',
3158
			0x09 => 'theme start',
3159
			0x0A => 'variation start',
3160
			0x0B => 'key change',
3161
			0x0C => 'time change',
3162
			0x0D => 'momentary unwanted noise (Snap, Crackle & Pop)',
3163
			0x0E => 'sustained noise',
3164
			0x0F => 'sustained noise end',
3165
			0x10 => 'intro end',
3166
			0x11 => 'main part end',
3167
			0x12 => 'verse end',
3168
			0x13 => 'refrain end',
3169
			0x14 => 'theme end',
3170
			0x15 => 'profanity',
3171
			0x16 => 'profanity end',
3172
			0xFD => 'audio end (start of silence)',
3173
			0xFE => 'audio file ends',
3174
			0xFF => 'one more byte of events follows'
3175
		);
3176
3177
		return (isset($EventLookup[$index]) ? $EventLookup[$index] : '');
3178
	}
3179
3180
	/**
3181
	 * @param int $index
3182
	 *
3183
	 * @return string
3184
	 */
3185 View Code Duplication
	public static function SYTLContentTypeLookup($index) {
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...
3186
		static $SYTLContentTypeLookup = array(
3187
			0x00 => 'other',
3188
			0x01 => 'lyrics',
3189
			0x02 => 'text transcription',
3190
			0x03 => 'movement/part name', // (e.g. 'Adagio')
3191
			0x04 => 'events',             // (e.g. 'Don Quijote enters the stage')
3192
			0x05 => 'chord',              // (e.g. 'Bb F Fsus')
3193
			0x06 => 'trivia/\'pop up\' information',
3194
			0x07 => 'URLs to webpages',
3195
			0x08 => 'URLs to images'
3196
		);
3197
3198
		return (isset($SYTLContentTypeLookup[$index]) ? $SYTLContentTypeLookup[$index] : '');
3199
	}
3200
3201
	/**
3202
	 * @param int   $index
3203
	 * @param bool $returnarray
3204
	 *
3205
	 * @return array|string
3206
	 */
3207 View Code Duplication
	public static function APICPictureTypeLookup($index, $returnarray=false) {
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...
3208
		static $APICPictureTypeLookup = array(
3209
			0x00 => 'Other',
3210
			0x01 => '32x32 pixels \'file icon\' (PNG only)',
3211
			0x02 => 'Other file icon',
3212
			0x03 => 'Cover (front)',
3213
			0x04 => 'Cover (back)',
3214
			0x05 => 'Leaflet page',
3215
			0x06 => 'Media (e.g. label side of CD)',
3216
			0x07 => 'Lead artist/lead performer/soloist',
3217
			0x08 => 'Artist/performer',
3218
			0x09 => 'Conductor',
3219
			0x0A => 'Band/Orchestra',
3220
			0x0B => 'Composer',
3221
			0x0C => 'Lyricist/text writer',
3222
			0x0D => 'Recording Location',
3223
			0x0E => 'During recording',
3224
			0x0F => 'During performance',
3225
			0x10 => 'Movie/video screen capture',
3226
			0x11 => 'A bright coloured fish',
3227
			0x12 => 'Illustration',
3228
			0x13 => 'Band/artist logotype',
3229
			0x14 => 'Publisher/Studio logotype'
3230
		);
3231
		if ($returnarray) {
3232
			return $APICPictureTypeLookup;
3233
		}
3234
		return (isset($APICPictureTypeLookup[$index]) ? $APICPictureTypeLookup[$index] : '');
3235
	}
3236
3237
	/**
3238
	 * @param int $index
3239
	 *
3240
	 * @return string
3241
	 */
3242 View Code Duplication
	public static function COMRReceivedAsLookup($index) {
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...
3243
		static $COMRReceivedAsLookup = array(
3244
			0x00 => 'Other',
3245
			0x01 => 'Standard CD album with other songs',
3246
			0x02 => 'Compressed audio on CD',
3247
			0x03 => 'File over the Internet',
3248
			0x04 => 'Stream over the Internet',
3249
			0x05 => 'As note sheets',
3250
			0x06 => 'As note sheets in a book with other sheets',
3251
			0x07 => 'Music on other media',
3252
			0x08 => 'Non-musical merchandise'
3253
		);
3254
3255
		return (isset($COMRReceivedAsLookup[$index]) ? $COMRReceivedAsLookup[$index] : '');
3256
	}
3257
3258
	/**
3259
	 * @param int $index
3260
	 *
3261
	 * @return string
3262
	 */
3263 View Code Duplication
	public static function RVA2ChannelTypeLookup($index) {
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...
3264
		static $RVA2ChannelTypeLookup = array(
3265
			0x00 => 'Other',
3266
			0x01 => 'Master volume',
3267
			0x02 => 'Front right',
3268
			0x03 => 'Front left',
3269
			0x04 => 'Back right',
3270
			0x05 => 'Back left',
3271
			0x06 => 'Front centre',
3272
			0x07 => 'Back centre',
3273
			0x08 => 'Subwoofer'
3274
		);
3275
3276
		return (isset($RVA2ChannelTypeLookup[$index]) ? $RVA2ChannelTypeLookup[$index] : '');
3277
	}
3278
3279
	/**
3280
	 * @param string $framename
3281
	 *
3282
	 * @return string
3283
	 */
3284
	public static function FrameNameLongLookup($framename) {
3285
3286
		$begin = __LINE__;
3287
3288
		/** This is not a comment!
3289
3290
			AENC	Audio encryption
3291
			APIC	Attached picture
3292
			ASPI	Audio seek point index
3293
			BUF	Recommended buffer size
3294
			CNT	Play counter
3295
			COM	Comments
3296
			COMM	Comments
3297
			COMR	Commercial frame
3298
			CRA	Audio encryption
3299
			CRM	Encrypted meta frame
3300
			ENCR	Encryption method registration
3301
			EQU	Equalisation
3302
			EQU2	Equalisation (2)
3303
			EQUA	Equalisation
3304
			ETC	Event timing codes
3305
			ETCO	Event timing codes
3306
			GEO	General encapsulated object
3307
			GEOB	General encapsulated object
3308
			GRID	Group identification registration
3309
			IPL	Involved people list
3310
			IPLS	Involved people list
3311
			LINK	Linked information
3312
			LNK	Linked information
3313
			MCDI	Music CD identifier
3314
			MCI	Music CD Identifier
3315
			MLL	MPEG location lookup table
3316
			MLLT	MPEG location lookup table
3317
			OWNE	Ownership frame
3318
			PCNT	Play counter
3319
			PIC	Attached picture
3320
			POP	Popularimeter
3321
			POPM	Popularimeter
3322
			POSS	Position synchronisation frame
3323
			PRIV	Private frame
3324
			RBUF	Recommended buffer size
3325
			REV	Reverb
3326
			RVA	Relative volume adjustment
3327
			RVA2	Relative volume adjustment (2)
3328
			RVAD	Relative volume adjustment
3329
			RVRB	Reverb
3330
			SEEK	Seek frame
3331
			SIGN	Signature frame
3332
			SLT	Synchronised lyric/text
3333
			STC	Synced tempo codes
3334
			SYLT	Synchronised lyric/text
3335
			SYTC	Synchronised tempo codes
3336
			TAL	Album/Movie/Show title
3337
			TALB	Album/Movie/Show title
3338
			TBP	BPM (Beats Per Minute)
3339
			TBPM	BPM (beats per minute)
3340
			TCM	Composer
3341
			TCMP	Part of a compilation
3342
			TCO	Content type
3343
			TCOM	Composer
3344
			TCON	Content type
3345
			TCOP	Copyright message
3346
			TCP	Part of a compilation
3347
			TCR	Copyright message
3348
			TDA	Date
3349
			TDAT	Date
3350
			TDEN	Encoding time
3351
			TDLY	Playlist delay
3352
			TDOR	Original release time
3353
			TDRC	Recording time
3354
			TDRL	Release time
3355
			TDTG	Tagging time
3356
			TDY	Playlist delay
3357
			TEN	Encoded by
3358
			TENC	Encoded by
3359
			TEXT	Lyricist/Text writer
3360
			TFLT	File type
3361
			TFT	File type
3362
			TIM	Time
3363
			TIME	Time
3364
			TIPL	Involved people list
3365
			TIT1	Content group description
3366
			TIT2	Title/songname/content description
3367
			TIT3	Subtitle/Description refinement
3368
			TKE	Initial key
3369
			TKEY	Initial key
3370
			TLA	Language(s)
3371
			TLAN	Language(s)
3372
			TLE	Length
3373
			TLEN	Length
3374
			TMCL	Musician credits list
3375
			TMED	Media type
3376
			TMOO	Mood
3377
			TMT	Media type
3378
			TOA	Original artist(s)/performer(s)
3379
			TOAL	Original album/movie/show title
3380
			TOF	Original filename
3381
			TOFN	Original filename
3382
			TOL	Original Lyricist(s)/text writer(s)
3383
			TOLY	Original lyricist(s)/text writer(s)
3384
			TOPE	Original artist(s)/performer(s)
3385
			TOR	Original release year
3386
			TORY	Original release year
3387
			TOT	Original album/Movie/Show title
3388
			TOWN	File owner/licensee
3389
			TP1	Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group
3390
			TP2	Band/Orchestra/Accompaniment
3391
			TP3	Conductor/Performer refinement
3392
			TP4	Interpreted, remixed, or otherwise modified by
3393
			TPA	Part of a set
3394
			TPB	Publisher
3395
			TPE1	Lead performer(s)/Soloist(s)
3396
			TPE2	Band/orchestra/accompaniment
3397
			TPE3	Conductor/performer refinement
3398
			TPE4	Interpreted, remixed, or otherwise modified by
3399
			TPOS	Part of a set
3400
			TPRO	Produced notice
3401
			TPUB	Publisher
3402
			TRC	ISRC (International Standard Recording Code)
3403
			TRCK	Track number/Position in set
3404
			TRD	Recording dates
3405
			TRDA	Recording dates
3406
			TRK	Track number/Position in set
3407
			TRSN	Internet radio station name
3408
			TRSO	Internet radio station owner
3409
			TS2	Album-Artist sort order
3410
			TSA	Album sort order
3411
			TSC	Composer sort order
3412
			TSI	Size
3413
			TSIZ	Size
3414
			TSO2	Album-Artist sort order
3415
			TSOA	Album sort order
3416
			TSOC	Composer sort order
3417
			TSOP	Performer sort order
3418
			TSOT	Title sort order
3419
			TSP	Performer sort order
3420
			TSRC	ISRC (international standard recording code)
3421
			TSS	Software/hardware and settings used for encoding
3422
			TSSE	Software/Hardware and settings used for encoding
3423
			TSST	Set subtitle
3424
			TST	Title sort order
3425
			TT1	Content group description
3426
			TT2	Title/Songname/Content description
3427
			TT3	Subtitle/Description refinement
3428
			TXT	Lyricist/text writer
3429
			TXX	User defined text information frame
3430
			TXXX	User defined text information frame
3431
			TYE	Year
3432
			TYER	Year
3433
			UFI	Unique file identifier
3434
			UFID	Unique file identifier
3435
			ULT	Unsynchronised lyric/text transcription
3436
			USER	Terms of use
3437
			USLT	Unsynchronised lyric/text transcription
3438
			WAF	Official audio file webpage
3439
			WAR	Official artist/performer webpage
3440
			WAS	Official audio source webpage
3441
			WCM	Commercial information
3442
			WCOM	Commercial information
3443
			WCOP	Copyright/Legal information
3444
			WCP	Copyright/Legal information
3445
			WOAF	Official audio file webpage
3446
			WOAR	Official artist/performer webpage
3447
			WOAS	Official audio source webpage
3448
			WORS	Official Internet radio station homepage
3449
			WPAY	Payment
3450
			WPB	Publishers official webpage
3451
			WPUB	Publishers official webpage
3452
			WXX	User defined URL link frame
3453
			WXXX	User defined URL link frame
3454
			TFEA	Featured Artist
3455
			TSTU	Recording Studio
3456
			rgad	Replay Gain Adjustment
3457
3458
		*/
3459
3460
		return getid3_lib::EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_long');
3461
3462
		// Last three:
3463
		// from Helium2 [www.helium2.com]
3464
		// from http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html
3465
	}
3466
3467
	/**
3468
	 * @param string $framename
3469
	 *
3470
	 * @return string
3471
	 */
3472
	public static function FrameNameShortLookup($framename) {
3473
3474
		$begin = __LINE__;
3475
3476
		/** This is not a comment!
3477
3478
			AENC	audio_encryption
3479
			APIC	attached_picture
3480
			ASPI	audio_seek_point_index
3481
			BUF	recommended_buffer_size
3482
			CNT	play_counter
3483
			COM	comment
3484
			COMM	comment
3485
			COMR	commercial_frame
3486
			CRA	audio_encryption
3487
			CRM	encrypted_meta_frame
3488
			ENCR	encryption_method_registration
3489
			EQU	equalisation
3490
			EQU2	equalisation
3491
			EQUA	equalisation
3492
			ETC	event_timing_codes
3493
			ETCO	event_timing_codes
3494
			GEO	general_encapsulated_object
3495
			GEOB	general_encapsulated_object
3496
			GRID	group_identification_registration
3497
			IPL	involved_people_list
3498
			IPLS	involved_people_list
3499
			LINK	linked_information
3500
			LNK	linked_information
3501
			MCDI	music_cd_identifier
3502
			MCI	music_cd_identifier
3503
			MLL	mpeg_location_lookup_table
3504
			MLLT	mpeg_location_lookup_table
3505
			OWNE	ownership_frame
3506
			PCNT	play_counter
3507
			PIC	attached_picture
3508
			POP	popularimeter
3509
			POPM	popularimeter
3510
			POSS	position_synchronisation_frame
3511
			PRIV	private_frame
3512
			RBUF	recommended_buffer_size
3513
			REV	reverb
3514
			RVA	relative_volume_adjustment
3515
			RVA2	relative_volume_adjustment
3516
			RVAD	relative_volume_adjustment
3517
			RVRB	reverb
3518
			SEEK	seek_frame
3519
			SIGN	signature_frame
3520
			SLT	synchronised_lyric
3521
			STC	synced_tempo_codes
3522
			SYLT	synchronised_lyric
3523
			SYTC	synchronised_tempo_codes
3524
			TAL	album
3525
			TALB	album
3526
			TBP	bpm
3527
			TBPM	bpm
3528
			TCM	composer
3529
			TCMP	part_of_a_compilation
3530
			TCO	genre
3531
			TCOM	composer
3532
			TCON	genre
3533
			TCOP	copyright_message
3534
			TCP	part_of_a_compilation
3535
			TCR	copyright_message
3536
			TDA	date
3537
			TDAT	date
3538
			TDEN	encoding_time
3539
			TDLY	playlist_delay
3540
			TDOR	original_release_time
3541
			TDRC	recording_time
3542
			TDRL	release_time
3543
			TDTG	tagging_time
3544
			TDY	playlist_delay
3545
			TEN	encoded_by
3546
			TENC	encoded_by
3547
			TEXT	lyricist
3548
			TFLT	file_type
3549
			TFT	file_type
3550
			TIM	time
3551
			TIME	time
3552
			TIPL	involved_people_list
3553
			TIT1	content_group_description
3554
			TIT2	title
3555
			TIT3	subtitle
3556
			TKE	initial_key
3557
			TKEY	initial_key
3558
			TLA	language
3559
			TLAN	language
3560
			TLE	length
3561
			TLEN	length
3562
			TMCL	musician_credits_list
3563
			TMED	media_type
3564
			TMOO	mood
3565
			TMT	media_type
3566
			TOA	original_artist
3567
			TOAL	original_album
3568
			TOF	original_filename
3569
			TOFN	original_filename
3570
			TOL	original_lyricist
3571
			TOLY	original_lyricist
3572
			TOPE	original_artist
3573
			TOR	original_year
3574
			TORY	original_year
3575
			TOT	original_album
3576
			TOWN	file_owner
3577
			TP1	artist
3578
			TP2	band
3579
			TP3	conductor
3580
			TP4	remixer
3581
			TPA	part_of_a_set
3582
			TPB	publisher
3583
			TPE1	artist
3584
			TPE2	band
3585
			TPE3	conductor
3586
			TPE4	remixer
3587
			TPOS	part_of_a_set
3588
			TPRO	produced_notice
3589
			TPUB	publisher
3590
			TRC	isrc
3591
			TRCK	track_number
3592
			TRD	recording_dates
3593
			TRDA	recording_dates
3594
			TRK	track_number
3595
			TRSN	internet_radio_station_name
3596
			TRSO	internet_radio_station_owner
3597
			TS2	album_artist_sort_order
3598
			TSA	album_sort_order
3599
			TSC	composer_sort_order
3600
			TSI	size
3601
			TSIZ	size
3602
			TSO2	album_artist_sort_order
3603
			TSOA	album_sort_order
3604
			TSOC	composer_sort_order
3605
			TSOP	performer_sort_order
3606
			TSOT	title_sort_order
3607
			TSP	performer_sort_order
3608
			TSRC	isrc
3609
			TSS	encoder_settings
3610
			TSSE	encoder_settings
3611
			TSST	set_subtitle
3612
			TST	title_sort_order
3613
			TT1	content_group_description
3614
			TT2	title
3615
			TT3	subtitle
3616
			TXT	lyricist
3617
			TXX	text
3618
			TXXX	text
3619
			TYE	year
3620
			TYER	year
3621
			UFI	unique_file_identifier
3622
			UFID	unique_file_identifier
3623
			ULT	unsynchronised_lyric
3624
			USER	terms_of_use
3625
			USLT	unsynchronised_lyric
3626
			WAF	url_file
3627
			WAR	url_artist
3628
			WAS	url_source
3629
			WCM	commercial_information
3630
			WCOM	commercial_information
3631
			WCOP	copyright
3632
			WCP	copyright
3633
			WOAF	url_file
3634
			WOAR	url_artist
3635
			WOAS	url_source
3636
			WORS	url_station
3637
			WPAY	url_payment
3638
			WPB	url_publisher
3639
			WPUB	url_publisher
3640
			WXX	url_user
3641
			WXXX	url_user
3642
			TFEA	featured_artist
3643
			TSTU	recording_studio
3644
			rgad	replay_gain_adjustment
3645
3646
		*/
3647
3648
		return getid3_lib::EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_short');
3649
	}
3650
3651
	/**
3652
	 * @param string $encoding
3653
	 *
3654
	 * @return string
3655
	 */
3656
	public static function TextEncodingTerminatorLookup($encoding) {
3657
		// http://www.id3.org/id3v2.4.0-structure.txt
3658
		// Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings:
3659
		static $TextEncodingTerminatorLookup = array(
3660
			0   => "\x00",     // $00  ISO-8859-1. Terminated with $00.
3661
			1   => "\x00\x00", // $01  UTF-16 encoded Unicode with BOM. All strings in the same frame SHALL have the same byteorder. Terminated with $00 00.
3662
			2   => "\x00\x00", // $02  UTF-16BE encoded Unicode without BOM. Terminated with $00 00.
3663
			3   => "\x00",     // $03  UTF-8 encoded Unicode. Terminated with $00.
3664
			255 => "\x00\x00"
3665
		);
3666
		return (isset($TextEncodingTerminatorLookup[$encoding]) ? $TextEncodingTerminatorLookup[$encoding] : "\x00");
3667
	}
3668
3669
	/**
3670
	 * @param int $encoding
3671
	 *
3672
	 * @return string
3673
	 */
3674
	public static function TextEncodingNameLookup($encoding) {
3675
		// http://www.id3.org/id3v2.4.0-structure.txt
3676
		// Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings:
3677
		static $TextEncodingNameLookup = array(
3678
			0   => 'ISO-8859-1', // $00  ISO-8859-1. Terminated with $00.
3679
			1   => 'UTF-16',     // $01  UTF-16 encoded Unicode with BOM. All strings in the same frame SHALL have the same byteorder. Terminated with $00 00.
3680
			2   => 'UTF-16BE',   // $02  UTF-16BE encoded Unicode without BOM. Terminated with $00 00.
3681
			3   => 'UTF-8',      // $03  UTF-8 encoded Unicode. Terminated with $00.
3682
			255 => 'UTF-16BE'
3683
		);
3684
		return (isset($TextEncodingNameLookup[$encoding]) ? $TextEncodingNameLookup[$encoding] : 'ISO-8859-1');
3685
	}
3686
3687
	/**
3688
	 * @param string $string
3689
	 * @param string $terminator
3690
	 *
3691
	 * @return string
3692
	 */
3693
	public static function RemoveStringTerminator($string, $terminator) {
3694
		// Null terminator at end of comment string is somewhat ambiguous in the specification, may or may not be implemented by various taggers. Remove terminator only if present.
3695
		// https://github.com/JamesHeinrich/getID3/issues/121
3696
		// https://community.mp3tag.de/t/x-trailing-nulls-in-id3v2-comments/19227
3697
		if (substr($string, -strlen($terminator), strlen($terminator)) === $terminator) {
3698
			$string = substr($string, 0, -strlen($terminator));
3699
		}
3700
		return $string;
3701
	}
3702
3703
	/**
3704
	 * @param string $string
3705
	 *
3706
	 * @return string
3707
	 */
3708
	public static function MakeUTF16emptyStringEmpty($string) {
3709
		if (in_array($string, array("\x00", "\x00\x00", "\xFF\xFE", "\xFE\xFF"))) {
3710
			// if string only contains a BOM or terminator then make it actually an empty string
3711
			$string = '';
3712
		}
3713
		return $string;
3714
	}
3715
3716
	/**
3717
	 * @param string $framename
3718
	 * @param int    $id3v2majorversion
3719
	 *
3720
	 * @return bool|int
3721
	 */
3722
	public static function IsValidID3v2FrameName($framename, $id3v2majorversion) {
3723
		switch ($id3v2majorversion) {
3724
			case 2:
3725
				return preg_match('#[A-Z][A-Z0-9]{2}#', $framename);
3726
3727
			case 3:
3728
			case 4:
3729
				return preg_match('#[A-Z][A-Z0-9]{3}#', $framename);
3730
		}
3731
		return false;
3732
	}
3733
3734
	/**
3735
	 * @param string $numberstring
3736
	 * @param bool   $allowdecimal
3737
	 * @param bool   $allownegative
3738
	 *
3739
	 * @return bool
3740
	 */
3741
	public static function IsANumber($numberstring, $allowdecimal=false, $allownegative=false) {
3742
		for ($i = 0; $i < strlen($numberstring); $i++) {
3743
			if ((chr($numberstring[$i]) < chr('0')) || (chr($numberstring[$i]) > chr('9'))) {
3744
				if (($numberstring[$i] == '.') && $allowdecimal) {
3745
					// allowed
3746
				} elseif (($numberstring[$i] == '-') && $allownegative && ($i == 0)) {
3747
					// allowed
3748
				} else {
3749
					return false;
3750
				}
3751
			}
3752
		}
3753
		return true;
3754
	}
3755
3756
	/**
3757
	 * @param string $datestamp
3758
	 *
3759
	 * @return bool
3760
	 */
3761
	public static function IsValidDateStampString($datestamp) {
3762
		if (strlen($datestamp) != 8) {
3763
			return false;
3764
		}
3765
		if (!self::IsANumber($datestamp, false)) {
3766
			return false;
3767
		}
3768
		$year  = substr($datestamp, 0, 4);
3769
		$month = substr($datestamp, 4, 2);
3770
		$day   = substr($datestamp, 6, 2);
3771
		if (($year == 0) || ($month == 0) || ($day == 0)) {
3772
			return false;
3773
		}
3774
		if ($month > 12) {
3775
			return false;
3776
		}
3777
		if ($day > 31) {
3778
			return false;
3779
		}
3780
		if (($day > 30) && (($month == 4) || ($month == 6) || ($month == 9) || ($month == 11))) {
3781
			return false;
3782
		}
3783
		if (($day > 29) && ($month == 2)) {
3784
			return false;
3785
		}
3786
		return true;
3787
	}
3788
3789
	/**
3790
	 * @param int $majorversion
3791
	 *
3792
	 * @return int
3793
	 */
3794
	public static function ID3v2HeaderLength($majorversion) {
3795
		return (($majorversion == 2) ? 6 : 10);
3796
	}
3797
3798
	/**
3799
	 * @param string $frame_name
3800
	 *
3801
	 * @return string|false
3802
	 */
3803
	public static function ID3v22iTunesBrokenFrameName($frame_name) {
3804
		// iTunes (multiple versions) has been known to write ID3v2.3 style frames
3805
		// but use ID3v2.2 frame names, right-padded using either [space] or [null]
3806
		// to make them fit in the 4-byte frame name space of the ID3v2.3 frame.
3807
		// This function will detect and translate the corrupt frame name into ID3v2.3 standard.
3808
		static $ID3v22_iTunes_BrokenFrames = array(
3809
			'BUF' => 'RBUF', // Recommended buffer size
3810
			'CNT' => 'PCNT', // Play counter
3811
			'COM' => 'COMM', // Comments
3812
			'CRA' => 'AENC', // Audio encryption
3813
			'EQU' => 'EQUA', // Equalisation
3814
			'ETC' => 'ETCO', // Event timing codes
3815
			'GEO' => 'GEOB', // General encapsulated object
3816
			'IPL' => 'IPLS', // Involved people list
3817
			'LNK' => 'LINK', // Linked information
3818
			'MCI' => 'MCDI', // Music CD identifier
3819
			'MLL' => 'MLLT', // MPEG location lookup table
3820
			'PIC' => 'APIC', // Attached picture
3821
			'POP' => 'POPM', // Popularimeter
3822
			'REV' => 'RVRB', // Reverb
3823
			'RVA' => 'RVAD', // Relative volume adjustment
3824
			'SLT' => 'SYLT', // Synchronised lyric/text
3825
			'STC' => 'SYTC', // Synchronised tempo codes
3826
			'TAL' => 'TALB', // Album/Movie/Show title
3827
			'TBP' => 'TBPM', // BPM (beats per minute)
3828
			'TCM' => 'TCOM', // Composer
3829
			'TCO' => 'TCON', // Content type
3830
			'TCP' => 'TCMP', // Part of a compilation
3831
			'TCR' => 'TCOP', // Copyright message
3832
			'TDA' => 'TDAT', // Date
3833
			'TDY' => 'TDLY', // Playlist delay
3834
			'TEN' => 'TENC', // Encoded by
3835
			'TFT' => 'TFLT', // File type
3836
			'TIM' => 'TIME', // Time
3837
			'TKE' => 'TKEY', // Initial key
3838
			'TLA' => 'TLAN', // Language(s)
3839
			'TLE' => 'TLEN', // Length
3840
			'TMT' => 'TMED', // Media type
3841
			'TOA' => 'TOPE', // Original artist(s)/performer(s)
3842
			'TOF' => 'TOFN', // Original filename
3843
			'TOL' => 'TOLY', // Original lyricist(s)/text writer(s)
3844
			'TOR' => 'TORY', // Original release year
3845
			'TOT' => 'TOAL', // Original album/movie/show title
3846
			'TP1' => 'TPE1', // Lead performer(s)/Soloist(s)
3847
			'TP2' => 'TPE2', // Band/orchestra/accompaniment
3848
			'TP3' => 'TPE3', // Conductor/performer refinement
3849
			'TP4' => 'TPE4', // Interpreted, remixed, or otherwise modified by
3850
			'TPA' => 'TPOS', // Part of a set
3851
			'TPB' => 'TPUB', // Publisher
3852
			'TRC' => 'TSRC', // ISRC (international standard recording code)
3853
			'TRD' => 'TRDA', // Recording dates
3854
			'TRK' => 'TRCK', // Track number/Position in set
3855
			'TS2' => 'TSO2', // Album-Artist sort order
3856
			'TSA' => 'TSOA', // Album sort order
3857
			'TSC' => 'TSOC', // Composer sort order
3858
			'TSI' => 'TSIZ', // Size
3859
			'TSP' => 'TSOP', // Performer sort order
3860
			'TSS' => 'TSSE', // Software/Hardware and settings used for encoding
3861
			'TST' => 'TSOT', // Title sort order
3862
			'TT1' => 'TIT1', // Content group description
3863
			'TT2' => 'TIT2', // Title/songname/content description
3864
			'TT3' => 'TIT3', // Subtitle/Description refinement
3865
			'TXT' => 'TEXT', // Lyricist/Text writer
3866
			'TXX' => 'TXXX', // User defined text information frame
3867
			'TYE' => 'TYER', // Year
3868
			'UFI' => 'UFID', // Unique file identifier
3869
			'ULT' => 'USLT', // Unsynchronised lyric/text transcription
3870
			'WAF' => 'WOAF', // Official audio file webpage
3871
			'WAR' => 'WOAR', // Official artist/performer webpage
3872
			'WAS' => 'WOAS', // Official audio source webpage
3873
			'WCM' => 'WCOM', // Commercial information
3874
			'WCP' => 'WCOP', // Copyright/Legal information
3875
			'WPB' => 'WPUB', // Publishers official webpage
3876
			'WXX' => 'WXXX', // User defined URL link frame
3877
		);
3878
		if (strlen($frame_name) == 4) {
3879
			if ((substr($frame_name, 3, 1) == ' ') || (substr($frame_name, 3, 1) == "\x00")) {
3880
				if (isset($ID3v22_iTunes_BrokenFrames[substr($frame_name, 0, 3)])) {
3881
					return $ID3v22_iTunes_BrokenFrames[substr($frame_name, 0, 3)];
3882
				}
3883
			}
3884
		}
3885
		return false;
3886
	}
3887
3888
}
3889
3890