/** * Parse frame out from v2.3 and higher tags * * Frame ID $xx xx xx xx (four characters) * Size $xx xx xx xx (32-bit integer in v2.3, 28-bit synchsafe in v2.4+) * Flags $xx xx * * @param string $frameData */ protected function _getFrame($frameData) { $info = array(); // take next 10 bytes for header $info['frameHeader'] = substr($frameData, 0, 10); // and leave the rest in $frame_data $info['frameData'] = substr($frameData, 10); $info['frameName'] = substr($info['frameHeader'], 0, 4); $info['frameSize'] = $this->_tagVersion == 3 ? Zend_Id3_ByteConvert::bigEndian2Int(substr($info['frameHeader'], 4, 4)) : Zend_Id3_ByteConvert::bigEndianSyncSafe2Int(substr($info['frameHeader'], 4, 4)); if ($info['frameSize'] < strlen($frameData) + 4) { $arrBrokenMP3extFrames = array("" . 'MP3', "" . 'MP', ' MP3', 'MP3e'); $nextFrameID = substr($frameData, $info['frameSize'], 4); if ($this->_isValidID3v2FrameName($nextFrameID)) { // next frame is OK } else { if (in_array($info['frameName'], $arrBrokenMP3extFrames)) { // MP3ext known broken frames - "ok" for the purposes of this test } else { if ($this->_tagVersion == 4 && $this->_isValidID3v2FrameName(substr($info['frameData'], Zend_Id3_ByteConvert::bigEndian2Int(substr($info['frameHeader'], 4, 4)), 4), 3)) { $this->_tagVersion = 3; $info['frameSize'] = Zend_Id3_ByteConvert::bigEndian2Int(substr($info['frameHeader'], 4, 4)); // 32-bit integer } } } } $info['frameFlag'] = Zend_Id3_ByteConvert::bigEndian2Int(substr($info['frameHeader'], 8, 2)); // padding encountered if ($info['frameName'] == "") { return $this->_parsePadding($info['frameData'], $info['frameHeader']); } return $info; }
public static function littleEndian2Float($byte_word) { return Zend_Id3_ByteConvert::bigEndian2Float(strrev($byte_word)); }
/** * Parse the Frame Flags * * @return array * @throws Zend_Id3_Adapter_Id3v2_Frame_Exception */ private function _parseFrameFlags() { $flags = array(); switch ($this->_tagVersion) { /** * v2.3 Frame Header Flags * %abc00000 %ijk00000 */ case 3: $flags['TagAlterPreservation'] = (bool) ($this->_data['frame_flags_raw'] & 0x8000); // a - Tag alter preservation $flags['FileAlterPreservation'] = (bool) ($this->_data['frame_flags_raw'] & 0x4000); // b - File alter preservation $flags['ReadOnly'] = (bool) ($this->_data['frame_flags_raw'] & 0x2000); // c - Read only $flags['compression'] = (bool) ($this->_data['frame_flags_raw'] & 0x80); // i - Compression $flags['Encryption'] = (bool) ($this->_data['frame_flags_raw'] & 0x40); // j - Encryption $flags['GroupingIdentity'] = (bool) ($this->_data['frame_flags_raw'] & 0x20); // k - Grouping identity break; /** * v2.4 Frame Header Flags * %0abc0000 %0h00kmnp */ /** * v2.4 Frame Header Flags * %0abc0000 %0h00kmnp */ case 4: $flags['TagAlterPreservation'] = (bool) ($this->_data['frame_flags_raw'] & 0x4000); // a - Tag alter preservation $flags['FileAlterPreservation'] = (bool) ($this->_data['frame_flags_raw'] & 0x2000); // b - File alter preservation $flags['ReadOnly'] = (bool) ($this->_data['frame_flags_raw'] & 0x1000); // c - Read only $flags['GroupingIdentity'] = (bool) ($this->_data['frame_flags_raw'] & 0x40); // h - Grouping identity $flags['compression'] = (bool) ($this->_data['frame_flags_raw'] & 0x8); // k - Compression $flags['Encryption'] = (bool) ($this->_data['frame_flags_raw'] & 0x4); // m - Encryption $flags['Unsynchronisation'] = (bool) ($this->_data['frame_flags_raw'] & 0x2); // n - Unsynchronisation $flags['DataLengthIndicator'] = (bool) ($this->_data['frame_flags_raw'] & 0x1); // p - Data length indicator // Frame-level de-unsynchronisation - ID3v2.4 if ($flags['Unsynchronisation']) { $this->_data['data'] = str_replace("ÿ", "ÿ", $this->_data['data']); } break; } /** * Frame-Level de-compression */ if ($flags['compression']) { $this->_data['decompressed_size'] = Zend_Id3_ByteConvert::bigEndian2Int(substr($this->_data['data'], 0, 4)); if (!function_exists('gzuncompress')) { include_once 'Zend/Id3/Adapter/Id3v2/Frame/Exception.php'; throw new Zend_Id3_Adapter_Id3v2_Frame_Exception('gzuncompress() support required to decompress ID3v2 frame "' . $this->_data['frame_name'] . '"'); } elseif ($decompressed_data = @gzuncompress(substr($this->_data['data'], 4))) { $this->_data['data'] = $decompressed_data; } else { include_once 'Zend/Id3/Adapter/Id3v2/Frame/Exception.php'; throw new Zend_Id3_Adapter_Id3v2_Frame_Exception('gzuncompress() failed on compressed contents of ID3v2 frame "' . $this->_data['frame_name'] . '"'); } } return $flags; }
/** * */ protected function _proccessExtendedFrameHeader($frameData) { $extendedHeaderOffset = 0; switch ($this->_tagMajorVersion) { /** * v2.3 definition: * * Extended header size $xx xx xx xx // 32-bit integer * Extended Flags $xx xx * %x0000000 %00000000 // v2.3 * x - CRC data present * Size of padding $xx xx xx xx */ case 3: $this->_tagInfo['id3v2']['exthead']['length'] = Zend_Id3_ByteConvert::bigEndian2Int(substr($frameData, $extendedHeaderOffset, 4), 0); $extendedHeaderOffset += 4; $this->_tagInfo['id3v2']['exthead']['flag_bytes'] = 2; $this->_tagInfo['id3v2']['exthead']['flag_raw'] = Zend_Id3_ByteConvert::bigEndian2Int(substr($frameData, $extendedHeaderOffset, $this->_tagInfo['id3v2']['exthead']['flag_bytes'])); $extendedHeaderOffset += $this->_tagInfo['id3v2']['exthead']['flag_bytes']; $this->_tagInfo['id3v2']['exthead']['flags']['crc'] = (bool) ($this->_tagInfo['id3v2']['exthead']['flag_raw'] & 0x8000); $this->_tagInfo['id3v2']['exthead']['padding_size'] = Zend_Id3_ByteConvert::bigEndian2Int(substr($frameData, $extendedHeaderOffset, 4)); $extendedHeaderOffset += 4; if ($this->_tagInfo['id3v2']['exthead']['flags']['crc']) { $this->_tagInfo['id3v2']['exthead']['flag_data']['crc'] = Zend_Id3_ByteConvert::bigEndian2Int(substr($frameData, $extendedHeaderOffset, 4)); $extendedHeaderOffset += 4; } $extendedHeaderOffset += $this->_tagInfo['id3v2']['exthead']['padding_size']; break; /** * v2.4 definition: * * Extended header size 4 * %0xxxxxxx * 28-bit synchsafe integer * Number of flag bytes $01 * Extended Flags $xx * %0bcd0000 * v2.4 * b - Tag is an update * Flag data length $00 * c - CRC data present * Flag data length $05 * Total frame CRC 5 * %0xxxxxxx * d - Tag restrictions * Flag data length $01 */ /** * v2.4 definition: * * Extended header size 4 * %0xxxxxxx * 28-bit synchsafe integer * Number of flag bytes $01 * Extended Flags $xx * %0bcd0000 * v2.4 * b - Tag is an update * Flag data length $00 * c - CRC data present * Flag data length $05 * Total frame CRC 5 * %0xxxxxxx * d - Tag restrictions * Flag data length $01 */ case 4: $this->_tagInfo['id3v2']['exthead']['length'] = Zend_Id3_ByteConvert::bigEndian2Int(substr($frameData, $extendedHeaderOffset, 4), 1); $extendedHeaderOffset += 4; $this->_tagInfo['id3v2']['exthead']['flag_bytes'] = 1; $this->_tagInfo['id3v2']['exthead']['flag_raw'] = Zend_Id3_ByteConvert::bigEndian2Int(substr($frameData, $extendedHeaderOffset, $this->_tagInfo['id3v2']['exthead']['flag_bytes'])); $extendedHeaderOffset += $this->_tagInfo['id3v2']['exthead']['flag_bytes']; $this->_tagInfo['id3v2']['exthead']['flags']['update'] = (bool) ($this->_tagInfo['id3v2']['exthead']['flag_raw'] & 0x4000); $this->_tagInfo['id3v2']['exthead']['flags']['crc'] = (bool) ($this->_tagInfo['id3v2']['exthead']['flag_raw'] & 0x2000); $this->_tagInfo['id3v2']['exthead']['flags']['restrictions'] = (bool) ($this->_tagInfo['id3v2']['exthead']['flag_raw'] & 0x1000); if ($this->_tagInfo['id3v2']['exthead']['flags']['crc']) { $this->_tagInfo['id3v2']['exthead']['flag_data']['crc'] = Zend_Id3_ByteConvert::bigEndian2Int(substr($frameData, $extendedHeaderOffset, 5), 1); $extendedHeaderOffset += 5; } if ($this->_tagInfo['id3v2']['exthead']['flags']['restrictions']) { // %ppqrrstt $restrictionsByte = Zend_Id3_ByteConvert::bigEndian2Int(substr($frameData, $extendedHeaderOffset, 1)); $extendedHeaderOffset += 1; $this->_tagInfo['id3v2']['exthead']['flags']['restrictions']['tagsize'] = ($restrictionsByte && 0xc0) >> 6; // p - Tag size restrictions $this->_tagInfo['id3v2']['exthead']['flags']['restrictions']['textenc'] = ($restrictionsByte && 0x20) >> 5; // q - Text encoding restrictions $this->_tagInfo['id3v2']['exthead']['flags']['restrictions']['textsize'] = ($restrictionsByte && 0x18) >> 3; // r - Text fields size restrictions $this->_tagInfo['id3v2']['exthead']['flags']['restrictions']['imgenc'] = ($restrictionsByte && 0x4) >> 2; // s - Image encoding restrictions $this->_tagInfo['id3v2']['exthead']['flags']['restrictions']['imgsize'] = ($restrictionsByte && 0x3) >> 0; // t - Image size restrictions } break; } $this->_frameDataOffset += $extendedHeaderOffset; $frameData = substr($frameData, $extendedHeaderOffset); return $frameData; }