PageRenderTime 53ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 1ms

/mc_podcast/getid3/module.tag.id3v2.php

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