PageRenderTime 70ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/common/libraries/plugin/osflvplayer/flash/module.tag.id3v2.php

https://bitbucket.org/renaatdemuynck/chamilo
PHP | 3402 lines | 1525 code | 338 blank | 1539 comment | 454 complexity | b4029567fd0fbb6fd2a43f59d1efd273 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, LGPL-3.0, GPL-3.0, MIT, GPL-2.0
  1. <?php
  2. /////////////////////////////////////////////////////////////////
  3. /// getID3() by James Heinrich <info@getid3.org> //
  4. // available at http://getid3.sourceforge.net //
  5. // or http://www.getid3.org //
  6. /////////////////////////////////////////////////////////////////
  7. // See readme.txt for more details //
  8. /////////////////////////////////////////////////////////////////
  9. /// //
  10. // module.tag.id3v2.php //
  11. // module for analyzing ID3v2 tags //
  12. // dependencies: module.tag.id3v1.php //
  13. // ///
  14. /////////////////////////////////////////////////////////////////
  15. getid3_lib :: IncludeDependency(GETID3_INCLUDEPATH . 'module.tag.id3v1.php', __FILE__, true);
  16. class getid3_id3v2
  17. {
  18. function getid3_id3v2(&$fd, &$ThisFileInfo, $StartingOffset = 0)
  19. {
  20. // Overall tag structure:
  21. // +-----------------------------+
  22. // | Header (10 bytes) |
  23. // +-----------------------------+
  24. // | Extended Header |
  25. // | (variable length, OPTIONAL) |
  26. // +-----------------------------+
  27. // | Frames (variable length) |
  28. // +-----------------------------+
  29. // | Padding |
  30. // | (variable length, OPTIONAL) |
  31. // +-----------------------------+
  32. // | Footer (10 bytes, OPTIONAL) |
  33. // +-----------------------------+
  34. // Header
  35. // ID3v2/file identifier "ID3"
  36. // ID3v2 version $04 00
  37. // ID3v2 flags (%ab000000 in v2.2, %abc00000 in v2.3, %abcd0000 in v2.4.x)
  38. // ID3v2 size 4 * %0xxxxxxx
  39. // shortcuts
  40. $ThisFileInfo['id3v2']['header'] = true;
  41. $thisfile_id3v2 = &$ThisFileInfo['id3v2'];
  42. $thisfile_id3v2['flags'] = array();
  43. $thisfile_id3v2_flags = &$thisfile_id3v2['flags'];
  44. fseek($fd, $StartingOffset, SEEK_SET);
  45. $header = fread($fd, 10);
  46. if (substr($header, 0, 3) == 'ID3')
  47. {
  48. $thisfile_id3v2['majorversion'] = ord($header{3});
  49. $thisfile_id3v2['minorversion'] = ord($header{4});
  50. // shortcut
  51. $id3v2_majorversion = &$thisfile_id3v2['majorversion'];
  52. }
  53. else
  54. {
  55. unset($ThisFileInfo['id3v2']);
  56. return false;
  57. }
  58. if ($id3v2_majorversion > 4)
  59. { // this script probably won't correctly parse ID3v2.5.x and above (if it ever exists)
  60. $ThisFileInfo['error'][] = 'this script only parses up to ID3v2.4.x - this tag is ID3v2.' . $id3v2_majorversion . '.' . $thisfile_id3v2['minorversion'];
  61. return false;
  62. }
  63. $id3_flags = ord($header{5});
  64. switch ($id3v2_majorversion)
  65. {
  66. case 2 :
  67. // %ab000000 in v2.2
  68. $thisfile_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80); // a - Unsynchronisation
  69. $thisfile_id3v2_flags['compression'] = (bool) ($id3_flags & 0x40); // b - Compression
  70. break;
  71. case 3 :
  72. // %abc00000 in v2.3
  73. $thisfile_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80); // a - Unsynchronisation
  74. $thisfile_id3v2_flags['exthead'] = (bool) ($id3_flags & 0x40); // b - Extended header
  75. $thisfile_id3v2_flags['experim'] = (bool) ($id3_flags & 0x20); // c - Experimental indicator
  76. break;
  77. case 4 :
  78. // %abcd0000 in v2.4
  79. $thisfile_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80); // a - Unsynchronisation
  80. $thisfile_id3v2_flags['exthead'] = (bool) ($id3_flags & 0x40); // b - Extended header
  81. $thisfile_id3v2_flags['experim'] = (bool) ($id3_flags & 0x20); // c - Experimental indicator
  82. $thisfile_id3v2_flags['isfooter'] = (bool) ($id3_flags & 0x10); // d - Footer present
  83. break;
  84. }
  85. $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
  86. $thisfile_id3v2['tag_offset_start'] = $StartingOffset;
  87. $thisfile_id3v2['tag_offset_end'] = $thisfile_id3v2['tag_offset_start'] + $thisfile_id3v2['headerlength'];
  88. // Extended Header
  89. if (isset($thisfile_id3v2_flags['exthead']) && $thisfile_id3v2_flags['exthead'])
  90. {
  91. // Extended header size 4 * %0xxxxxxx
  92. // Number of flag bytes $01
  93. // Extended Flags $xx
  94. // Where the 'Extended header size' is the size of the whole extended header, stored as a 32 bit synchsafe integer.
  95. $thisfile_id3v2['exthead_length'] = getid3_lib :: BigEndian2Int(fread($fd, 4), 1);
  96. $thisfile_id3v2['exthead_flag_bytes'] = ord(fread($fd, 1));
  97. if ($thisfile_id3v2['exthead_flag_bytes'] == 1)
  98. {
  99. // The extended flags field, with its size described by 'number of flag bytes', is defined as:
  100. // %0bcd0000
  101. // b - Tag is an update
  102. // Flag data length $00
  103. // c - CRC data present
  104. // Flag data length $05
  105. // Total frame CRC 5 * %0xxxxxxx
  106. // d - Tag restrictions
  107. // Flag data length $01
  108. $extheaderflags = fread($fd, $thisfile_id3v2['exthead_flag_bytes']);
  109. $id3_exthead_flags = getid3_lib :: BigEndian2Bin(substr($header, 5, 1));
  110. $thisfile_id3v2['exthead_flags']['update'] = substr($id3_exthead_flags, 1, 1);
  111. $thisfile_id3v2['exthead_flags']['CRC'] = substr($id3_exthead_flags, 2, 1);
  112. if ($thisfile_id3v2['exthead_flags']['CRC'])
  113. {
  114. $extheaderrawCRC = fread($fd, 5);
  115. $thisfile_id3v2['exthead_flags']['CRC'] = getid3_lib :: BigEndian2Int($extheaderrawCRC, 1);
  116. }
  117. $thisfile_id3v2['exthead_flags']['restrictions'] = substr($id3_exthead_flags, 3, 1);
  118. if ($thisfile_id3v2['exthead_flags']['restrictions'])
  119. {
  120. // Restrictions %ppqrrstt
  121. $extheaderrawrestrictions = fread($fd, 1);
  122. $thisfile_id3v2['exthead_flags']['restrictions_tagsize'] = (bindec('11000000') & ord($extheaderrawrestrictions)) >> 6; // p - Tag size restrictions
  123. $thisfile_id3v2['exthead_flags']['restrictions_textenc'] = (bindec('00100000') & ord($extheaderrawrestrictions)) >> 5; // q - Text encoding restrictions
  124. $thisfile_id3v2['exthead_flags']['restrictions_textsize'] = (bindec('00011000') & ord($extheaderrawrestrictions)) >> 3; // r - Text fields size restrictions
  125. $thisfile_id3v2['exthead_flags']['restrictions_imgenc'] = (bindec('00000100') & ord($extheaderrawrestrictions)) >> 2; // s - Image encoding restrictions
  126. $thisfile_id3v2['exthead_flags']['restrictions_imgsize'] = (bindec('00000011') & ord($extheaderrawrestrictions)) >> 0; // t - Image size restrictions
  127. }
  128. }
  129. else
  130. {
  131. $ThisFileInfo['warning'][] = '$thisfile_id3v2[exthead_flag_bytes] = "' . $thisfile_id3v2['exthead_flag_bytes'] . '" (expecting "1")';
  132. fseek($fd, $thisfile_id3v2['exthead_length'] - 1, SEEK_CUR);
  133. //return false;
  134. }
  135. } // end extended header
  136. // create 'encoding' key - used by getid3::HandleAllTags()
  137. // in ID3v2 every field can have it's own encoding type
  138. // so force everything to UTF-8 so it can be handled consistantly
  139. $thisfile_id3v2['encoding'] = 'UTF-8';
  140. // Frames
  141. // All ID3v2 frames consists of one frame header followed by one or more
  142. // fields containing the actual information. The header is always 10
  143. // bytes and laid out as follows:
  144. //
  145. // Frame ID $xx xx xx xx (four characters)
  146. // Size 4 * %0xxxxxxx
  147. // Flags $xx xx
  148. $sizeofframes = $thisfile_id3v2['headerlength'] - 10; // not including 10-byte initial header
  149. if (@$thisfile_id3v2['exthead_length'])
  150. {
  151. $sizeofframes -= ($thisfile_id3v2['exthead_length'] + 4);
  152. }
  153. if (@$thisfile_id3v2_flags['isfooter'])
  154. {
  155. $sizeofframes -= 10; // footer takes last 10 bytes of ID3v2 header, after frame data, before audio
  156. }
  157. if ($sizeofframes > 0)
  158. {
  159. $framedata = fread($fd, $sizeofframes); // read all frames from file into $framedata variable
  160. // if entire frame data is unsynched, de-unsynch it now (ID3v2.3.x)
  161. if (@$thisfile_id3v2_flags['unsynch'] && ($id3v2_majorversion <= 3))
  162. {
  163. $framedata = $this->DeUnsynchronise($framedata);
  164. }
  165. // [in ID3v2.4.0] Unsynchronisation [S:6.1] is done on frame level, instead
  166. // of on tag level, making it easier to skip frames, increasing the streamability
  167. // of the tag. The unsynchronisation flag in the header [S:3.1] indicates that
  168. // there exists an unsynchronised frame, while the new unsynchronisation flag in
  169. // the frame header [S:4.1.2] indicates unsynchronisation.
  170. $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)
  171. while (isset($framedata) && (strlen($framedata) > 0))
  172. { // cycle through until no more frame data is left to parse
  173. if (strlen($framedata) <= $this->ID3v2HeaderLength($id3v2_majorversion))
  174. {
  175. // insufficient room left in ID3v2 header for actual data - must be padding
  176. $thisfile_id3v2['padding']['start'] = $framedataoffset;
  177. $thisfile_id3v2['padding']['length'] = strlen($framedata);
  178. $thisfile_id3v2['padding']['valid'] = true;
  179. for($i = 0; $i < $thisfile_id3v2['padding']['length']; $i ++)
  180. {
  181. if ($framedata{$i} != "\x00")
  182. {
  183. $thisfile_id3v2['padding']['valid'] = false;
  184. $thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i;
  185. $ThisFileInfo['warning'][] = 'Invalid ID3v2 padding found at offset ' . $thisfile_id3v2['padding']['errorpos'] . ' (the remaining ' . ($thisfile_id3v2['padding']['length'] - $i) . ' bytes are considered invalid)';
  186. break;
  187. }
  188. }
  189. break; // skip rest of ID3v2 header
  190. }
  191. if ($id3v2_majorversion == 2)
  192. {
  193. // Frame ID $xx xx xx (three characters)
  194. // Size $xx xx xx (24-bit integer)
  195. // Flags $xx xx
  196. $frame_header = substr($framedata, 0, 6); // take next 6 bytes for header
  197. $framedata = substr($framedata, 6); // and leave the rest in $framedata
  198. $frame_name = substr($frame_header, 0, 3);
  199. $frame_size = getid3_lib :: BigEndian2Int(substr($frame_header, 3, 3), 0);
  200. $frame_flags = 0; // not used for anything in ID3v2.2, just set to avoid E_NOTICEs
  201. }
  202. elseif ($id3v2_majorversion > 2)
  203. {
  204. // Frame ID $xx xx xx xx (four characters)
  205. // Size $xx xx xx xx (32-bit integer in v2.3, 28-bit synchsafe in v2.4+)
  206. // Flags $xx xx
  207. $frame_header = substr($framedata, 0, 10); // take next 10 bytes for header
  208. $framedata = substr($framedata, 10); // and leave the rest in $framedata
  209. $frame_name = substr($frame_header, 0, 4);
  210. if ($id3v2_majorversion == 3)
  211. {
  212. $frame_size = getid3_lib :: BigEndian2Int(substr($frame_header, 4, 4), 0); // 32-bit integer
  213. }
  214. else
  215. { // ID3v2.4+
  216. $frame_size = getid3_lib :: BigEndian2Int(substr($frame_header, 4, 4), 1); // 32-bit synchsafe integer (28-bit value)
  217. }
  218. if ($frame_size < (strlen($framedata) + 4))
  219. {
  220. $nextFrameID = substr($framedata, $frame_size, 4);
  221. if ($this->IsValidID3v2FrameName($nextFrameID, $id3v2_majorversion))
  222. {
  223. // next frame is OK
  224. }
  225. elseif (($frame_name == "\x00" . 'MP3') || ($frame_name == "\x00\x00" . 'MP') || ($frame_name == ' MP3') || ($frame_name == 'MP3e'))
  226. {
  227. // MP3ext known broken frames - "ok" for the purposes of this test
  228. }
  229. elseif (($id3v2_majorversion == 4) && ($this->IsValidID3v2FrameName(substr($framedata, getid3_lib :: BigEndian2Int(substr($frame_header, 4, 4), 0), 4), 3)))
  230. {
  231. $ThisFileInfo['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';
  232. $id3v2_majorversion = 3;
  233. $frame_size = getid3_lib :: BigEndian2Int(substr($frame_header, 4, 4), 0); // 32-bit integer
  234. }
  235. }
  236. $frame_flags = getid3_lib :: BigEndian2Int(substr($frame_header, 8, 2));
  237. }
  238. if ((($id3v2_majorversion == 2) && ($frame_name == "\x00\x00\x00")) || ($frame_name == "\x00\x00\x00\x00"))
  239. {
  240. // padding encountered
  241. $thisfile_id3v2['padding']['start'] = $framedataoffset;
  242. $thisfile_id3v2['padding']['length'] = strlen($framedata);
  243. $thisfile_id3v2['padding']['valid'] = true;
  244. for($i = 0; $i < $thisfile_id3v2['padding']['length']; $i ++)
  245. {
  246. if ($framedata{$i} != "\x00")
  247. {
  248. $thisfile_id3v2['padding']['valid'] = false;
  249. $thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i;
  250. $ThisFileInfo['warning'][] = 'Invalid ID3v2 padding found at offset ' . $thisfile_id3v2['padding']['errorpos'] . ' (the remaining ' . ($thisfile_id3v2['padding']['length'] - $i) . ' bytes are considered invalid)';
  251. break;
  252. }
  253. }
  254. break; // skip rest of ID3v2 header
  255. }
  256. if ($frame_name == 'COM ')
  257. {
  258. $ThisFileInfo['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" are known-guilty, probably others too)]';
  259. $frame_name = 'COMM';
  260. }
  261. if (($frame_size <= strlen($framedata)) && ($this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion)))
  262. {
  263. unset($parsedFrame);
  264. $parsedFrame['frame_name'] = $frame_name;
  265. $parsedFrame['frame_flags_raw'] = $frame_flags;
  266. $parsedFrame['data'] = substr($framedata, 0, $frame_size);
  267. $parsedFrame['datalength'] = getid3_lib :: CastAsInt($frame_size);
  268. $parsedFrame['dataoffset'] = $framedataoffset;
  269. $this->ParseID3v2Frame($parsedFrame, $ThisFileInfo);
  270. $thisfile_id3v2[$frame_name][] = $parsedFrame;
  271. $framedata = substr($framedata, $frame_size);
  272. }
  273. else
  274. { // invalid frame length or FrameID
  275. if ($frame_size <= strlen($framedata))
  276. {
  277. if ($this->IsValidID3v2FrameName(substr($framedata, $frame_size, 4), $id3v2_majorversion))
  278. {
  279. // next frame is valid, just skip the current frame
  280. $framedata = substr($framedata, $frame_size);
  281. $ThisFileInfo['warning'][] = 'Next ID3v2 frame is valid, skipping current frame.';
  282. }
  283. else
  284. {
  285. // next frame is invalid too, abort processing
  286. //unset($framedata);
  287. $framedata = null;
  288. $ThisFileInfo['error'][] = 'Next ID3v2 frame is also invalid, aborting processing.';
  289. }
  290. }
  291. elseif ($frame_size == strlen($framedata))
  292. {
  293. // this is the last frame, just skip
  294. $ThisFileInfo['warning'][] = 'This was the last ID3v2 frame.';
  295. }
  296. else
  297. {
  298. // next frame is invalid too, abort processing
  299. //unset($framedata);
  300. $framedata = null;
  301. $ThisFileInfo['warning'][] = 'Invalid ID3v2 frame size, aborting.';
  302. }
  303. if (! $this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion))
  304. {
  305. switch ($frame_name)
  306. {
  307. case "\x00\x00" . 'MP' :
  308. case "\x00" . 'MP3' :
  309. case ' MP3' :
  310. case 'MP3e' :
  311. case "\x00" . 'MP' :
  312. case ' MP' :
  313. case 'MP3' :
  314. $ThisFileInfo['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/)"]';
  315. break;
  316. default :
  317. $ThisFileInfo['warning'][] = 'error parsing "' . $frame_name . '" (' . $framedataoffset . ' bytes into the ID3v2.' . $id3v2_majorversion . ' tag). (ERROR: !IsValidID3v2FrameName("' . str_replace("\x00", ' ', $frame_name) . '", ' . $id3v2_majorversion . '))).';
  318. break;
  319. }
  320. }
  321. elseif ($frame_size > strlen($framedata))
  322. {
  323. $ThisFileInfo['error'][] = 'error parsing "' . $frame_name . '" (' . $framedataoffset . ' bytes into the ID3v2.' . $id3v2_majorversion . ' tag). (ERROR: $frame_size (' . $frame_size . ') > strlen($framedata) (' . strlen($framedata) . ')).';
  324. }
  325. else
  326. {
  327. $ThisFileInfo['error'][] = 'error parsing "' . $frame_name . '" (' . $framedataoffset . ' bytes into the ID3v2.' . $id3v2_majorversion . ' tag).';
  328. }
  329. }
  330. $framedataoffset += ($frame_size + $this->ID3v2HeaderLength($id3v2_majorversion));
  331. }
  332. }
  333. // Footer
  334. // The footer is a copy of the header, but with a different identifier.
  335. // ID3v2 identifier "3DI"
  336. // ID3v2 version $04 00
  337. // ID3v2 flags %abcd0000
  338. // ID3v2 size 4 * %0xxxxxxx
  339. if (isset($thisfile_id3v2_flags['isfooter']) && $thisfile_id3v2_flags['isfooter'])
  340. {
  341. $footer = fread($fd, 10);
  342. if (substr($footer, 0, 3) == '3DI')
  343. {
  344. $thisfile_id3v2['footer'] = true;
  345. $thisfile_id3v2['majorversion_footer'] = ord($footer{3});
  346. $thisfile_id3v2['minorversion_footer'] = ord($footer{4});
  347. }
  348. if ($thisfile_id3v2['majorversion_footer'] <= 4)
  349. {
  350. $id3_flags = ord(substr($footer{5}));
  351. $thisfile_id3v2_flags['unsynch_footer'] = (bool) ($id3_flags & 0x80);
  352. $thisfile_id3v2_flags['extfoot_footer'] = (bool) ($id3_flags & 0x40);
  353. $thisfile_id3v2_flags['experim_footer'] = (bool) ($id3_flags & 0x20);
  354. $thisfile_id3v2_flags['isfooter_footer'] = (bool) ($id3_flags & 0x10);
  355. $thisfile_id3v2['footerlength'] = getid3_lib :: BigEndian2Int(substr($footer, 6, 4), 1);
  356. }
  357. } // end footer
  358. if (isset($thisfile_id3v2['comments']['genre']))
  359. {
  360. foreach ($thisfile_id3v2['comments']['genre'] as $key => $value)
  361. {
  362. unset($thisfile_id3v2['comments']['genre'][$key]);
  363. $thisfile_id3v2['comments'] = getid3_lib :: array_merge_noclobber($thisfile_id3v2['comments'], $this->ParseID3v2GenreString($value));
  364. }
  365. }
  366. if (isset($thisfile_id3v2['comments']['track']))
  367. {
  368. foreach ($thisfile_id3v2['comments']['track'] as $key => $value)
  369. {
  370. if (strstr($value, '/'))
  371. {
  372. list($thisfile_id3v2['comments']['tracknum'][$key], $thisfile_id3v2['comments']['totaltracks'][$key]) = explode('/', $thisfile_id3v2['comments']['track'][$key]);
  373. }
  374. }
  375. }
  376. if (! isset($thisfile_id3v2['comments']['year']) && ereg('^([0-9]{4})', trim(@$thisfile_id3v2['comments']['recording_time'][0]), $matches))
  377. {
  378. $thisfile_id3v2['comments']['year'] = array($matches[1]);
  379. }
  380. // Set avdataoffset
  381. $ThisFileInfo['avdataoffset'] = $thisfile_id3v2['headerlength'];
  382. if (isset($thisfile_id3v2['footer']))
  383. {
  384. $ThisFileInfo['avdataoffset'] += 10;
  385. }
  386. return true;
  387. }
  388. function ParseID3v2GenreString($genrestring)
  389. {
  390. // Parse genres into arrays of genreName and genreID
  391. // ID3v2.2.x, ID3v2.3.x: '(21)' or '(4)Eurodisco' or '(51)(39)' or '(55)((I think...)'
  392. // ID3v2.4.x: '21' $00 'Eurodisco' $00
  393. $genrestring = trim($genrestring);
  394. $returnarray = array();
  395. if (strpos($genrestring, "\x00") !== false)
  396. {
  397. $unprocessed = trim($genrestring); // trailing nulls will cause an infinite loop.
  398. $genrestring = '';
  399. while (strpos($unprocessed, "\x00") !== false)
  400. {
  401. // convert null-seperated v2.4-format into v2.3 ()-seperated format
  402. $endpos = strpos($unprocessed, "\x00");
  403. $genrestring .= '(' . substr($unprocessed, 0, $endpos) . ')';
  404. $unprocessed = substr($unprocessed, $endpos + 1);
  405. }
  406. unset($unprocessed);
  407. }
  408. if (getid3_id3v1 :: LookupGenreID($genrestring))
  409. {
  410. $returnarray['genre'][] = $genrestring;
  411. }
  412. else
  413. {
  414. while (strpos($genrestring, '(') !== false)
  415. {
  416. $startpos = strpos($genrestring, '(');
  417. $endpos = strpos($genrestring, ')');
  418. if (substr($genrestring, $startpos + 1, 1) == '(')
  419. {
  420. $genrestring = substr($genrestring, 0, $startpos) . substr($genrestring, $startpos + 1);
  421. $endpos --;
  422. }
  423. $element = substr($genrestring, $startpos + 1, $endpos - ($startpos + 1));
  424. $genrestring = substr($genrestring, 0, $startpos) . substr($genrestring, $endpos + 1);
  425. if (getid3_id3v1 :: LookupGenreName($element))
  426. { // $element is a valid genre id/abbreviation
  427. if (empty($returnarray['genre']) || ! in_array(getid3_id3v1 :: LookupGenreName($element), $returnarray['genre']))
  428. { // avoid duplicate entires
  429. $returnarray['genre'][] = getid3_id3v1 :: LookupGenreName($element);
  430. }
  431. }
  432. else
  433. {
  434. if (empty($returnarray['genre']) || ! in_array($element, $returnarray['genre']))
  435. { // avoid duplicate entires
  436. $returnarray['genre'][] = $element;
  437. }
  438. }
  439. }
  440. }
  441. if ($genrestring)
  442. {
  443. if (empty($returnarray['genre']) || ! in_array($genrestring, $returnarray['genre']))
  444. { // avoid duplicate entires
  445. $returnarray['genre'][] = $genrestring;
  446. }
  447. }
  448. return $returnarray;
  449. }
  450. function ParseID3v2Frame(&$parsedFrame, &$ThisFileInfo)
  451. {
  452. // shortcuts
  453. $id3v2_majorversion = $ThisFileInfo['id3v2']['majorversion'];
  454. $parsedFrame['framenamelong'] = $this->FrameNameLongLookup($parsedFrame['frame_name']);
  455. if (empty($parsedFrame['framenamelong']))
  456. {
  457. unset($parsedFrame['framenamelong']);
  458. }
  459. $parsedFrame['framenameshort'] = $this->FrameNameShortLookup($parsedFrame['frame_name']);
  460. if (empty($parsedFrame['framenameshort']))
  461. {
  462. unset($parsedFrame['framenameshort']);
  463. }
  464. if ($id3v2_majorversion >= 3)
  465. { // frame flags are not part of the ID3v2.2 standard
  466. if ($id3v2_majorversion == 3)
  467. {
  468. // Frame Header Flags
  469. // %abc00000 %ijk00000
  470. $parsedFrame['flags']['TagAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x8000); // a - Tag alter preservation
  471. $parsedFrame['flags']['FileAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x4000); // b - File alter preservation
  472. $parsedFrame['flags']['ReadOnly'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x2000); // c - Read only
  473. $parsedFrame['flags']['compression'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0080); // i - Compression
  474. $parsedFrame['flags']['Encryption'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0040); // j - Encryption
  475. $parsedFrame['flags']['GroupingIdentity'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0020); // k - Grouping identity
  476. }
  477. elseif ($id3v2_majorversion == 4)
  478. {
  479. // Frame Header Flags
  480. // %0abc0000 %0h00kmnp
  481. $parsedFrame['flags']['TagAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x4000); // a - Tag alter preservation
  482. $parsedFrame['flags']['FileAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x2000); // b - File alter preservation
  483. $parsedFrame['flags']['ReadOnly'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x1000); // c - Read only
  484. $parsedFrame['flags']['GroupingIdentity'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0040); // h - Grouping identity
  485. $parsedFrame['flags']['compression'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0008); // k - Compression
  486. $parsedFrame['flags']['Encryption'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0004); // m - Encryption
  487. $parsedFrame['flags']['Unsynchronisation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0002); // n - Unsynchronisation
  488. $parsedFrame['flags']['DataLengthIndicator'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0001); // p - Data length indicator
  489. // Frame-level de-unsynchronisation - ID3v2.4
  490. if ($parsedFrame['flags']['Unsynchronisation'])
  491. {
  492. $parsedFrame['data'] = $this->DeUnsynchronise($parsedFrame['data']);
  493. }
  494. }
  495. // Frame-level de-compression
  496. if ($parsedFrame['flags']['compression'])
  497. {
  498. $parsedFrame['decompressed_size'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], 0, 4));
  499. if (! function_exists('gzuncompress'))
  500. {
  501. $ThisFileInfo['warning'][] = 'gzuncompress() support required to decompress ID3v2 frame "' . $parsedFrame['frame_name'] . '"';
  502. }
  503. elseif ($decompresseddata = @gzuncompress(substr($parsedFrame['data'], 4)))
  504. {
  505. $parsedFrame['data'] = $decompresseddata;
  506. }
  507. else
  508. {
  509. $ThisFileInfo['warning'][] = 'gzuncompress() failed on compressed contents of ID3v2 frame "' . $parsedFrame['frame_name'] . '"';
  510. }
  511. }
  512. }
  513. if (isset($parsedFrame['datalength']) && ($parsedFrame['datalength'] == 0))
  514. {
  515. $warning = 'Frame "' . $parsedFrame['frame_name'] . '" at offset ' . $parsedFrame['dataoffset'] . ' has no data portion';
  516. switch ($parsedFrame['frame_name'])
  517. {
  518. case 'WCOM' :
  519. $warning .= ' (this is known to happen with files tagged by RioPort)';
  520. break;
  521. default :
  522. break;
  523. }
  524. $ThisFileInfo['warning'][] = $warning;
  525. }
  526. elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'UFID')) || // 4.1 UFID Unique file identifier
  527. (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'UFI')))
  528. { // 4.1 UFI Unique file identifier
  529. // There may be more than one 'UFID' frame in a tag,
  530. // but only one with the same 'Owner identifier'.
  531. // <Header for 'Unique file identifier', ID: 'UFID'>
  532. // Owner identifier <text string> $00
  533. // Identifier <up to 64 bytes binary data>
  534. $frame_terminatorpos = strpos($parsedFrame['data'], "\x00");
  535. $frame_idstring = substr($parsedFrame['data'], 0, $frame_terminatorpos);
  536. $parsedFrame['ownerid'] = $frame_idstring;
  537. $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00"));
  538. unset($parsedFrame['data']);
  539. }
  540. elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'TXXX')) || // 4.2.2 TXXX User defined text information frame
  541. (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'TXX')))
  542. { // 4.2.2 TXX User defined text information frame
  543. // There may be more than one 'TXXX' frame in each tag,
  544. // but only one with the same description.
  545. // <Header for 'User defined text information frame', ID: 'TXXX'>
  546. // Text encoding $xx
  547. // Description <text string according to encoding> $00 (00)
  548. // Value <text string according to encoding>
  549. $frame_offset = 0;
  550. $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  551. if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3)))
  552. {
  553. $ThisFileInfo['warning'][] = 'Invalid text encoding byte (' . $frame_textencoding . ') in frame "' . $parsedFrame['frame_name'] . '" - defaulting to ISO-8859-1 encoding';
  554. }
  555. $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
  556. if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0)
  557. {
  558. $frame_terminatorpos ++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
  559. }
  560. $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  561. if (ord($frame_description) === 0)
  562. {
  563. $frame_description = '';
  564. }
  565. $parsedFrame['encodingid'] = $frame_textencoding;
  566. $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
  567. $parsedFrame['description'] = $frame_description;
  568. $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
  569. if (! empty($parsedFrame['framenameshort']) && ! empty($parsedFrame['data']))
  570. {
  571. $ThisFileInfo['id3v2']['comments'][$parsedFrame['framenameshort']][] = trim(getid3_lib :: iconv_fallback($parsedFrame['encoding'], $ThisFileInfo['id3v2']['encoding'], $parsedFrame['data']));
  572. }
  573. unset($parsedFrame['data']);
  574. }
  575. elseif ($parsedFrame['frame_name']{0} == 'T')
  576. { // 4.2. T??[?] Text information frame
  577. // There may only be one text information frame of its kind in an tag.
  578. // <Header for 'Text information frame', ID: 'T000' - 'TZZZ',
  579. // excluding 'TXXX' described in 4.2.6.>
  580. // Text encoding $xx
  581. // Information <text string(s) according to encoding>
  582. $frame_offset = 0;
  583. $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  584. if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3)))
  585. {
  586. $ThisFileInfo['warning'][] = 'Invalid text encoding byte (' . $frame_textencoding . ') in frame "' . $parsedFrame['frame_name'] . '" - defaulting to ISO-8859-1 encoding';
  587. }
  588. $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
  589. $parsedFrame['encodingid'] = $frame_textencoding;
  590. $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
  591. if (! empty($parsedFrame['framenameshort']) && ! empty($parsedFrame['data']))
  592. {
  593. $ThisFileInfo['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib :: iconv_fallback($parsedFrame['encoding'], $ThisFileInfo['id3v2']['encoding'], $parsedFrame['data']);
  594. }
  595. }
  596. elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'WXXX')) || // 4.3.2 WXXX User defined URL link frame
  597. (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'WXX')))
  598. { // 4.3.2 WXX User defined URL link frame
  599. // There may be more than one 'WXXX' frame in each tag,
  600. // but only one with the same description
  601. // <Header for 'User defined URL link frame', ID: 'WXXX'>
  602. // Text encoding $xx
  603. // Description <text string according to encoding> $00 (00)
  604. // URL <text string>
  605. $frame_offset = 0;
  606. $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  607. if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3)))
  608. {
  609. $ThisFileInfo['warning'][] = 'Invalid text encoding byte (' . $frame_textencoding . ') in frame "' . $parsedFrame['frame_name'] . '" - defaulting to ISO-8859-1 encoding';
  610. }
  611. $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
  612. if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0)
  613. {
  614. $frame_terminatorpos ++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
  615. }
  616. $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  617. if (ord($frame_description) === 0)
  618. {
  619. $frame_description = '';
  620. }
  621. $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
  622. $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding));
  623. if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0)
  624. {
  625. $frame_terminatorpos ++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
  626. }
  627. if ($frame_terminatorpos)
  628. {
  629. // there are null bytes after the data - this is not according to spec
  630. // only use data up to first null byte
  631. $frame_urldata = (string) substr($parsedFrame['data'], 0, $frame_terminatorpos);
  632. }
  633. else
  634. {
  635. // no null bytes following data, just use all data
  636. $frame_urldata = (string) $parsedFrame['data'];
  637. }
  638. $parsedFrame['encodingid'] = $frame_textencoding;
  639. $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
  640. $parsedFrame['url'] = $frame_urldata;
  641. $parsedFrame['description'] = $frame_description;
  642. if (! empty($parsedFrame['framenameshort']) && $parsedFrame['url'])
  643. {
  644. $ThisFileInfo['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib :: iconv_fallback($parsedFrame['encoding'], $ThisFileInfo['id3v2']['encoding'], $parsedFrame['url']);
  645. }
  646. unset($parsedFrame['data']);
  647. }
  648. elseif ($parsedFrame['frame_name']{0} == 'W')
  649. { // 4.3. W??? URL link frames
  650. // There may only be one URL link frame of its kind in a tag,
  651. // except when stated otherwise in the frame description
  652. // <Header for 'URL link frame', ID: 'W000' - 'WZZZ', excluding 'WXXX'
  653. // described in 4.3.2.>
  654. // URL <text string>
  655. $parsedFrame['url'] = trim($parsedFrame['data']);
  656. if (! empty($parsedFrame['framenameshort']) && $parsedFrame['url'])
  657. {
  658. $ThisFileInfo['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['url'];
  659. }
  660. unset($parsedFrame['data']);
  661. }
  662. elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'IPLS')) || // 4.4 IPLS Involved people list (ID3v2.3 only)
  663. (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'IPL')))
  664. { // 4.4 IPL Involved people list (ID3v2.2 only)
  665. // There may only be one 'IPL' frame in each tag
  666. // <Header for 'User defined URL link frame', ID: 'IPL'>
  667. // Text encoding $xx
  668. // People list strings <textstrings>
  669. $frame_offset = 0;
  670. $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  671. if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3)))
  672. {
  673. $ThisFileInfo['warning'][] = 'Invalid text encoding byte (' . $frame_textencoding . ') in frame "' . $parsedFrame['frame_name'] . '" - defaulting to ISO-8859-1 encoding';
  674. }
  675. $parsedFrame['encodingid'] = $frame_textencoding;
  676. $parsedFrame['encoding'] = $this->TextEncodingNameLookup($parsedFrame['encodingid']);
  677. $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
  678. if (! empty($parsedFrame['framenameshort']) && ! empty($parsedFrame['data']))
  679. {
  680. $ThisFileInfo['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib :: iconv_fallback($parsedFrame['encoding'], $ThisFileInfo['id3v2']['encoding'], $parsedFrame['data']);
  681. }
  682. }
  683. elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'MCDI')) || // 4.4 MCDI Music CD identifier
  684. (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'MCI')))
  685. { // 4.5 MCI Music CD identifier
  686. // There may only be one 'MCDI' frame in each tag
  687. // <Header for 'Music CD identifier', ID: 'MCDI'>
  688. // CD TOC <binary data>
  689. if (! empty($parsedFrame['framenameshort']) && ! empty($parsedFrame['data']))
  690. {
  691. $ThisFileInfo['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['data'];
  692. }
  693. }
  694. elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'ETCO')) || // 4.5 ETCO Event timing codes
  695. (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ETC')))
  696. { // 4.6 ETC Event timing codes
  697. // There may only be one 'ETCO' frame in each tag
  698. // <Header for 'Event timing codes', ID: 'ETCO'>
  699. // Time stamp format $xx
  700. // Where time stamp format is:
  701. // $01 (32-bit value) MPEG frames from beginning of file
  702. // $02 (32-bit value) milliseconds from beginning of file
  703. // Followed by a list of key events in the following format:
  704. // Type of event $xx
  705. // Time stamp $xx (xx ...)
  706. // The 'Time stamp' is set to zero if directly at the beginning of the sound
  707. // or after the previous event. All events MUST be sorted in chronological order.
  708. $frame_offset = 0;
  709. $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  710. while ($frame_offset < strlen($parsedFrame['data']))
  711. {
  712. $parsedFrame['typeid'] = substr($parsedFrame['data'], $frame_offset ++, 1);
  713. $parsedFrame['type'] = $this->ETCOEventLookup($parsedFrame['typeid']);
  714. $parsedFrame['timestamp'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
  715. $frame_offset += 4;
  716. }
  717. unset($parsedFrame['data']);
  718. }
  719. elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'MLLT')) || // 4.6 MLLT MPEG location lookup table
  720. (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'MLL')))
  721. { // 4.7 MLL MPEG location lookup table
  722. // There may only be one 'MLLT' frame in each tag
  723. // <Header for 'Location lookup table', ID: 'MLLT'>
  724. // MPEG frames between reference $xx xx
  725. // Bytes between reference $xx xx xx
  726. // Milliseconds between reference $xx xx xx
  727. // Bits for bytes deviation $xx
  728. // Bits for milliseconds dev. $xx
  729. // Then for every reference the following data is included;
  730. // Deviation in bytes %xxx....
  731. // Deviation in milliseconds %xxx....
  732. $frame_offset = 0;
  733. $parsedFrame['framesbetweenreferences'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], 0, 2));
  734. $parsedFrame['bytesbetweenreferences'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], 2, 3));
  735. $parsedFrame['msbetweenreferences'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], 5, 3));
  736. $parsedFrame['bitsforbytesdeviation'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], 8, 1));
  737. $parsedFrame['bitsformsdeviation'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], 9, 1));
  738. $parsedFrame['data'] = substr($parsedFrame['data'], 10);
  739. while ($frame_offset < strlen($parsedFrame['data']))
  740. {
  741. $deviationbitstream .= getid3_lib :: BigEndian2Bin(substr($parsedFrame['data'], $frame_offset ++, 1));
  742. }
  743. $reference_counter = 0;
  744. while (strlen($deviationbitstream) > 0)
  745. {
  746. $parsedFrame[$reference_counter]['bytedeviation'] = bindec(substr($deviationbitstream, 0, $parsedFrame['bitsforbytesdeviation']));
  747. $parsedFrame[$reference_counter]['msdeviation'] = bindec(substr($deviationbitstream, $parsedFrame['bitsforbytesdeviation'], $parsedFrame['bitsformsdeviation']));
  748. $deviationbitstream = substr($deviationbitstream, $parsedFrame['bitsforbytesdeviation'] + $parsedFrame['bitsformsdeviation']);
  749. $reference_counter ++;
  750. }
  751. unset($parsedFrame['data']);
  752. }
  753. elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'SYTC')) || // 4.7 SYTC Synchronised tempo codes
  754. (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'STC')))
  755. { // 4.8 STC Synchronised tempo codes
  756. // There may only be one 'SYTC' frame in each tag
  757. // <Header for 'Synchronised tempo codes', ID: 'SYTC'>
  758. // Time stamp format $xx
  759. // Tempo data <binary data>
  760. // Where time stamp format is:
  761. // $01 (32-bit value) MPEG frames from beginning of file
  762. // $02 (32-bit value) milliseconds from beginning of file
  763. $frame_offset = 0;
  764. $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  765. $timestamp_counter = 0;
  766. while ($frame_offset < strlen($parsedFrame['data']))
  767. {
  768. $parsedFrame[$timestamp_counter]['tempo'] = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  769. if ($parsedFrame[$timestamp_counter]['tempo'] == 255)
  770. {
  771. $parsedFrame[$timestamp_counter]['tempo'] += ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  772. }
  773. $parsedFrame[$timestamp_counter]['timestamp'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
  774. $frame_offset += 4;
  775. $timestamp_counter ++;
  776. }
  777. unset($parsedFrame['data']);
  778. }
  779. elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USLT')) || // 4.8 USLT Unsynchronised lyric/text transcription
  780. (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ULT')))
  781. { // 4.9 ULT Unsynchronised lyric/text transcription
  782. // There may be more than one 'Unsynchronised lyrics/text transcription' frame
  783. // in each tag, but only one with the same language and content descriptor.
  784. // <Header for 'Unsynchronised lyrics/text transcription', ID: 'USLT'>
  785. // Text encoding $xx
  786. // Language $xx xx xx
  787. // Content descriptor <text string according to encoding> $00 (00)
  788. // Lyrics/text <full text string according to encoding>
  789. $frame_offset = 0;
  790. $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  791. if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3)))
  792. {
  793. $ThisFileInfo['warning'][] = 'Invalid text encoding byte (' . $frame_textencoding . ') in frame "' . $parsedFrame['frame_name'] . '" - defaulting to ISO-8859-1 encoding';
  794. }
  795. $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
  796. $frame_offset += 3;
  797. $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
  798. if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0)
  799. {
  800. $frame_terminatorpos ++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
  801. }
  802. $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  803. if (ord($frame_description) === 0)
  804. {
  805. $frame_description = '';
  806. }
  807. $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
  808. $parsedFrame['encodingid'] = $frame_textencoding;
  809. $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
  810. $parsedFrame['data'] = $parsedFrame['data'];
  811. $parsedFrame['language'] = $frame_language;
  812. $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
  813. $parsedFrame['description'] = $frame_description;
  814. if (! empty($parsedFrame['framenameshort']) && ! empty($parsedFrame['data']))
  815. {
  816. $ThisFileInfo['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib :: iconv_fallback($parsedFrame['encoding'], $ThisFileInfo['id3v2']['encoding'], $parsedFrame['data']);
  817. }
  818. unset($parsedFrame['data']);
  819. }
  820. elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'SYLT')) || // 4.9 SYLT Synchronised lyric/text
  821. (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'SLT')))
  822. { // 4.10 SLT Synchronised lyric/text
  823. // There may be more than one 'SYLT' frame in each tag,
  824. // but only one with the same language and content descriptor.
  825. // <Header for 'Synchronised lyrics/text', ID: 'SYLT'>
  826. // Text encoding $xx
  827. // Language $xx xx xx
  828. // Time stamp format $xx
  829. // $01 (32-bit value) MPEG frames from beginning of file
  830. // $02 (32-bit value) milliseconds from beginning of file
  831. // Content type $xx
  832. // Content descriptor <text string according to encoding> $00 (00)
  833. // Terminated text to be synced (typically a syllable)
  834. // Sync identifier (terminator to above string) $00 (00)
  835. // Time stamp $xx (xx ...)
  836. $frame_offset = 0;
  837. $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  838. if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3)))
  839. {
  840. $ThisFileInfo['warning'][] = 'Invalid text encoding byte (' . $frame_textencoding . ') in frame "' . $parsedFrame['frame_name'] . '" - defaulting to ISO-8859-1 encoding';
  841. }
  842. $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
  843. $frame_offset += 3;
  844. $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  845. $parsedFrame['contenttypeid'] = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  846. $parsedFrame['contenttype'] = $this->SYTLContentTypeLookup($parsedFrame['contenttypeid']);
  847. $parsedFrame['encodingid'] = $frame_textencoding;
  848. $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
  849. $parsedFrame['language'] = $frame_language;
  850. $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
  851. $timestampindex = 0;
  852. $frame_remainingdata = substr($parsedFrame['data'], $frame_offset);
  853. while (strlen($frame_remainingdata))
  854. {
  855. $frame_offset = 0;
  856. $frame_terminatorpos = strpos($frame_remainingdata, $this->TextEncodingTerminatorLookup($frame_textencoding));
  857. if ($frame_terminatorpos === false)
  858. {
  859. $frame_remainingdata = '';
  860. }
  861. else
  862. {
  863. if (ord(substr($frame_remainingdata, $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0)
  864. {
  865. $frame_terminatorpos ++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
  866. }
  867. $parsedFrame['lyrics'][$timestampindex]['data'] = substr($frame_remainingdata, $frame_offset, $frame_terminatorpos - $frame_offset);
  868. $frame_remainingdata = substr($frame_remainingdata, $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
  869. if (($timestampindex == 0) && (ord($frame_remainingdata{0}) != 0))
  870. {
  871. // timestamp probably omitted for first data item
  872. }
  873. else
  874. {
  875. $parsedFrame['lyrics'][$timestampindex]['timestamp'] = getid3_lib :: BigEndian2Int(substr($frame_remainingdata, 0, 4));
  876. $frame_remainingdata = substr($frame_remainingdata, 4);
  877. }
  878. $timestampindex ++;
  879. }
  880. }
  881. unset($parsedFrame['data']);
  882. }
  883. elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'COMM')) || // 4.10 COMM Comments
  884. (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'COM')))
  885. { // 4.11 COM Comments
  886. // There may be more than one comment frame in each tag,
  887. // but only one with the same language and content descriptor.
  888. // <Header for 'Comment', ID: 'COMM'>
  889. // Text encoding $xx
  890. // Language $xx xx xx
  891. // Short content descrip. <text string according to encoding> $00 (00)
  892. // The actual text <full text string according to encoding>
  893. if (strlen($parsedFrame['data']) < 5)
  894. {
  895. $ThisFileInfo['warning'][] = 'Invalid data (too short) for "' . $parsedFrame['frame_name'] . '" frame at offset ' . $parsedFrame['dataoffset'];
  896. }
  897. else
  898. {
  899. $frame_offset = 0;
  900. $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  901. if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3)))
  902. {
  903. $ThisFileInfo['warning'][] = 'Invalid text encoding byte (' . $frame_textencoding . ') in frame "' . $parsedFrame['frame_name'] . '" - defaulting to ISO-8859-1 encoding';
  904. }
  905. $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
  906. $frame_offset += 3;
  907. $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
  908. if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0)
  909. {
  910. $frame_terminatorpos ++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
  911. }
  912. $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  913. if (ord($frame_description) === 0)
  914. {
  915. $frame_description = '';
  916. }
  917. $frame_text = (string) substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
  918. $parsedFrame['encodingid'] = $frame_textencoding;
  919. $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
  920. $parsedFrame['language'] = $frame_language;
  921. $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
  922. $parsedFrame['description'] = $frame_description;
  923. $parsedFrame['data'] = $frame_text;
  924. if (! empty($parsedFrame['framenameshort']) && ! empty($parsedFrame['data']))
  925. {
  926. $ThisFileInfo['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib :: iconv_fallback($parsedFrame['encoding'], $ThisFileInfo['id3v2']['encoding'], $parsedFrame['data']);
  927. }
  928. }
  929. }
  930. elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'RVA2'))
  931. { // 4.11 RVA2 Relative volume adjustment (2) (ID3v2.4+ only)
  932. // There may be more than one 'RVA2' frame in each tag,
  933. // but only one with the same identification string
  934. // <Header for 'Relative volume adjustment (2)', ID: 'RVA2'>
  935. // Identification <text string> $00
  936. // The 'identification' string is used to identify the situation and/or
  937. // device where this adjustment should apply. The following is then
  938. // repeated for every channel:
  939. // Type of channel $xx
  940. // Volume adjustment $xx xx
  941. // Bits representing peak $xx
  942. // Peak volume $xx (xx ...)
  943. $frame_terminatorpos = strpos($parsedFrame['data'], "\x00");
  944. $frame_idstring = substr($parsedFrame['data'], 0, $frame_terminatorpos);
  945. if (ord($frame_idstring) === 0)
  946. {
  947. $frame_idstring = '';
  948. }
  949. $frame_remainingdata = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00"));
  950. $parsedFrame['description'] = $frame_idstring;
  951. while (strlen($frame_remainingdata))
  952. {
  953. $frame_offset = 0;
  954. $frame_channeltypeid = ord(substr($frame_remainingdata, $frame_offset ++, 1));
  955. $parsedFrame[$frame_channeltypeid]['channeltypeid'] = $frame_channeltypeid;
  956. $parsedFrame[$frame_channeltypeid]['channeltype'] = $this->RVA2ChannelTypeLookup($frame_channeltypeid);
  957. $parsedFrame[$frame_channeltypeid]['volumeadjust'] = getid3_lib :: BigEndian2Int(substr($frame_remainingdata, $frame_offset, 2), false, true); // 16-bit signed
  958. $frame_offset += 2;
  959. $parsedFrame[$frame_channeltypeid]['bitspeakvolume'] = ord(substr($frame_remainingdata, $frame_offset ++, 1));
  960. $frame_bytespeakvolume = ceil($parsedFrame[$frame_channeltypeid]['bitspeakvolume'] / 8);
  961. $parsedFrame[$frame_channeltypeid]['peakvolume'] = getid3_lib :: BigEndian2Int(substr($frame_remainingdata, $frame_offset, $frame_bytespeakvolume));
  962. $frame_remainingdata = substr($frame_remainingdata, $frame_offset + $frame_bytespeakvolume);
  963. }
  964. unset($parsedFrame['data']);
  965. }
  966. elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'RVAD')) || // 4.12 RVAD Relative volume adjustment (ID3v2.3 only)
  967. (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'RVA')))
  968. { // 4.12 RVA Relative volume adjustment (ID3v2.2 only)
  969. // There may only be one 'RVA' frame in each tag
  970. // <Header for 'Relative volume adjustment', ID: 'RVA'>
  971. // ID3v2.2 => Increment/decrement %000000ba
  972. // ID3v2.3 => Increment/decrement %00fedcba
  973. // Bits used for volume descr. $xx
  974. // Relative volume change, right $xx xx (xx ...) // a
  975. // Relative volume change, left $xx xx (xx ...) // b
  976. // Peak volume right $xx xx (xx ...)
  977. // Peak volume left $xx xx (xx ...)
  978. // ID3v2.3 only, optional (not present in ID3v2.2):
  979. // Relative volume change, right back $xx xx (xx ...) // c
  980. // Relative volume change, left back $xx xx (xx ...) // d
  981. // Peak volume right back $xx xx (xx ...)
  982. // Peak volume left back $xx xx (xx ...)
  983. // ID3v2.3 only, optional (not present in ID3v2.2):
  984. // Relative volume change, center $xx xx (xx ...) // e
  985. // Peak volume center $xx xx (xx ...)
  986. // ID3v2.3 only, optional (not present in ID3v2.2):
  987. // Relative volume change, bass $xx xx (xx ...) // f
  988. // Peak volume bass $xx xx (xx ...)
  989. $frame_offset = 0;
  990. $frame_incrdecrflags = getid3_lib :: BigEndian2Bin(substr($parsedFrame['data'], $frame_offset ++, 1));
  991. $parsedFrame['incdec']['right'] = (bool) substr($frame_incrdecrflags, 6, 1);
  992. $parsedFrame['incdec']['left'] = (bool) substr($frame_incrdecrflags, 7, 1);
  993. $parsedFrame['bitsvolume'] = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  994. $frame_bytesvolume = ceil($parsedFrame['bitsvolume'] / 8);
  995. $parsedFrame['volumechange']['right'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
  996. if ($parsedFrame['incdec']['right'] === false)
  997. {
  998. $parsedFrame['volumechange']['right'] *= - 1;
  999. }
  1000. $frame_offset += $frame_bytesvolume;
  1001. $parsedFrame['volumechange']['left'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
  1002. if ($parsedFrame['incdec']['left'] === false)
  1003. {
  1004. $parsedFrame['volumechange']['left'] *= - 1;
  1005. }
  1006. $frame_offset += $frame_bytesvolume;
  1007. $parsedFrame['peakvolume']['right'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
  1008. $frame_offset += $frame_bytesvolume;
  1009. $parsedFrame['peakvolume']['left'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
  1010. $frame_offset += $frame_bytesvolume;
  1011. if ($id3v2_majorversion == 3)
  1012. {
  1013. $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
  1014. if (strlen($parsedFrame['data']) > 0)
  1015. {
  1016. $parsedFrame['incdec']['rightrear'] = (bool) substr($frame_incrdecrflags, 4, 1);
  1017. $parsedFrame['incdec']['leftrear'] = (bool) substr($frame_incrdecrflags, 5, 1);
  1018. $parsedFrame['volumechange']['rightrear'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
  1019. if ($parsedFrame['incdec']['rightrear'] === false)
  1020. {
  1021. $parsedFrame['volumechange']['rightrear'] *= - 1;
  1022. }
  1023. $frame_offset += $frame_bytesvolume;
  1024. $parsedFrame['volumechange']['leftrear'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
  1025. if ($parsedFrame['incdec']['leftrear'] === false)
  1026. {
  1027. $parsedFrame['volumechange']['leftrear'] *= - 1;
  1028. }
  1029. $frame_offset += $frame_bytesvolume;
  1030. $parsedFrame['peakvolume']['rightrear'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
  1031. $frame_offset += $frame_bytesvolume;
  1032. $parsedFrame['peakvolume']['leftrear'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
  1033. $frame_offset += $frame_bytesvolume;
  1034. }
  1035. $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
  1036. if (strlen($parsedFrame['data']) > 0)
  1037. {
  1038. $parsedFrame['incdec']['center'] = (bool) substr($frame_incrdecrflags, 3, 1);
  1039. $parsedFrame['volumechange']['center'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
  1040. if ($parsedFrame['incdec']['center'] === false)
  1041. {
  1042. $parsedFrame['volumechange']['center'] *= - 1;
  1043. }
  1044. $frame_offset += $frame_bytesvolume;
  1045. $parsedFrame['peakvolume']['center'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
  1046. $frame_offset += $frame_bytesvolume;
  1047. }
  1048. $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
  1049. if (strlen($parsedFrame['data']) > 0)
  1050. {
  1051. $parsedFrame['incdec']['bass'] = (bool) substr($frame_incrdecrflags, 2, 1);
  1052. $parsedFrame['volumechange']['bass'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
  1053. if ($parsedFrame['incdec']['bass'] === false)
  1054. {
  1055. $parsedFrame['volumechange']['bass'] *= - 1;
  1056. }
  1057. $frame_offset += $frame_bytesvolume;
  1058. $parsedFrame['peakvolume']['bass'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
  1059. $frame_offset += $frame_bytesvolume;
  1060. }
  1061. }
  1062. unset($parsedFrame['data']);
  1063. }
  1064. elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'EQU2'))
  1065. { // 4.12 EQU2 Equalisation (2) (ID3v2.4+ only)
  1066. // There may be more than one 'EQU2' frame in each tag,
  1067. // but only one with the same identification string
  1068. // <Header of 'Equalisation (2)', ID: 'EQU2'>
  1069. // Interpolation method $xx
  1070. // $00 Band
  1071. // $01 Linear
  1072. // Identification <text string> $00
  1073. // The following is then repeated for every adjustment point
  1074. // Frequency $xx xx
  1075. // Volume adjustment $xx xx
  1076. $frame_offset = 0;
  1077. $frame_interpolationmethod = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  1078. $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
  1079. $frame_idstring = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  1080. if (ord($frame_idstring) === 0)
  1081. {
  1082. $frame_idstring = '';
  1083. }
  1084. $parsedFrame['description'] = $frame_idstring;
  1085. $frame_remainingdata = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00"));
  1086. while (strlen($frame_remainingdata))
  1087. {
  1088. $frame_frequency = getid3_lib :: BigEndian2Int(substr($frame_remainingdata, 0, 2)) / 2;
  1089. $parsedFrame['data'][$frame_frequency] = getid3_lib :: BigEndian2Int(substr($frame_remainingdata, 2, 2), false, true);
  1090. $frame_remainingdata = substr($frame_remainingdata, 4);
  1091. }
  1092. $parsedFrame['interpolationmethod'] = $frame_interpolationmethod;
  1093. unset($parsedFrame['data']);
  1094. }
  1095. elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'EQUA')) || // 4.12 EQUA Equalisation (ID3v2.3 only)
  1096. (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'EQU')))
  1097. { // 4.13 EQU Equalisation (ID3v2.2 only)
  1098. // There may only be one 'EQUA' frame in each tag
  1099. // <Header for 'Relative volume adjustment', ID: 'EQU'>
  1100. // Adjustment bits $xx
  1101. // This is followed by 2 bytes + ('adjustment bits' rounded up to the
  1102. // nearest byte) for every equalisation band in the following format,
  1103. // giving a frequency range of 0 - 32767Hz:
  1104. // Increment/decrement %x (MSB of the Frequency)
  1105. // Frequency (lower 15 bits)
  1106. // Adjustment $xx (xx ...)
  1107. $frame_offset = 0;
  1108. $parsedFrame['adjustmentbits'] = substr($parsedFrame['data'], $frame_offset ++, 1);
  1109. $frame_adjustmentbytes = ceil($parsedFrame['adjustmentbits'] / 8);
  1110. $frame_remainingdata = (string) substr($parsedFrame['data'], $frame_offset);
  1111. while (strlen($frame_remainingdata) > 0)
  1112. {
  1113. $frame_frequencystr = getid3_lib :: BigEndian2Bin(substr($frame_remainingdata, 0, 2));
  1114. $frame_incdec = (bool) substr($frame_frequencystr, 0, 1);
  1115. $frame_frequency = bindec(substr($frame_frequencystr, 1, 15));
  1116. $parsedFrame[$frame_frequency]['incdec'] = $frame_incdec;
  1117. $parsedFrame[$frame_frequency]['adjustment'] = getid3_lib :: BigEndian2Int(substr($frame_remainingdata, 2, $frame_adjustmentbytes));
  1118. if ($parsedFrame[$frame_frequency]['incdec'] === false)
  1119. {
  1120. $parsedFrame[$frame_frequency]['adjustment'] *= - 1;
  1121. }
  1122. $frame_remainingdata = substr($frame_remainingdata, 2 + $frame_adjustmentbytes);
  1123. }
  1124. unset($parsedFrame['data']);
  1125. }
  1126. elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RVRB')) || // 4.13 RVRB Reverb
  1127. (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'REV')))
  1128. { // 4.14 REV Reverb
  1129. // There may only be one 'RVRB' frame in each tag.
  1130. // <Header for 'Reverb', ID: 'RVRB'>
  1131. // Reverb left (ms) $xx xx
  1132. // Reverb right (ms) $xx xx
  1133. // Reverb bounces, left $xx
  1134. // Reverb bounces, right $xx
  1135. // Reverb feedback, left to left $xx
  1136. // Reverb feedback, left to right $xx
  1137. // Reverb feedback, right to right $xx
  1138. // Reverb feedback, right to left $xx
  1139. // Premix left to right $xx
  1140. // Premix right to left $xx
  1141. $frame_offset = 0;
  1142. $parsedFrame['left'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
  1143. $frame_offset += 2;
  1144. $parsedFrame['right'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
  1145. $frame_offset += 2;
  1146. $parsedFrame['bouncesL'] = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  1147. $parsedFrame['bouncesR'] = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  1148. $parsedFrame['feedbackLL'] = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  1149. $parsedFrame['feedbackLR'] = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  1150. $parsedFrame['feedbackRR'] = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  1151. $parsedFrame['feedbackRL'] = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  1152. $parsedFrame['premixLR'] = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  1153. $parsedFrame['premixRL'] = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  1154. unset($parsedFrame['data']);
  1155. }
  1156. elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'APIC')) || // 4.14 APIC Attached picture
  1157. (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'PIC')))
  1158. { // 4.15 PIC Attached picture
  1159. // There may be several pictures attached to one file,
  1160. // each in their individual 'APIC' frame, but only one
  1161. // with the same content descriptor
  1162. // <Header for 'Attached picture', ID: 'APIC'>
  1163. // Text encoding $xx
  1164. // ID3v2.3+ => MIME type <text string> $00
  1165. // ID3v2.2 => Image format $xx xx xx
  1166. // Picture type $xx
  1167. // Description <text string according to encoding> $00 (00)
  1168. // Picture data <binary data>
  1169. $frame_offset = 0;
  1170. $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  1171. if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3)))
  1172. {
  1173. $ThisFileInfo['warning'][] = 'Invalid text encoding byte (' . $frame_textencoding . ') in frame "' . $parsedFrame['frame_name'] . '" - defaulting to ISO-8859-1 encoding';
  1174. }
  1175. if ($id3v2_majorversion == 2)
  1176. {
  1177. $frame_imagetype = substr($parsedFrame['data'], $frame_offset, 3);
  1178. if (strtolower($frame_imagetype) == 'ima')
  1179. {
  1180. // complete hack for mp3Rage (www.chaoticsoftware.com) that puts ID3v2.3-formatted
  1181. // MIME type instead of 3-char ID3v2.2-format image type (thanks xbhoff�pacbell*net)
  1182. $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
  1183. $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  1184. if (ord($frame_mimetype) === 0)
  1185. {
  1186. $frame_mimetype = '';
  1187. }
  1188. $frame_imagetype = strtoupper(str_replace('image/', '', strtolower($frame_mimetype)));
  1189. if ($frame_imagetype == 'JPEG')
  1190. {
  1191. $frame_imagetype = 'JPG';
  1192. }
  1193. $frame_offset = $frame_terminatorpos + strlen("\x00");
  1194. }
  1195. else
  1196. {
  1197. $frame_offset += 3;
  1198. }
  1199. }
  1200. if ($id3v2_majorversion > 2)
  1201. {
  1202. $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
  1203. $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  1204. if (ord($frame_mimetype) === 0)
  1205. {
  1206. $frame_mimetype = '';
  1207. }
  1208. $frame_offset = $frame_terminatorpos + strlen("\x00");
  1209. }
  1210. $frame_picturetype = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  1211. $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
  1212. if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0)
  1213. {
  1214. $frame_terminatorpos ++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
  1215. }
  1216. $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  1217. if (ord($frame_description) === 0)
  1218. {
  1219. $frame_description = '';
  1220. }
  1221. $parsedFrame['encodingid'] = $frame_textencoding;
  1222. $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
  1223. if ($id3v2_majorversion == 2)
  1224. {
  1225. $parsedFrame['imagetype'] = $frame_imagetype;
  1226. }
  1227. else
  1228. {
  1229. $parsedFrame['mime'] = $frame_mimetype;
  1230. }
  1231. $parsedFrame['picturetypeid'] = $frame_picturetype;
  1232. $parsedFrame['picturetype'] = $this->APICPictureTypeLookup($frame_picturetype);
  1233. $parsedFrame['description'] = $frame_description;
  1234. $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
  1235. $imagechunkcheck = getid3_lib :: GetDataImageSize($parsedFrame['data']);
  1236. if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3))
  1237. {
  1238. $parsedFrame['image_mime'] = 'image/' . getid3_lib :: ImageTypesLookup($imagechunkcheck[2]);
  1239. if ($imagechunkcheck[0])
  1240. {
  1241. $parsedFrame['image_width'] = $imagechunkcheck[0];
  1242. }
  1243. if ($imagechunkcheck[1])
  1244. {
  1245. $parsedFrame['image_height'] = $imagechunkcheck[1];
  1246. }
  1247. $parsedFrame['image_bytes'] = strlen($parsedFrame['data']);
  1248. }
  1249. }
  1250. elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GEOB')) || // 4.15 GEOB General encapsulated object
  1251. (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'GEO')))
  1252. { // 4.16 GEO General encapsulated object
  1253. // There may be more than one 'GEOB' frame in each tag,
  1254. // but only one with the same content descriptor
  1255. // <Header for 'General encapsulated object', ID: 'GEOB'>
  1256. // Text encoding $xx
  1257. // MIME type <text string> $00
  1258. // Filename <text string according to encoding> $00 (00)
  1259. // Content description <text string according to encoding> $00 (00)
  1260. // Encapsulated object <binary data>
  1261. $frame_offset = 0;
  1262. $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  1263. if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3)))
  1264. {
  1265. $ThisFileInfo['warning'][] = 'Invalid text encoding byte (' . $frame_textencoding . ') in frame "' . $parsedFrame['frame_name'] . '" - defaulting to ISO-8859-1 encoding';
  1266. }
  1267. $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
  1268. $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  1269. if (ord($frame_mimetype) === 0)
  1270. {
  1271. $frame_mimetype = '';
  1272. }
  1273. $frame_offset = $frame_terminatorpos + strlen("\x00");
  1274. $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
  1275. if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0)
  1276. {
  1277. $frame_terminatorpos ++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
  1278. }
  1279. $frame_filename = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  1280. if (ord($frame_filename) === 0)
  1281. {
  1282. $frame_filename = '';
  1283. }
  1284. $frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding));
  1285. $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
  1286. if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0)
  1287. {
  1288. $frame_terminatorpos ++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
  1289. }
  1290. $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  1291. if (ord($frame_description) === 0)
  1292. {
  1293. $frame_description = '';
  1294. }
  1295. $frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding));
  1296. $parsedFrame['objectdata'] = (string) substr($parsedFrame['data'], $frame_offset);
  1297. $parsedFrame['encodingid'] = $frame_textencoding;
  1298. $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
  1299. $parsedFrame['mime'] = $frame_mimetype;
  1300. $parsedFrame['filename'] = $frame_filename;
  1301. $parsedFrame['description'] = $frame_description;
  1302. unset($parsedFrame['data']);
  1303. }
  1304. elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'PCNT')) || // 4.16 PCNT Play counter
  1305. (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CNT')))
  1306. { // 4.17 CNT Play counter
  1307. // There may only be one 'PCNT' frame in each tag.
  1308. // When the counter reaches all one's, one byte is inserted in
  1309. // front of the counter thus making the counter eight bits bigger
  1310. // <Header for 'Play counter', ID: 'PCNT'>
  1311. // Counter $xx xx xx xx (xx ...)
  1312. $parsedFrame['data'] = getid3_lib :: BigEndian2Int($parsedFrame['data']);
  1313. }
  1314. elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'POPM')) || // 4.17 POPM Popularimeter
  1315. (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'POP')))
  1316. { // 4.18 POP Popularimeter
  1317. // There may be more than one 'POPM' frame in each tag,
  1318. // but only one with the same email address
  1319. // <Header for 'Popularimeter', ID: 'POPM'>
  1320. // Email to user <text string> $00
  1321. // Rating $xx
  1322. // Counter $xx xx xx xx (xx ...)
  1323. $frame_offset = 0;
  1324. $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
  1325. $frame_emailaddress = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  1326. if (ord($frame_emailaddress) === 0)
  1327. {
  1328. $frame_emailaddress = '';
  1329. }
  1330. $frame_offset = $frame_terminatorpos + strlen("\x00");
  1331. $frame_rating = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  1332. $parsedFrame['data'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset));
  1333. $parsedFrame['email'] = $frame_emailaddress;
  1334. $parsedFrame['rating'] = $frame_rating;
  1335. unset($parsedFrame['data']);
  1336. }
  1337. elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RBUF')) || // 4.18 RBUF Recommended buffer size
  1338. (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'BUF')))
  1339. { // 4.19 BUF Recommended buffer size
  1340. // There may only be one 'RBUF' frame in each tag
  1341. // <Header for 'Recommended buffer size', ID: 'RBUF'>
  1342. // Buffer size $xx xx xx
  1343. // Embedded info flag %0000000x
  1344. // Offset to next tag $xx xx xx xx
  1345. $frame_offset = 0;
  1346. $parsedFrame['buffersize'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 3));
  1347. $frame_offset += 3;
  1348. $frame_embeddedinfoflags = getid3_lib :: BigEndian2Bin(substr($parsedFrame['data'], $frame_offset ++, 1));
  1349. $parsedFrame['flags']['embededinfo'] = (bool) substr($frame_embeddedinfoflags, 7, 1);
  1350. $parsedFrame['nexttagoffset'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
  1351. unset($parsedFrame['data']);
  1352. }
  1353. elseif (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CRM'))
  1354. { // 4.20 Encrypted meta frame (ID3v2.2 only)
  1355. // There may be more than one 'CRM' frame in a tag,
  1356. // but only one with the same 'owner identifier'
  1357. // <Header for 'Encrypted meta frame', ID: 'CRM'>
  1358. // Owner identifier <textstring> $00 (00)
  1359. // Content/explanation <textstring> $00 (00)
  1360. // Encrypted datablock <binary data>
  1361. $frame_offset = 0;
  1362. $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
  1363. $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  1364. $frame_offset = $frame_terminatorpos + strlen("\x00");
  1365. $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
  1366. $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  1367. if (ord($frame_description) === 0)
  1368. {
  1369. $frame_description = '';
  1370. }
  1371. $frame_offset = $frame_terminatorpos + strlen("\x00");
  1372. $parsedFrame['ownerid'] = $frame_ownerid;
  1373. $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
  1374. $parsedFrame['description'] = $frame_description;
  1375. unset($parsedFrame['data']);
  1376. }
  1377. elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'AENC')) || // 4.19 AENC Audio encryption
  1378. (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CRA')))
  1379. { // 4.21 CRA Audio encryption
  1380. // There may be more than one 'AENC' frames in a tag,
  1381. // but only one with the same 'Owner identifier'
  1382. // <Header for 'Audio encryption', ID: 'AENC'>
  1383. // Owner identifier <text string> $00
  1384. // Preview start $xx xx
  1385. // Preview length $xx xx
  1386. // Encryption info <binary data>
  1387. $frame_offset = 0;
  1388. $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
  1389. $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  1390. if (ord($frame_ownerid) === 0)
  1391. {
  1392. $frame_ownerid == '';
  1393. }
  1394. $frame_offset = $frame_terminatorpos + strlen("\x00");
  1395. $parsedFrame['ownerid'] = $frame_ownerid;
  1396. $parsedFrame['previewstart'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
  1397. $frame_offset += 2;
  1398. $parsedFrame['previewlength'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
  1399. $frame_offset += 2;
  1400. $parsedFrame['encryptioninfo'] = (string) substr($parsedFrame['data'], $frame_offset);
  1401. unset($parsedFrame['data']);
  1402. }
  1403. elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'LINK')) || // 4.20 LINK Linked information
  1404. (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'LNK')))
  1405. { // 4.22 LNK Linked information
  1406. // There may be more than one 'LINK' frame in a tag,
  1407. // but only one with the same contents
  1408. // <Header for 'Linked information', ID: 'LINK'>
  1409. // ID3v2.3+ => Frame identifier $xx xx xx xx
  1410. // ID3v2.2 => Frame identifier $xx xx xx
  1411. // URL <text string> $00
  1412. // ID and additional data <text string(s)>
  1413. $frame_offset = 0;
  1414. if ($id3v2_majorversion == 2)
  1415. {
  1416. $parsedFrame['frameid'] = substr($parsedFrame['data'], $frame_offset, 3);
  1417. $frame_offset += 3;
  1418. }
  1419. else
  1420. {
  1421. $parsedFrame['frameid'] = substr($parsedFrame['data'], $frame_offset, 4);
  1422. $frame_offset += 4;
  1423. }
  1424. $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
  1425. $frame_url = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  1426. if (ord($frame_url) === 0)
  1427. {
  1428. $frame_url = '';
  1429. }
  1430. $frame_offset = $frame_terminatorpos + strlen("\x00");
  1431. $parsedFrame['url'] = $frame_url;
  1432. $parsedFrame['additionaldata'] = (string) substr($parsedFrame['data'], $frame_offset);
  1433. if (! empty($parsedFrame['framenameshort']) && $parsedFrame['url'])
  1434. {
  1435. $ThisFileInfo['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib :: iconv_fallback($parsedFrame['encoding'], $ThisFileInfo['id3v2']['encoding'], $parsedFrame['url']);
  1436. }
  1437. unset($parsedFrame['data']);
  1438. }
  1439. elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'POSS'))
  1440. { // 4.21 POSS Position synchronisation frame (ID3v2.3+ only)
  1441. // There may only be one 'POSS' frame in each tag
  1442. // <Head for 'Position synchronisation', ID: 'POSS'>
  1443. // Time stamp format $xx
  1444. // Position $xx (xx ...)
  1445. $frame_offset = 0;
  1446. $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  1447. $parsedFrame['position'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset));
  1448. unset($parsedFrame['data']);
  1449. }
  1450. elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USER'))
  1451. { // 4.22 USER Terms of use (ID3v2.3+ only)
  1452. // There may be more than one 'Terms of use' frame in a tag,
  1453. // but only one with the same 'Language'
  1454. // <Header for 'Terms of use frame', ID: 'USER'>
  1455. // Text encoding $xx
  1456. // Language $xx xx xx
  1457. // The actual text <text string according to encoding>
  1458. $frame_offset = 0;
  1459. $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  1460. if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3)))
  1461. {
  1462. $ThisFileInfo['warning'][] = 'Invalid text encoding byte (' . $frame_textencoding . ') in frame "' . $parsedFrame['frame_name'] . '" - defaulting to ISO-8859-1 encoding';
  1463. }
  1464. $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
  1465. $frame_offset += 3;
  1466. $parsedFrame['language'] = $frame_language;
  1467. $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
  1468. $parsedFrame['encodingid'] = $frame_textencoding;
  1469. $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
  1470. $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
  1471. if (! empty($parsedFrame['framenameshort']) && ! empty($parsedFrame['data']))
  1472. {
  1473. $ThisFileInfo['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib :: iconv_fallback($parsedFrame['encoding'], $ThisFileInfo['id3v2']['encoding'], $parsedFrame['data']);
  1474. }
  1475. unset($parsedFrame['data']);
  1476. }
  1477. elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'OWNE'))
  1478. { // 4.23 OWNE Ownership frame (ID3v2.3+ only)
  1479. // There may only be one 'OWNE' frame in a tag
  1480. // <Header for 'Ownership frame', ID: 'OWNE'>
  1481. // Text encoding $xx
  1482. // Price paid <text string> $00
  1483. // Date of purch. <text string>
  1484. // Seller <text string according to encoding>
  1485. $frame_offset = 0;
  1486. $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  1487. if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3)))
  1488. {
  1489. $ThisFileInfo['warning'][] = 'Invalid text encoding byte (' . $frame_textencoding . ') in frame "' . $parsedFrame['frame_name'] . '" - defaulting to ISO-8859-1 encoding';
  1490. }
  1491. $parsedFrame['encodingid'] = $frame_textencoding;
  1492. $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
  1493. $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
  1494. $frame_pricepaid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  1495. $frame_offset = $frame_terminatorpos + strlen("\x00");
  1496. $parsedFrame['pricepaid']['currencyid'] = substr($frame_pricepaid, 0, 3);
  1497. $parsedFrame['pricepaid']['currency'] = $this->LookupCurrencyUnits($parsedFrame['pricepaid']['currencyid']);
  1498. $parsedFrame['pricepaid']['value'] = substr($frame_pricepaid, 3);
  1499. $parsedFrame['purchasedate'] = substr($parsedFrame['data'], $frame_offset, 8);
  1500. if (! $this->IsValidDateStampString($parsedFrame['purchasedate']))
  1501. {
  1502. $parsedFrame['purchasedateunix'] = mktime(0, 0, 0, substr($parsedFrame['purchasedate'], 4, 2), substr($parsedFrame['purchasedate'], 6, 2), substr($parsedFrame['purchasedate'], 0, 4));
  1503. }
  1504. $frame_offset += 8;
  1505. $parsedFrame['seller'] = (string) substr($parsedFrame['data'], $frame_offset);
  1506. unset($parsedFrame['data']);
  1507. }
  1508. elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'COMR'))
  1509. { // 4.24 COMR Commercial frame (ID3v2.3+ only)
  1510. // There may be more than one 'commercial frame' in a tag,
  1511. // but no two may be identical
  1512. // <Header for 'Commercial frame', ID: 'COMR'>
  1513. // Text encoding $xx
  1514. // Price string <text string> $00
  1515. // Valid until <text string>
  1516. // Contact URL <text string> $00
  1517. // Received as $xx
  1518. // Name of seller <text string according to encoding> $00 (00)
  1519. // Description <text string according to encoding> $00 (00)
  1520. // Picture MIME type <string> $00
  1521. // Seller logo <binary data>
  1522. $frame_offset = 0;
  1523. $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  1524. if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3)))
  1525. {
  1526. $ThisFileInfo['warning'][] = 'Invalid text encoding byte (' . $frame_textencoding . ') in frame "' . $parsedFrame['frame_name'] . '" - defaulting to ISO-8859-1 encoding';
  1527. }
  1528. $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
  1529. $frame_pricestring = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  1530. $frame_offset = $frame_terminatorpos + strlen("\x00");
  1531. $frame_rawpricearray = explode('/', $frame_pricestring);
  1532. foreach ($frame_rawpricearray as $key => $val)
  1533. {
  1534. $frame_currencyid = substr($val, 0, 3);
  1535. $parsedFrame['price'][$frame_currencyid]['currency'] = $this->LookupCurrencyUnits($frame_currencyid);
  1536. $parsedFrame['price'][$frame_currencyid]['value'] = substr($val, 3);
  1537. }
  1538. $frame_datestring = substr($parsedFrame['data'], $frame_offset, 8);
  1539. $frame_offset += 8;
  1540. $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
  1541. $frame_contacturl = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  1542. $frame_offset = $frame_terminatorpos + strlen("\x00");
  1543. $frame_receivedasid = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  1544. $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
  1545. if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0)
  1546. {
  1547. $frame_terminatorpos ++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
  1548. }
  1549. $frame_sellername = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  1550. if (ord($frame_sellername) === 0)
  1551. {
  1552. $frame_sellername = '';
  1553. }
  1554. $frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding));
  1555. $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
  1556. if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0)
  1557. {
  1558. $frame_terminatorpos ++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
  1559. }
  1560. $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  1561. if (ord($frame_description) === 0)
  1562. {
  1563. $frame_description = '';
  1564. }
  1565. $frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding));
  1566. $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
  1567. $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  1568. $frame_offset = $frame_terminatorpos + strlen("\x00");
  1569. $frame_sellerlogo = substr($parsedFrame['data'], $frame_offset);
  1570. $parsedFrame['encodingid'] = $frame_textencoding;
  1571. $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
  1572. $parsedFrame['pricevaliduntil'] = $frame_datestring;
  1573. $parsedFrame['contacturl'] = $frame_contacturl;
  1574. $parsedFrame['receivedasid'] = $frame_receivedasid;
  1575. $parsedFrame['receivedas'] = $this->COMRReceivedAsLookup($frame_receivedasid);
  1576. $parsedFrame['sellername'] = $frame_sellername;
  1577. $parsedFrame['description'] = $frame_description;
  1578. $parsedFrame['mime'] = $frame_mimetype;
  1579. $parsedFrame['logo'] = $frame_sellerlogo;
  1580. unset($parsedFrame['data']);
  1581. }
  1582. elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'ENCR'))
  1583. { // 4.25 ENCR Encryption method registration (ID3v2.3+ only)
  1584. // There may be several 'ENCR' frames in a tag,
  1585. // but only one containing the same symbol
  1586. // and only one containing the same owner identifier
  1587. // <Header for 'Encryption method registration', ID: 'ENCR'>
  1588. // Owner identifier <text string> $00
  1589. // Method symbol $xx
  1590. // Encryption data <binary data>
  1591. $frame_offset = 0;
  1592. $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
  1593. $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  1594. if (ord($frame_ownerid) === 0)
  1595. {
  1596. $frame_ownerid = '';
  1597. }
  1598. $frame_offset = $frame_terminatorpos + strlen("\x00");
  1599. $parsedFrame['ownerid'] = $frame_ownerid;
  1600. $parsedFrame['methodsymbol'] = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  1601. $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
  1602. }
  1603. elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GRID'))
  1604. { // 4.26 GRID Group identification registration (ID3v2.3+ only)
  1605. // There may be several 'GRID' frames in a tag,
  1606. // but only one containing the same symbol
  1607. // and only one containing the same owner identifier
  1608. // <Header for 'Group ID registration', ID: 'GRID'>
  1609. // Owner identifier <text string> $00
  1610. // Group symbol $xx
  1611. // Group dependent data <binary data>
  1612. $frame_offset = 0;
  1613. $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
  1614. $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  1615. if (ord($frame_ownerid) === 0)
  1616. {
  1617. $frame_ownerid = '';
  1618. }
  1619. $frame_offset = $frame_terminatorpos + strlen("\x00");
  1620. $parsedFrame['ownerid'] = $frame_ownerid;
  1621. $parsedFrame['groupsymbol'] = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  1622. $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
  1623. }
  1624. elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'PRIV'))
  1625. { // 4.27 PRIV Private frame (ID3v2.3+ only)
  1626. // The tag may contain more than one 'PRIV' frame
  1627. // but only with different contents
  1628. // <Header for 'Private frame', ID: 'PRIV'>
  1629. // Owner identifier <text string> $00
  1630. // The private data <binary data>
  1631. $frame_offset = 0;
  1632. $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
  1633. $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
  1634. if (ord($frame_ownerid) === 0)
  1635. {
  1636. $frame_ownerid = '';
  1637. }
  1638. $frame_offset = $frame_terminatorpos + strlen("\x00");
  1639. $parsedFrame['ownerid'] = $frame_ownerid;
  1640. $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
  1641. }
  1642. elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'SIGN'))
  1643. { // 4.28 SIGN Signature frame (ID3v2.4+ only)
  1644. // There may be more than one 'signature frame' in a tag,
  1645. // but no two may be identical
  1646. // <Header for 'Signature frame', ID: 'SIGN'>
  1647. // Group symbol $xx
  1648. // Signature <binary data>
  1649. $frame_offset = 0;
  1650. $parsedFrame['groupsymbol'] = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  1651. $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
  1652. }
  1653. elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'SEEK'))
  1654. { // 4.29 SEEK Seek frame (ID3v2.4+ only)
  1655. // There may only be one 'seek frame' in a tag
  1656. // <Header for 'Seek frame', ID: 'SEEK'>
  1657. // Minimum offset to next tag $xx xx xx xx
  1658. $frame_offset = 0;
  1659. $parsedFrame['data'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
  1660. }
  1661. elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'ASPI'))
  1662. { // 4.30 ASPI Audio seek point index (ID3v2.4+ only)
  1663. // There may only be one 'audio seek point index' frame in a tag
  1664. // <Header for 'Seek Point Index', ID: 'ASPI'>
  1665. // Indexed data start (S) $xx xx xx xx
  1666. // Indexed data length (L) $xx xx xx xx
  1667. // Number of index points (N) $xx xx
  1668. // Bits per index point (b) $xx
  1669. // Then for every index point the following data is included:
  1670. // Fraction at index (Fi) $xx (xx)
  1671. $frame_offset = 0;
  1672. $parsedFrame['datastart'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
  1673. $frame_offset += 4;
  1674. $parsedFrame['indexeddatalength'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
  1675. $frame_offset += 4;
  1676. $parsedFrame['indexpoints'] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
  1677. $frame_offset += 2;
  1678. $parsedFrame['bitsperpoint'] = ord(substr($parsedFrame['data'], $frame_offset ++, 1));
  1679. $frame_bytesperpoint = ceil($parsedFrame['bitsperpoint'] / 8);
  1680. for($i = 0; $i < $frame_indexpoints; $i ++)
  1681. {
  1682. $parsedFrame['indexes'][$i] = getid3_lib :: BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesperpoint));
  1683. $frame_offset += $frame_bytesperpoint;
  1684. }
  1685. unset($parsedFrame['data']);
  1686. }
  1687. elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RGAD'))
  1688. { // Replay Gain Adjustment
  1689. // http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html
  1690. // There may only be one 'RGAD' frame in a tag
  1691. // <Header for 'Replay Gain Adjustment', ID: 'RGAD'>
  1692. // Peak Amplitude $xx $xx $xx $xx
  1693. // Radio Replay Gain Adjustment %aaabbbcd %dddddddd
  1694. // Audiophile Replay Gain Adjustment %aaabbbcd %dddddddd
  1695. // a - name code
  1696. // b - originator code
  1697. // c - sign bit
  1698. // d - replay gain adjustment
  1699. $frame_offset = 0;
  1700. $parsedFrame['peakamplitude'] = getid3_lib :: BigEndian2Float(substr($parsedFrame['data'], $frame_offset, 4));
  1701. $frame_offset += 4;
  1702. $rg_track_adjustment = getid3_lib :: Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2));
  1703. $frame_offset += 2;
  1704. $rg_album_adjustment = getid3_lib :: Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2));
  1705. $frame_offset += 2;
  1706. $parsedFrame['raw']['track']['name'] = getid3_lib :: Bin2Dec(substr($rg_track_adjustment, 0, 3));
  1707. $parsedFrame['raw']['track']['originator'] = getid3_lib :: Bin2Dec(substr($rg_track_adjustment, 3, 3));
  1708. $parsedFrame['raw']['track']['signbit'] = getid3_lib :: Bin2Dec(substr($rg_track_adjustment, 6, 1));
  1709. $parsedFrame['raw']['track']['adjustment'] = getid3_lib :: Bin2Dec(substr($rg_track_adjustment, 7, 9));
  1710. $parsedFrame['raw']['album']['name'] = getid3_lib :: Bin2Dec(substr($rg_album_adjustment, 0, 3));
  1711. $parsedFrame['raw']['album']['originator'] = getid3_lib :: Bin2Dec(substr($rg_album_adjustment, 3, 3));
  1712. $parsedFrame['raw']['album']['signbit'] = getid3_lib :: Bin2Dec(substr($rg_album_adjustment, 6, 1));
  1713. $parsedFrame['raw']['album']['adjustment'] = getid3_lib :: Bin2Dec(substr($rg_album_adjustment, 7, 9));
  1714. $parsedFrame['track']['name'] = getid3_lib :: RGADnameLookup($parsedFrame['raw']['track']['name']);
  1715. $parsedFrame['track']['originator'] = getid3_lib :: RGADoriginatorLookup($parsedFrame['raw']['track']['originator']);
  1716. $parsedFrame['track']['adjustment'] = getid3_lib :: RGADadjustmentLookup($parsedFrame['raw']['track']['adjustment'], $parsedFrame['raw']['track']['signbit']);
  1717. $parsedFrame['album']['name'] = getid3_lib :: RGADnameLookup($parsedFrame['raw']['album']['name']);
  1718. $parsedFrame['album']['originator'] = getid3_lib :: RGADoriginatorLookup($parsedFrame['raw']['album']['originator']);
  1719. $parsedFrame['album']['adjustment'] = getid3_lib :: RGADadjustmentLookup($parsedFrame['raw']['album']['adjustment'], $parsedFrame['raw']['album']['signbit']);
  1720. $ThisFileInfo['replay_gain']['track']['peak'] = $parsedFrame['peakamplitude'];
  1721. $ThisFileInfo['replay_gain']['track']['originator'] = $parsedFrame['track']['originator'];
  1722. $ThisFileInfo['replay_gain']['track']['adjustment'] = $parsedFrame['track']['adjustment'];
  1723. $ThisFileInfo['replay_gain']['album']['originator'] = $parsedFrame['album']['originator'];
  1724. $ThisFileInfo['replay_gain']['album']['adjustment'] = $parsedFrame['album']['adjustment'];
  1725. unset($parsedFrame['data']);
  1726. }
  1727. return true;
  1728. }
  1729. function DeUnsynchronise($data)
  1730. {
  1731. return str_replace("\xFF\x00", "\xFF", $data);
  1732. }
  1733. function LookupCurrencyUnits($currencyid)
  1734. {
  1735. $begin = __LINE__;
  1736. /** This is not a comment!
  1737. AED Dirhams
  1738. AFA Afghanis
  1739. ALL Leke
  1740. AMD Drams
  1741. ANG Guilders
  1742. AOA Kwanza
  1743. ARS Pesos
  1744. ATS Schillings
  1745. AUD Dollars
  1746. AWG Guilders
  1747. AZM Manats
  1748. BAM Convertible Marka
  1749. BBD Dollars
  1750. BDT Taka
  1751. BEF Francs
  1752. BGL Leva
  1753. BHD Dinars
  1754. BIF Francs
  1755. BMD Dollars
  1756. BND Dollars
  1757. BOB Bolivianos
  1758. BRL Brazil Real
  1759. BSD Dollars
  1760. BTN Ngultrum
  1761. BWP Pulas
  1762. BYR Rubles
  1763. BZD Dollars
  1764. CAD Dollars
  1765. CDF Congolese Francs
  1766. CHF Francs
  1767. CLP Pesos
  1768. CNY Yuan Renminbi
  1769. COP Pesos
  1770. CRC Colones
  1771. CUP Pesos
  1772. CVE Escudos
  1773. CYP Pounds
  1774. CZK Koruny
  1775. DEM Deutsche Marks
  1776. DJF Francs
  1777. DKK Kroner
  1778. DOP Pesos
  1779. DZD Algeria Dinars
  1780. EEK Krooni
  1781. EGP Pounds
  1782. ERN Nakfa
  1783. ESP Pesetas
  1784. ETB Birr
  1785. EUR Euro
  1786. FIM Markkaa
  1787. FJD Dollars
  1788. FKP Pounds
  1789. FRF Francs
  1790. GBP Pounds
  1791. GEL Lari
  1792. GGP Pounds
  1793. GHC Cedis
  1794. GIP Pounds
  1795. GMD Dalasi
  1796. GNF Francs
  1797. GRD Drachmae
  1798. GTQ Quetzales
  1799. GYD Dollars
  1800. HKD Dollars
  1801. HNL Lempiras
  1802. HRK Kuna
  1803. HTG Gourdes
  1804. HUF Forints
  1805. IDR Rupiahs
  1806. IEP Pounds
  1807. ILS New Shekels
  1808. IMP Pounds
  1809. INR Rupees
  1810. IQD Dinars
  1811. IRR Rials
  1812. ISK Kronur
  1813. ITL Lire
  1814. JEP Pounds
  1815. JMD Dollars
  1816. JOD Dinars
  1817. JPY Yen
  1818. KES Shillings
  1819. KGS Soms
  1820. KHR Riels
  1821. KMF Francs
  1822. KPW Won
  1823. KWD Dinars
  1824. KYD Dollars
  1825. KZT Tenge
  1826. LAK Kips
  1827. LBP Pounds
  1828. LKR Rupees
  1829. LRD Dollars
  1830. LSL Maloti
  1831. LTL Litai
  1832. LUF Francs
  1833. LVL Lati
  1834. LYD Dinars
  1835. MAD Dirhams
  1836. MDL Lei
  1837. MGF Malagasy Francs
  1838. MKD Denars
  1839. MMK Kyats
  1840. MNT Tugriks
  1841. MOP Patacas
  1842. MRO Ouguiyas
  1843. MTL Liri
  1844. MUR Rupees
  1845. MVR Rufiyaa
  1846. MWK Kwachas
  1847. MXN Pesos
  1848. MYR Ringgits
  1849. MZM Meticais
  1850. NAD Dollars
  1851. NGN Nairas
  1852. NIO Gold Cordobas
  1853. NLG Guilders
  1854. NOK Krone
  1855. NPR Nepal Rupees
  1856. NZD Dollars
  1857. OMR Rials
  1858. PAB Balboa
  1859. PEN Nuevos Soles
  1860. PGK Kina
  1861. PHP Pesos
  1862. PKR Rupees
  1863. PLN Zlotych
  1864. PTE Escudos
  1865. PYG Guarani
  1866. QAR Rials
  1867. ROL Lei
  1868. RUR Rubles
  1869. RWF Rwanda Francs
  1870. SAR Riyals
  1871. SBD Dollars
  1872. SCR Rupees
  1873. SDD Dinars
  1874. SEK Kronor
  1875. SGD Dollars
  1876. SHP Pounds
  1877. SIT Tolars
  1878. SKK Koruny
  1879. SLL Leones
  1880. SOS Shillings
  1881. SPL Luigini
  1882. SRG Guilders
  1883. STD Dobras
  1884. SVC Colones
  1885. SYP Pounds
  1886. SZL Emalangeni
  1887. THB Baht
  1888. TJR Rubles
  1889. TMM Manats
  1890. TND Dinars
  1891. TOP Pa'anga
  1892. TRL Liras
  1893. TTD Dollars
  1894. TVD Tuvalu Dollars
  1895. TWD New Dollars
  1896. TZS Shillings
  1897. UAH Hryvnia
  1898. UGX Shillings
  1899. USD Dollars
  1900. UYU Pesos
  1901. UZS Sums
  1902. VAL Lire
  1903. VEB Bolivares
  1904. VND Dong
  1905. VUV Vatu
  1906. WST Tala
  1907. XAF Francs
  1908. XAG Ounces
  1909. XAU Ounces
  1910. XCD Dollars
  1911. XDR Special Drawing Rights
  1912. XPD Ounces
  1913. XPF Francs
  1914. XPT Ounces
  1915. YER Rials
  1916. YUM New Dinars
  1917. ZAR Rand
  1918. ZMK Kwacha
  1919. ZWD Zimbabwe Dollars
  1920. */
  1921. return getid3_lib :: EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-units');
  1922. }
  1923. function LookupCurrencyCountry($currencyid)
  1924. {
  1925. $begin = __LINE__;
  1926. /** This is not a comment!
  1927. AED United Arab Emirates
  1928. AFA Afghanistan
  1929. ALL Albania
  1930. AMD Armenia
  1931. ANG Netherlands Antilles
  1932. AOA Angola
  1933. ARS Argentina
  1934. ATS Austria
  1935. AUD Australia
  1936. AWG Aruba
  1937. AZM Azerbaijan
  1938. BAM Bosnia and Herzegovina
  1939. BBD Barbados
  1940. BDT Bangladesh
  1941. BEF Belgium
  1942. BGL Bulgaria
  1943. BHD Bahrain
  1944. BIF Burundi
  1945. BMD Bermuda
  1946. BND Brunei Darussalam
  1947. BOB Bolivia
  1948. BRL Brazil
  1949. BSD Bahamas
  1950. BTN Bhutan
  1951. BWP Botswana
  1952. BYR Belarus
  1953. BZD Belize
  1954. CAD Canada
  1955. CDF Congo/Kinshasa
  1956. CHF Switzerland
  1957. CLP Chile
  1958. CNY China
  1959. COP Colombia
  1960. CRC Costa Rica
  1961. CUP Cuba
  1962. CVE Cape Verde
  1963. CYP Cyprus
  1964. CZK Czech Republic
  1965. DEM Germany
  1966. DJF Djibouti
  1967. DKK Denmark
  1968. DOP Dominican Republic
  1969. DZD Algeria
  1970. EEK Estonia
  1971. EGP Egypt
  1972. ERN Eritrea
  1973. ESP Spain
  1974. ETB Ethiopia
  1975. EUR Euro Member Countries
  1976. FIM Finland
  1977. FJD Fiji
  1978. FKP Falkland Islands (Malvinas)
  1979. FRF France
  1980. GBP United Kingdom
  1981. GEL Georgia
  1982. GGP Guernsey
  1983. GHC Ghana
  1984. GIP Gibraltar
  1985. GMD Gambia
  1986. GNF Guinea
  1987. GRD Greece
  1988. GTQ Guatemala
  1989. GYD Guyana
  1990. HKD Hong Kong
  1991. HNL Honduras
  1992. HRK Croatia
  1993. HTG Haiti
  1994. HUF Hungary
  1995. IDR Indonesia
  1996. IEP Ireland (Eire)
  1997. ILS Israel
  1998. IMP Isle of Man
  1999. INR India
  2000. IQD Iraq
  2001. IRR Iran
  2002. ISK Iceland
  2003. ITL Italy
  2004. JEP Jersey
  2005. JMD Jamaica
  2006. JOD Jordan
  2007. JPY Japan
  2008. KES Kenya
  2009. KGS Kyrgyzstan
  2010. KHR Cambodia
  2011. KMF Comoros
  2012. KPW Korea
  2013. KWD Kuwait
  2014. KYD Cayman Islands
  2015. KZT Kazakstan
  2016. LAK Laos
  2017. LBP Lebanon
  2018. LKR Sri Lanka
  2019. LRD Liberia
  2020. LSL Lesotho
  2021. LTL Lithuania
  2022. LUF Luxembourg
  2023. LVL Latvia
  2024. LYD Libya
  2025. MAD Morocco
  2026. MDL Moldova
  2027. MGF Madagascar
  2028. MKD Macedonia
  2029. MMK Myanmar (Burma)
  2030. MNT Mongolia
  2031. MOP Macau
  2032. MRO Mauritania
  2033. MTL Malta
  2034. MUR Mauritius
  2035. MVR Maldives (Maldive Islands)
  2036. MWK Malawi
  2037. MXN Mexico
  2038. MYR Malaysia
  2039. MZM Mozambique
  2040. NAD Namibia
  2041. NGN Nigeria
  2042. NIO Nicaragua
  2043. NLG Netherlands (Holland)
  2044. NOK Norway
  2045. NPR Nepal
  2046. NZD New Zealand
  2047. OMR Oman
  2048. PAB Panama
  2049. PEN Peru
  2050. PGK Papua New Guinea
  2051. PHP Philippines
  2052. PKR Pakistan
  2053. PLN Poland
  2054. PTE Portugal
  2055. PYG Paraguay
  2056. QAR Qatar
  2057. ROL Romania
  2058. RUR Russia
  2059. RWF Rwanda
  2060. SAR Saudi Arabia
  2061. SBD Solomon Islands
  2062. SCR Seychelles
  2063. SDD Sudan
  2064. SEK Sweden
  2065. SGD Singapore
  2066. SHP Saint Helena
  2067. SIT Slovenia
  2068. SKK Slovakia
  2069. SLL Sierra Leone
  2070. SOS Somalia
  2071. SPL Seborga
  2072. SRG Suriname
  2073. STD S�o Tome and Principe
  2074. SVC El Salvador
  2075. SYP Syria
  2076. SZL Swaziland
  2077. THB Thailand
  2078. TJR Tajikistan
  2079. TMM Turkmenistan
  2080. TND Tunisia
  2081. TOP Tonga
  2082. TRL Turkey
  2083. TTD Trinidad and Tobago
  2084. TVD Tuvalu
  2085. TWD Taiwan
  2086. TZS Tanzania
  2087. UAH Ukraine
  2088. UGX Uganda
  2089. USD United States of America
  2090. UYU Uruguay
  2091. UZS Uzbekistan
  2092. VAL Vatican City
  2093. VEB Venezuela
  2094. VND Viet Nam
  2095. VUV Vanuatu
  2096. WST Samoa
  2097. XAF Communaut� Financi�re Africaine
  2098. XAG Silver
  2099. XAU Gold
  2100. XCD East Caribbean
  2101. XDR International Monetary Fund
  2102. XPD Palladium
  2103. XPF Comptoirs Fran�ais du Pacifique
  2104. XPT Platinum
  2105. YER Yemen
  2106. YUM Yugoslavia
  2107. ZAR South Africa
  2108. ZMK Zambia
  2109. ZWD Zimbabwe
  2110. */
  2111. return getid3_lib :: EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-country');
  2112. }
  2113. function LanguageLookup($languagecode, $casesensitive = false)
  2114. {
  2115. if (! $casesensitive)
  2116. {
  2117. $languagecode = strtolower($languagecode);
  2118. }
  2119. // http://www.id3.org/id3v2.4.0-structure.txt
  2120. // [4. ID3v2 frame overview]
  2121. // The three byte language field, present in several frames, is used to
  2122. // describe the language of the frame's content, according to ISO-639-2
  2123. // [ISO-639-2]. The language should be represented in lower case. If the
  2124. // language is not known the string "XXX" should be used.
  2125. // ISO 639-2 - http://www.id3.org/iso639-2.html
  2126. $begin = __LINE__;
  2127. /** This is not a comment!
  2128. XXX unknown
  2129. xxx unknown
  2130. aar Afar
  2131. abk Abkhazian
  2132. ace Achinese
  2133. ach Acoli
  2134. ada Adangme
  2135. afa Afro-Asiatic (Other)
  2136. afh Afrihili
  2137. afr Afrikaans
  2138. aka Akan
  2139. akk Akkadian
  2140. alb Albanian
  2141. ale Aleut
  2142. alg Algonquian Languages
  2143. amh Amharic
  2144. ang English, Old (ca. 450-1100)
  2145. apa Apache Languages
  2146. ara Arabic
  2147. arc Aramaic
  2148. arm Armenian
  2149. arn Araucanian
  2150. arp Arapaho
  2151. art Artificial (Other)
  2152. arw Arawak
  2153. asm Assamese
  2154. ath Athapascan Languages
  2155. ava Avaric
  2156. ave Avestan
  2157. awa Awadhi
  2158. aym Aymara
  2159. aze Azerbaijani
  2160. bad Banda
  2161. bai Bamileke Languages
  2162. bak Bashkir
  2163. bal Baluchi
  2164. bam Bambara
  2165. ban Balinese
  2166. baq Basque
  2167. bas Basa
  2168. bat Baltic (Other)
  2169. bej Beja
  2170. bel Byelorussian
  2171. bem Bemba
  2172. ben Bengali
  2173. ber Berber (Other)
  2174. bho Bhojpuri
  2175. bih Bihari
  2176. bik Bikol
  2177. bin Bini
  2178. bis Bislama
  2179. bla Siksika
  2180. bnt Bantu (Other)
  2181. bod Tibetan
  2182. bra Braj
  2183. bre Breton
  2184. bua Buriat
  2185. bug Buginese
  2186. bul Bulgarian
  2187. bur Burmese
  2188. cad Caddo
  2189. cai Central American Indian (Other)
  2190. car Carib
  2191. cat Catalan
  2192. cau Caucasian (Other)
  2193. ceb Cebuano
  2194. cel Celtic (Other)
  2195. ces Czech
  2196. cha Chamorro
  2197. chb Chibcha
  2198. che Chechen
  2199. chg Chagatai
  2200. chi Chinese
  2201. chm Mari
  2202. chn Chinook jargon
  2203. cho Choctaw
  2204. chr Cherokee
  2205. chu Church Slavic
  2206. chv Chuvash
  2207. chy Cheyenne
  2208. cop Coptic
  2209. cor Cornish
  2210. cos Corsican
  2211. cpe Creoles and Pidgins, English-based (Other)
  2212. cpf Creoles and Pidgins, French-based (Other)
  2213. cpp Creoles and Pidgins, Portuguese-based (Other)
  2214. cre Cree
  2215. crp Creoles and Pidgins (Other)
  2216. cus Cushitic (Other)
  2217. cym Welsh
  2218. cze Czech
  2219. dak Dakota
  2220. dan Danish
  2221. del Delaware
  2222. deu German
  2223. din Dinka
  2224. div Divehi
  2225. doi Dogri
  2226. dra Dravidian (Other)
  2227. dua Duala
  2228. dum Dutch, Middle (ca. 1050-1350)
  2229. dut Dutch
  2230. dyu Dyula
  2231. dzo Dzongkha
  2232. efi Efik
  2233. egy Egyptian (Ancient)
  2234. eka Ekajuk
  2235. ell Greek, Modern (1453-)
  2236. elx Elamite
  2237. eng English
  2238. enm English, Middle (ca. 1100-1500)
  2239. epo Esperanto
  2240. esk Eskimo (Other)
  2241. esl Spanish
  2242. est Estonian
  2243. eus Basque
  2244. ewe Ewe
  2245. ewo Ewondo
  2246. fan Fang
  2247. fao Faroese
  2248. fas Persian
  2249. fat Fanti
  2250. fij Fijian
  2251. fin Finnish
  2252. fiu Finno-Ugrian (Other)
  2253. fon Fon
  2254. fra French
  2255. fre French
  2256. frm French, Middle (ca. 1400-1600)
  2257. fro French, Old (842- ca. 1400)
  2258. fry Frisian
  2259. ful Fulah
  2260. gaa Ga
  2261. gae Gaelic (Scots)
  2262. gai Irish
  2263. gay Gayo
  2264. gdh Gaelic (Scots)
  2265. gem Germanic (Other)
  2266. geo Georgian
  2267. ger German
  2268. gez Geez
  2269. gil Gilbertese
  2270. glg Gallegan
  2271. gmh German, Middle High (ca. 1050-1500)
  2272. goh German, Old High (ca. 750-1050)
  2273. gon Gondi
  2274. got Gothic
  2275. grb Grebo
  2276. grc Greek, Ancient (to 1453)
  2277. gre Greek, Modern (1453-)
  2278. grn Guarani
  2279. guj Gujarati
  2280. hai Haida
  2281. hau Hausa
  2282. haw Hawaiian
  2283. heb Hebrew
  2284. her Herero
  2285. hil Hiligaynon
  2286. him Himachali
  2287. hin Hindi
  2288. hmo Hiri Motu
  2289. hun Hungarian
  2290. hup Hupa
  2291. hye Armenian
  2292. iba Iban
  2293. ibo Igbo
  2294. ice Icelandic
  2295. ijo Ijo
  2296. iku Inuktitut
  2297. ilo Iloko
  2298. ina Interlingua (International Auxiliary language Association)
  2299. inc Indic (Other)
  2300. ind Indonesian
  2301. ine Indo-European (Other)
  2302. ine Interlingue
  2303. ipk Inupiak
  2304. ira Iranian (Other)
  2305. iri Irish
  2306. iro Iroquoian uages
  2307. isl Icelandic
  2308. ita Italian
  2309. jav Javanese
  2310. jaw Javanese
  2311. jpn Japanese
  2312. jpr Judeo-Persian
  2313. jrb Judeo-Arabic
  2314. kaa Kara-Kalpak
  2315. kab Kabyle
  2316. kac Kachin
  2317. kal Greenlandic
  2318. kam Kamba
  2319. kan Kannada
  2320. kar Karen
  2321. kas Kashmiri
  2322. kat Georgian
  2323. kau Kanuri
  2324. kaw Kawi
  2325. kaz Kazakh
  2326. kha Khasi
  2327. khi Khoisan (Other)
  2328. khm Khmer
  2329. kho Khotanese
  2330. kik Kikuyu
  2331. kin Kinyarwanda
  2332. kir Kirghiz
  2333. kok Konkani
  2334. kom Komi
  2335. kon Kongo
  2336. kor Korean
  2337. kpe Kpelle
  2338. kro Kru
  2339. kru Kurukh
  2340. kua Kuanyama
  2341. kum Kumyk
  2342. kur Kurdish
  2343. kus Kusaie
  2344. kut Kutenai
  2345. lad Ladino
  2346. lah Lahnda
  2347. lam Lamba
  2348. lao Lao
  2349. lat Latin
  2350. lav Latvian
  2351. lez Lezghian
  2352. lin Lingala
  2353. lit Lithuanian
  2354. lol Mongo
  2355. loz Lozi
  2356. ltz Letzeburgesch
  2357. lub Luba-Katanga
  2358. lug Ganda
  2359. lui Luiseno
  2360. lun Lunda
  2361. luo Luo (Kenya and Tanzania)
  2362. mac Macedonian
  2363. mad Madurese
  2364. mag Magahi
  2365. mah Marshall
  2366. mai Maithili
  2367. mak Macedonian
  2368. mak Makasar
  2369. mal Malayalam
  2370. man Mandingo
  2371. mao Maori
  2372. map Austronesian (Other)
  2373. mar Marathi
  2374. mas Masai
  2375. max Manx
  2376. may Malay
  2377. men Mende
  2378. mga Irish, Middle (900 - 1200)
  2379. mic Micmac
  2380. min Minangkabau
  2381. mis Miscellaneous (Other)
  2382. mkh Mon-Kmer (Other)
  2383. mlg Malagasy
  2384. mlt Maltese
  2385. mni Manipuri
  2386. mno Manobo Languages
  2387. moh Mohawk
  2388. mol Moldavian
  2389. mon Mongolian
  2390. mos Mossi
  2391. mri Maori
  2392. msa Malay
  2393. mul Multiple Languages
  2394. mun Munda Languages
  2395. mus Creek
  2396. mwr Marwari
  2397. mya Burmese
  2398. myn Mayan Languages
  2399. nah Aztec
  2400. nai North American Indian (Other)
  2401. nau Nauru
  2402. nav Navajo
  2403. nbl Ndebele, South
  2404. nde Ndebele, North
  2405. ndo Ndongo
  2406. nep Nepali
  2407. new Newari
  2408. nic Niger-Kordofanian (Other)
  2409. niu Niuean
  2410. nla Dutch
  2411. nno Norwegian (Nynorsk)
  2412. non Norse, Old
  2413. nor Norwegian
  2414. nso Sotho, Northern
  2415. nub Nubian Languages
  2416. nya Nyanja
  2417. nym Nyamwezi
  2418. nyn Nyankole
  2419. nyo Nyoro
  2420. nzi Nzima
  2421. oci Langue d'Oc (post 1500)
  2422. oji Ojibwa
  2423. ori Oriya
  2424. orm Oromo
  2425. osa Osage
  2426. oss Ossetic
  2427. ota Turkish, Ottoman (1500 - 1928)
  2428. oto Otomian Languages
  2429. paa Papuan-Australian (Other)
  2430. pag Pangasinan
  2431. pal Pahlavi
  2432. pam Pampanga
  2433. pan Panjabi
  2434. pap Papiamento
  2435. pau Palauan
  2436. peo Persian, Old (ca 600 - 400 B.C.)
  2437. per Persian
  2438. phn Phoenician
  2439. pli Pali
  2440. pol Polish
  2441. pon Ponape
  2442. por Portuguese
  2443. pra Prakrit uages
  2444. pro Provencal, Old (to 1500)
  2445. pus Pushto
  2446. que Quechua
  2447. raj Rajasthani
  2448. rar Rarotongan
  2449. roa Romance (Other)
  2450. roh Rhaeto-Romance
  2451. rom Romany
  2452. ron Romanian
  2453. rum Romanian
  2454. run Rundi
  2455. rus Russian
  2456. sad Sandawe
  2457. sag Sango
  2458. sah Yakut
  2459. sai South American Indian (Other)
  2460. sal Salishan Languages
  2461. sam Samaritan Aramaic
  2462. san Sanskrit
  2463. sco Scots
  2464. scr Serbo-Croatian
  2465. sel Selkup
  2466. sem Semitic (Other)
  2467. sga Irish, Old (to 900)
  2468. shn Shan
  2469. sid Sidamo
  2470. sin Singhalese
  2471. sio Siouan Languages
  2472. sit Sino-Tibetan (Other)
  2473. sla Slavic (Other)
  2474. slk Slovak
  2475. slo Slovak
  2476. slv Slovenian
  2477. smi Sami Languages
  2478. smo Samoan
  2479. sna Shona
  2480. snd Sindhi
  2481. sog Sogdian
  2482. som Somali
  2483. son Songhai
  2484. sot Sotho, Southern
  2485. spa Spanish
  2486. sqi Albanian
  2487. srd Sardinian
  2488. srr Serer
  2489. ssa Nilo-Saharan (Other)
  2490. ssw Siswant
  2491. ssw Swazi
  2492. suk Sukuma
  2493. sun Sudanese
  2494. sus Susu
  2495. sux Sumerian
  2496. sve Swedish
  2497. swa Swahili
  2498. swe Swedish
  2499. syr Syriac
  2500. tah Tahitian
  2501. tam Tamil
  2502. tat Tatar
  2503. tel Telugu
  2504. tem Timne
  2505. ter Tereno
  2506. tgk Tajik
  2507. tgl Tagalog
  2508. tha Thai
  2509. tib Tibetan
  2510. tig Tigre
  2511. tir Tigrinya
  2512. tiv Tivi
  2513. tli Tlingit
  2514. tmh Tamashek
  2515. tog Tonga (Nyasa)
  2516. ton Tonga (Tonga Islands)
  2517. tru Truk
  2518. tsi Tsimshian
  2519. tsn Tswana
  2520. tso Tsonga
  2521. tuk Turkmen
  2522. tum Tumbuka
  2523. tur Turkish
  2524. tut Altaic (Other)
  2525. twi Twi
  2526. tyv Tuvinian
  2527. uga Ugaritic
  2528. uig Uighur
  2529. ukr Ukrainian
  2530. umb Umbundu
  2531. und Undetermined
  2532. urd Urdu
  2533. uzb Uzbek
  2534. vai Vai
  2535. ven Venda
  2536. vie Vietnamese
  2537. vol Volap�k
  2538. vot Votic
  2539. wak Wakashan Languages
  2540. wal Walamo
  2541. war Waray
  2542. was Washo
  2543. wel Welsh
  2544. wen Sorbian Languages
  2545. wol Wolof
  2546. xho Xhosa
  2547. yao Yao
  2548. yap Yap
  2549. yid Yiddish
  2550. yor Yoruba
  2551. zap Zapotec
  2552. zen Zenaga
  2553. zha Zhuang
  2554. zho Chinese
  2555. zul Zulu
  2556. zun Zuni
  2557. */
  2558. return getid3_lib :: EmbeddedLookup($languagecode, $begin, __LINE__, __FILE__, 'id3v2-languagecode');
  2559. }
  2560. function ETCOEventLookup($index)
  2561. {
  2562. if (($index >= 0x17) && ($index <= 0xDF))
  2563. {
  2564. return 'reserved for future use';
  2565. }
  2566. if (($index >= 0xE0) && ($index <= 0xEF))
  2567. {
  2568. return 'not predefined synch 0-F';
  2569. }
  2570. if (($index >= 0xF0) && ($index <= 0xFC))
  2571. {
  2572. return 'reserved for future use';
  2573. }
  2574. static $EventLookup = array(0x00 => 'padding (has no meaning)', 0x01 => 'end of initial silence',
  2575. 0x02 => 'intro start', 0x03 => 'main part start', 0x04 => 'outro start', 0x05 => 'outro end',
  2576. 0x06 => 'verse start', 0x07 => 'refrain start', 0x08 => 'interlude start', 0x09 => 'theme start',
  2577. 0x0A => 'variation start', 0x0B => 'key change', 0x0C => 'time change',
  2578. 0x0D => 'momentary unwanted noise (Snap, Crackle & Pop)', 0x0E => 'sustained noise',
  2579. 0x0F => 'sustained noise end', 0x10 => 'intro end', 0x11 => 'main part end', 0x12 => 'verse end',
  2580. 0x13 => 'refrain end', 0x14 => 'theme end', 0x15 => 'profanity', 0x16 => 'profanity end',
  2581. 0xFD => 'audio end (start of silence)', 0xFE => 'audio file ends',
  2582. 0xFF => 'one more byte of events follows');
  2583. return (isset($EventLookup[$index]) ? $EventLookup[$index] : '');
  2584. }
  2585. function SYTLContentTypeLookup($index)
  2586. {
  2587. static $SYTLContentTypeLookup = array(0x00 => 'other', 0x01 => 'lyrics', 0x02 => 'text transcription',
  2588. 0x03 => 'movement/part name', // (e.g. 'Adagio')
  2589. 0x04 => 'events', // (e.g. 'Don Quijote enters the stage')
  2590. 0x05 => 'chord', // (e.g. 'Bb F Fsus')
  2591. 0x06 => 'trivia/\'pop up\' information',
  2592. 0x07 => 'URLs to webpages', 0x08 => 'URLs to images');
  2593. return (isset($SYTLContentTypeLookup[$index]) ? $SYTLContentTypeLookup[$index] : '');
  2594. }
  2595. function APICPictureTypeLookup($index, $returnarray = false)
  2596. {
  2597. static $APICPictureTypeLookup = array(0x00 => 'Other', 0x01 => '32x32 pixels \'file icon\' (PNG only)',
  2598. 0x02 => 'Other file icon', 0x03 => 'Cover (front)', 0x04 => 'Cover (back)', 0x05 => 'Leaflet page',
  2599. 0x06 => 'Media (e.g. label side of CD)', 0x07 => 'Lead artist/lead performer/soloist',
  2600. 0x08 => 'Artist/performer', 0x09 => 'Conductor', 0x0A => 'Band/Orchestra', 0x0B => 'Composer',
  2601. 0x0C => 'Lyricist/text writer', 0x0D => 'Recording Location', 0x0E => 'During recording',
  2602. 0x0F => 'During performance', 0x10 => 'Movie/video screen capture', 0x11 => 'A bright coloured fish',
  2603. 0x12 => 'Illustration', 0x13 => 'Band/artist logotype', 0x14 => 'Publisher/Studio logotype');
  2604. if ($returnarray)
  2605. {
  2606. return $APICPictureTypeLookup;
  2607. }
  2608. return (isset($APICPictureTypeLookup[$index]) ? $APICPictureTypeLookup[$index] : '');
  2609. }
  2610. function COMRReceivedAsLookup($index)
  2611. {
  2612. static $COMRReceivedAsLookup = array(0x00 => 'Other', 0x01 => 'Standard CD album with other songs',
  2613. 0x02 => 'Compressed audio on CD', 0x03 => 'File over the Internet', 0x04 => 'Stream over the Internet',
  2614. 0x05 => 'As note sheets', 0x06 => 'As note sheets in a book with other sheets',
  2615. 0x07 => 'Music on other media', 0x08 => 'Non-musical merchandise');
  2616. return (isset($COMRReceivedAsLookup[$index]) ? $COMRReceivedAsLookup[$index] : '');
  2617. }
  2618. function RVA2ChannelTypeLookup($index)
  2619. {
  2620. static $RVA2ChannelTypeLookup = array(0x00 => 'Other', 0x01 => 'Master volume', 0x02 => 'Front right',
  2621. 0x03 => 'Front left', 0x04 => 'Back right', 0x05 => 'Back left', 0x06 => 'Front centre',
  2622. 0x07 => 'Back centre', 0x08 => 'Subwoofer');
  2623. return (isset($RVA2ChannelTypeLookup[$index]) ? $RVA2ChannelTypeLookup[$index] : '');
  2624. }
  2625. function FrameNameLongLookup($framename)
  2626. {
  2627. $begin = __LINE__;
  2628. /** This is not a comment!
  2629. AENC Audio encryption
  2630. APIC Attached picture
  2631. ASPI Audio seek point index
  2632. BUF Recommended buffer size
  2633. CNT Play counter
  2634. COM Comments
  2635. COMM Comments
  2636. COMR Commercial frame
  2637. CRA Audio encryption
  2638. CRM Encrypted meta frame
  2639. ENCR Encryption method registration
  2640. EQU Equalisation
  2641. EQU2 Equalisation (2)
  2642. EQUA Equalisation
  2643. ETC Event timing codes
  2644. ETCO Event timing codes
  2645. GEO General encapsulated object
  2646. GEOB General encapsulated object
  2647. GRID Group identification registration
  2648. IPL Involved people list
  2649. IPLS Involved people list
  2650. LINK Linked information
  2651. LNK Linked information
  2652. MCDI Music CD identifier
  2653. MCI Music CD Identifier
  2654. MLL MPEG location lookup table
  2655. MLLT MPEG location lookup table
  2656. OWNE Ownership frame
  2657. PCNT Play counter
  2658. PIC Attached picture
  2659. POP Popularimeter
  2660. POPM Popularimeter
  2661. POSS Position synchronisation frame
  2662. PRIV Private frame
  2663. RBUF Recommended buffer size
  2664. REV Reverb
  2665. RVA Relative volume adjustment
  2666. RVA2 Relative volume adjustment (2)
  2667. RVAD Relative volume adjustment
  2668. RVRB Reverb
  2669. SEEK Seek frame
  2670. SIGN Signature frame
  2671. SLT Synchronised lyric/text
  2672. STC Synced tempo codes
  2673. SYLT Synchronised lyric/text
  2674. SYTC Synchronised tempo codes
  2675. TAL Album/Movie/Show title
  2676. TALB Album/Movie/Show title
  2677. TBP BPM (Beats Per Minute)
  2678. TBPM BPM (beats per minute)
  2679. TCM Composer
  2680. TCO Content type
  2681. TCOM Composer
  2682. TCON Content type
  2683. TCOP Copyright message
  2684. TCR Copyright message
  2685. TDA Date
  2686. TDAT Date
  2687. TDEN Encoding time
  2688. TDLY Playlist delay
  2689. TDOR Original release time
  2690. TDRC Recording time
  2691. TDRL Release time
  2692. TDTG Tagging time
  2693. TDY Playlist delay
  2694. TEN Encoded by
  2695. TENC Encoded by
  2696. TEXT Lyricist/Text writer
  2697. TFLT File type
  2698. TFT File type
  2699. TIM Time
  2700. TIME Time
  2701. TIPL Involved people list
  2702. TIT1 Content group description
  2703. TIT2 Title/songname/content description
  2704. TIT3 Subtitle/Description refinement
  2705. TKE Initial key
  2706. TKEY Initial key
  2707. TLA Language(s)
  2708. TLAN Language(s)
  2709. TLE Length
  2710. TLEN Length
  2711. TMCL Musician credits list
  2712. TMED Media type
  2713. TMOO Mood
  2714. TMT Media type
  2715. TOA Original artist(s)/performer(s)
  2716. TOAL Original album/movie/show title
  2717. TOF Original filename
  2718. TOFN Original filename
  2719. TOL Original Lyricist(s)/text writer(s)
  2720. TOLY Original lyricist(s)/text writer(s)
  2721. TOPE Original artist(s)/performer(s)
  2722. TOR Original release year
  2723. TORY Original release year
  2724. TOT Original album/Movie/Show title
  2725. TOWN File owner/licensee
  2726. TP1 Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group
  2727. TP2 Band/Orchestra/Accompaniment
  2728. TP3 Conductor/Performer refinement
  2729. TP4 Interpreted, remixed, or otherwise modified by
  2730. TPA Part of a set
  2731. TPB Publisher
  2732. TPE1 Lead performer(s)/Soloist(s)
  2733. TPE2 Band/orchestra/accompaniment
  2734. TPE3 Conductor/performer refinement
  2735. TPE4 Interpreted, remixed, or otherwise modified by
  2736. TPOS Part of a set
  2737. TPRO Produced notice
  2738. TPUB Publisher
  2739. TRC ISRC (International Standard Recording Code)
  2740. TRCK Track number/Position in set
  2741. TRD Recording dates
  2742. TRDA Recording dates
  2743. TRK Track number/Position in set
  2744. TRSN Internet radio station name
  2745. TRSO Internet radio station owner
  2746. TSI Size
  2747. TSIZ Size
  2748. TSOA Album sort order
  2749. TSOP Performer sort order
  2750. TSOT Title sort order
  2751. TSRC ISRC (international standard recording code)
  2752. TSS Software/hardware and settings used for encoding
  2753. TSSE Software/Hardware and settings used for encoding
  2754. TSST Set subtitle
  2755. TT1 Content group description
  2756. TT2 Title/Songname/Content description
  2757. TT3 Subtitle/Description refinement
  2758. TXT Lyricist/text writer
  2759. TXX User defined text information frame
  2760. TXXX User defined text information frame
  2761. TYE Year
  2762. TYER Year
  2763. UFI Unique file identifier
  2764. UFID Unique file identifier
  2765. ULT Unsychronised lyric/text transcription
  2766. USER Terms of use
  2767. USLT Unsynchronised lyric/text transcription
  2768. WAF Official audio file webpage
  2769. WAR Official artist/performer webpage
  2770. WAS Official audio source webpage
  2771. WCM Commercial information
  2772. WCOM Commercial information
  2773. WCOP Copyright/Legal information
  2774. WCP Copyright/Legal information
  2775. WOAF Official audio file webpage
  2776. WOAR Official artist/performer webpage
  2777. WOAS Official audio source webpage
  2778. WORS Official Internet radio station homepage
  2779. WPAY Payment
  2780. WPB Publishers official webpage
  2781. WPUB Publishers official webpage
  2782. WXX User defined URL link frame
  2783. WXXX User defined URL link frame
  2784. TFEA Featured Artist
  2785. TSTU Recording Studio
  2786. rgad Replay Gain Adjustment
  2787. */
  2788. return getid3_lib :: EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_long');
  2789. // Last three:
  2790. // from Helium2 [www.helium2.com]
  2791. // from http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html
  2792. }
  2793. function FrameNameShortLookup($framename)
  2794. {
  2795. $begin = __LINE__;
  2796. /** This is not a comment!
  2797. AENC audio_encryption
  2798. APIC attached_picture
  2799. ASPI audio_seek_point_index
  2800. BUF recommended_buffer_size
  2801. CNT play_counter
  2802. COM comments
  2803. COMM comments
  2804. COMR commercial_frame
  2805. CRA audio_encryption
  2806. CRM encrypted_meta_frame
  2807. ENCR encryption_method_registration
  2808. EQU equalisation
  2809. EQU2 equalisation
  2810. EQUA equalisation
  2811. ETC event_timing_codes
  2812. ETCO event_timing_codes
  2813. GEO general_encapsulated_object
  2814. GEOB general_encapsulated_object
  2815. GRID group_identification_registration
  2816. IPL involved_people_list
  2817. IPLS involved_people_list
  2818. LINK linked_information
  2819. LNK linked_information
  2820. MCDI music_cd_identifier
  2821. MCI music_cd_identifier
  2822. MLL mpeg_location_lookup_table
  2823. MLLT mpeg_location_lookup_table
  2824. OWNE ownership_frame
  2825. PCNT play_counter
  2826. PIC attached_picture
  2827. POP popularimeter
  2828. POPM popularimeter
  2829. POSS position_synchronisation_frame
  2830. PRIV private_frame
  2831. RBUF recommended_buffer_size
  2832. REV reverb
  2833. RVA relative_volume_adjustment
  2834. RVA2 relative_volume_adjustment
  2835. RVAD relative_volume_adjustment
  2836. RVRB reverb
  2837. SEEK seek_frame
  2838. SIGN signature_frame
  2839. SLT synchronised_lyric
  2840. STC synced_tempo_codes
  2841. SYLT synchronised_lyric
  2842. SYTC synchronised_tempo_codes
  2843. TAL album
  2844. TALB album
  2845. TBP bpm
  2846. TBPM bpm
  2847. TCM composer
  2848. TCO content_type
  2849. TCOM composer
  2850. TCON content_type
  2851. TCOP copyright_message
  2852. TCR copyright_message
  2853. TDA date
  2854. TDAT date
  2855. TDEN encoding_time
  2856. TDLY playlist_delay
  2857. TDOR original_release_time
  2858. TDRC recording_time
  2859. TDRL release_time
  2860. TDTG tagging_time
  2861. TDY playlist_delay
  2862. TEN encoded_by
  2863. TENC encoded_by
  2864. TEXT lyricist
  2865. TFLT file_type
  2866. TFT file_type
  2867. TIM time
  2868. TIME time
  2869. TIPL involved_people_list
  2870. TIT1 content_group_description
  2871. TIT2 title
  2872. TIT3 subtitle
  2873. TKE initial_key
  2874. TKEY initial_key
  2875. TLA language
  2876. TLAN language
  2877. TLE length
  2878. TLEN length
  2879. TMCL musician_credits_list
  2880. TMED media_type
  2881. TMOO mood
  2882. TMT media_type
  2883. TOA original_artist
  2884. TOAL original_album
  2885. TOF original_filename
  2886. TOFN original_filename
  2887. TOL original_lyricist
  2888. TOLY original_lyricist
  2889. TOPE original_artist
  2890. TOR original_year
  2891. TORY original_year
  2892. TOT original_album
  2893. TOWN file_owner
  2894. TP1 artist
  2895. TP2 band
  2896. TP3 conductor
  2897. TP4 remixer
  2898. TPA part_of_a_set
  2899. TPB publisher
  2900. TPE1 artist
  2901. TPE2 band
  2902. TPE3 conductor
  2903. TPE4 remixer
  2904. TPOS part_of_a_set
  2905. TPRO produced_notice
  2906. TPUB publisher
  2907. TRC isrc
  2908. TRCK track_number
  2909. TRD recording_dates
  2910. TRDA recording_dates
  2911. TRK track_number
  2912. TRSN internet_radio_station_name
  2913. TRSO internet_radio_station_owner
  2914. TSI size
  2915. TSIZ size
  2916. TSOA album_sort_order
  2917. TSOP performer_sort_order
  2918. TSOT title_sort_order
  2919. TSRC isrc
  2920. TSS encoder_settings
  2921. TSSE encoder_settings
  2922. TSST set_subtitle
  2923. TT1 description
  2924. TT2 title
  2925. TT3 subtitle
  2926. TXT lyricist
  2927. TXX text
  2928. TXXX text
  2929. TYE year
  2930. TYER year
  2931. UFI unique_file_identifier
  2932. UFID unique_file_identifier
  2933. ULT unsychronised_lyric
  2934. USER terms_of_use
  2935. USLT unsynchronised_lyric
  2936. WAF url_file
  2937. WAR url_artist
  2938. WAS url_source
  2939. WCM commercial_information
  2940. WCOM commercial_information
  2941. WCOP copyright
  2942. WCP copyright
  2943. WOAF url_file
  2944. WOAR url_artist
  2945. WOAS url_source
  2946. WORS url_station
  2947. WPAY url_payment
  2948. WPB url_publisher
  2949. WPUB url_publisher
  2950. WXX url_user
  2951. WXXX url_user
  2952. TFEA featured_artist
  2953. TSTU recording_studio
  2954. rgad replay_gain_adjustment
  2955. */
  2956. return getid3_lib :: EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_short');
  2957. }
  2958. function TextEncodingTerminatorLookup($encoding)
  2959. {
  2960. // http://www.id3.org/id3v2.4.0-structure.txt
  2961. // Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings:
  2962. // $00 ISO-8859-1. Terminated with $00.
  2963. // $01 UTF-16 encoded Unicode with BOM. All strings in the same frame SHALL have the same byteorder. Terminated with $00 00.
  2964. // $02 UTF-16BE encoded Unicode without BOM. Terminated with $00 00.
  2965. // $03 UTF-8 encoded Unicode. Terminated with $00.
  2966. static $TextEncodingTerminatorLookup = array(0 => "\x00", 1 => "\x00\x00", 2 => "\x00\x00", 3 => "\x00",
  2967. 255 => "\x00\x00");
  2968. return @$TextEncodingTerminatorLookup[$encoding];
  2969. }
  2970. function TextEncodingNameLookup($encoding)
  2971. {
  2972. // http://www.id3.org/id3v2.4.0-structure.txt
  2973. static $TextEncodingNameLookup = array(0 => 'ISO-8859-1', 1 => 'UTF-16', 2 => 'UTF-16BE', 3 => 'UTF-8',
  2974. 255 => 'UTF-16BE');
  2975. return (isset($TextEncodingNameLookup[$encoding]) ? $TextEncodingNameLookup[$encoding] : 'ISO-8859-1');
  2976. }
  2977. function IsValidID3v2FrameName($framename, $id3v2majorversion)
  2978. {
  2979. switch ($id3v2majorversion)
  2980. {
  2981. case 2 :
  2982. return ereg('[A-Z][A-Z0-9]{2}', $framename);
  2983. break;
  2984. case 3 :
  2985. case 4 :
  2986. return ereg('[A-Z][A-Z0-9]{3}', $framename);
  2987. break;
  2988. }
  2989. return false;
  2990. }
  2991. function IsANumber($numberstring, $allowdecimal = false, $allownegative = false)
  2992. {
  2993. for($i = 0; $i < strlen($numberstring); $i ++)
  2994. {
  2995. if ((chr($numberstring{$i}) < chr('0')) || (chr($numberstring{$i}) > chr('9')))
  2996. {
  2997. if (($numberstring{$i} == '.') && $allowdecimal)
  2998. {
  2999. // allowed
  3000. }
  3001. elseif (($numberstring{$i} == '-') && $allownegative && ($i == 0))
  3002. {
  3003. // allowed
  3004. }
  3005. else
  3006. {
  3007. return false;
  3008. }
  3009. }
  3010. }
  3011. return true;
  3012. }
  3013. function IsValidDateStampString($datestamp)
  3014. {
  3015. if (strlen($datestamp) != 8)
  3016. {
  3017. return false;
  3018. }
  3019. if (! $this->IsANumber($datestamp, false))
  3020. {
  3021. return false;
  3022. }
  3023. $year = substr($datestamp, 0, 4);
  3024. $month = substr($datestamp, 4, 2);
  3025. $day = substr($datestamp, 6, 2);
  3026. if (($year == 0) || ($month == 0) || ($day == 0))
  3027. {
  3028. return false;
  3029. }
  3030. if ($month > 12)
  3031. {
  3032. return false;
  3033. }
  3034. if ($day > 31)
  3035. {
  3036. return false;
  3037. }
  3038. if (($day > 30) && (($month == 4) || ($month == 6) || ($month == 9) || ($month == 11)))
  3039. {
  3040. return false;
  3041. }
  3042. if (($day > 29) && ($month == 2))
  3043. {
  3044. return false;
  3045. }
  3046. return true;
  3047. }
  3048. function ID3v2HeaderLength($majorversion)
  3049. {
  3050. return (($majorversion == 2) ? 6 : 10);
  3051. }
  3052. }
  3053. ?>