PageRenderTime 32ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/blog/wp-content/plugins/podpress/getid3/module.tag.id3v2.php

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