/** * Constructs the class with given parameters and reads object related data * from the ID3v2 tag. * * @param HausDesign_Io_Reader $reader The reader object. * @param Array $options The options array. */ public function __construct($reader = null, &$options = array()) { parent::__construct($reader, $options); if ($reader === null) { return; } $this->_version = $options['version'] = $this->_reader->readUInt8() + $this->_reader->readUInt8() / 10; $this->_flags = $this->_reader->readUInt8(); $this->_size = $this->_decodeSynchsafe32($this->_reader->readUInt32BE()); }
/** * Constructs the HausDesign_Media_Id3v2 class with given file and options. The * options array may also be given as the only parameter. * * The following options are currently recognized: * o encoding -- Indicates the encoding that all the texts are presented * with. See the documentation of iconv for supported values. Please * note that write operations do not convert string and thus encodings * are limited to those supported by the {@link HausDesign_Media_Id3_Encoding} * interface. * o version -- The ID3v2 tag version to use in write operation. This * option is automatically set when a tag is read from a file and * defaults to version 4.0 for tag write. * o compat -- Normally unsynchronization is handled automatically behind * the scenes. However, current versions of Windows operating system and * Windows Media Player, just to name a few, do not support ID3v2.4 tags * nor ID3v2.3 tags with unsynchronization. Hence, for compatibility * reasons, this option is made available to disable automatic tag level * unsynchronization scheme that version 3.0 supports. * o readonly -- Indicates that the tag is read from a temporary file or * another source it cannot be written back to. The tag can, however, * still be written to another file. * * @todo Only limited subset of flags are processed. * @todo Utilize the SEEK frame and search for a footer to find the tag * @todo Utilize the LINK frame to fetch frames from other sources * @param string|resource|HausDesign_Io_Reader $filename The path to the file, * file descriptor of an opened file, or a {@link HausDesign_Io_Reader} instance. * @param Array $options The options array. * @throws HausDesign_Media_Id3_Exception if given file descriptor is not valid */ public function __construct($filename = null, $options = array()) { parent::__construct(null, $options); if (is_array($filename)) { $options = $filename; $filename = null; } if ($filename === null) { $this->_header = new HausDesign_Media_Id3_Header(null, $options); return; } if ($filename instanceof HausDesign_Io_Reader) { $this->_reader =& $filename; } else { require_once 'HausDesign/Io/FileReader.php'; try { $this->_reader = new HausDesign_Io_FileReader($filename); } catch (HausDesign_Io_Exception $e) { $this->_reader = null; require_once 'HausDesign/Media/Id3/Exception.php'; throw new HausDesign_Media_Id3_Exception($e->getMessage()); } if (is_string($filename) && !isset($options['readonly'])) { $this->_filename = $filename; } } $startOffset = $this->_reader->getOffset(); if ($this->_reader->read(3) != 'ID3') { require_once 'HausDesign/Media/Id3/Exception.php'; throw new HausDesign_Media_Id3_Exception('File does not contain ID3v2 tag'); } $this->_header = new HausDesign_Media_Id3_Header($this->_reader, $options); $tagSize = $this->_header->getSize(); if ($this->_header->getVersion() < 3 || $this->_header->getVersion() > 4) { require_once 'HausDesign/Media/Id3/Exception.php'; throw new HausDesign_Media_Id3_Exception('File does not contain ID3v2 tag of supported version: v2.' . $this->_header->getVersion()); } if ($this->_header->getVersion() < 4 && $this->_header->hasFlag(HausDesign_Media_Id3_Header::UNSYNCHRONISATION)) { $data = $this->_reader->read($this->_header->getSize()); require_once 'HausDesign/Io/StringReader.php'; $this->_reader = new HausDesign_Io_StringReader($this->_decodeUnsynchronisation($data)); $tagSize = $this->_reader->getSize(); } $this->clearOption('unsynchronisation'); if ($this->_header->hasFlag(HausDesign_Media_Id3_Header::UNSYNCHRONISATION)) { $this->setOption('unsynchronisation', true); } if ($this->_header->hasFlag(HausDesign_Media_Id3_Header::EXTENDED_HEADER)) { require_once 'HausDesign/Media/Id3/ExtendedHeader.php'; $this->_extendedHeader = new HausDesign_Media_Id3_ExtendedHeader($this->_reader, $options); } if ($this->_header->hasFlag(HausDesign_Media_Id3_Header::FOOTER)) { // skip footer, and rather copy header $this->_footer =& $this->_header; } while (true) { $offset = $this->_reader->getOffset(); // Jump off the loop if we reached the end of the tag if ($offset - $startOffset - 10 >= $tagSize - ($this->hasFooter() ? 10 : 0) - 10) { break; } // Jump off the loop if we reached padding if (ord($identifier = $this->_reader->read(1)) === 0) { break; } $identifier .= $this->_reader->read(3); // Jump off the loop if we reached invalid entities. This fix is // just to make things work. Utility called MP3ext does not seem // to know what it is doing as it uses padding to write its // version information there. if ($identifier == 'MP3e') { break; } $this->_reader->setOffset($offset); if (@fopen($file = 'HausDesign/Media/Id3/Frame/' . ucfirst(strtolower($identifier)) . '.php', 'r', true) !== false) { require_once $file; } if (class_exists($classname = 'HausDesign_Media_Id3_Frame_' . ucfirst(strtolower($identifier)))) { $frame = new $classname($this->_reader, $options); } else { require_once 'HausDesign/Media/Id3/Frame/Unknown.php'; $frame = new HausDesign_Media_Id3_Frame_Unknown($this->_reader, $options); } if (!isset($this->_frames[$frame->getIdentifier()])) { $this->_frames[$frame->getIdentifier()] = array(); } $this->_frames[$frame->getIdentifier()][] = $frame; } }
/** * Constructs the class with given parameters and reads object related data * from the ID3v2 tag. * * @param HausDesign_Io_Reader $reader The reader object. * @param Array $options The options array. */ public function __construct($reader = null, &$options = array()) { parent::__construct($reader, $options); if ($reader === null) { return; } $offset = $this->_reader->getOffset(); $this->_size = $this->_reader->readUInt32BE(); /* ID3v2.3.0 ExtendedHeader */ if ($this->getOption('version', 4) < 4) { if ($this->_reader->readUInt16BE() == 0x8000) { $this->_flags = self::CRC32; } $this->_padding = $this->_reader->readUInt32BE(); if ($this->hasFlag(self::CRC32)) { $this->_crc = $this->_reader->readUInt32BE(); } } else { $this->_size = $this->_decodeSynchsafe32($this->_size); $this->_reader->skip(1); $this->_flags = $this->_reader->readInt8(); if ($this->hasFlag(self::UPDATE)) { $this->_reader->skip(1); } if ($this->hasFlag(self::CRC32)) { $this->_reader->skip(1); $this->_crc = $this->_reader->readInt8() * (0xfffffff + 1) + $this->_decodeSynchsafe32($this->_reader->readUInt32BE()); } if ($this->hasFlag(self::RESTRICTED)) { $this->_reader->skip(1); $this->_restrictions = $this->_reader->readInt8(); } } }
/** * Constructs the class with given parameters and reads object related data * from the ID3v2 tag. * * Replaces the reader instance with a string reader object instance that * can be used to further process the data in the frame sub class. * * @todo Only limited subset of flags are processed. * @param HausDesign_Io_Reader $reader The reader object. * @param Array $options The options array. */ public function __construct($reader = null, &$options = array()) { parent::__construct($reader, $options); if ($reader === null) { $this->_identifier = strtoupper(substr(get_class($this), -4)); } else { $this->_identifier = strtoupper($this->_reader->readString8(4, " ")); /* ID3v2.3.0 size and flags; convert flags to 2.4.0 format */ if ($this->getOption('version', 4) < 4) { $this->_size = $this->_reader->readUInt32BE(); $flags = $this->_reader->readUInt16BE(); if (($flags & 0x8000) == 0x8000) { $this->_flags |= self::DISCARD_ON_TAGCHANGE; } if (($flags & 0x4000) == 0x4000) { $this->_flags |= self::DISCARD_ON_FILECHANGE; } if (($flags & 0x2000) == 0x2000) { $this->_flags |= self::READ_ONLY; } if (($flags & 0x80) == 0x80) { $this->_flags |= self::COMPRESSION; } if (($flags & 0x40) == 0x40) { $this->_flags |= self::ENCRYPTION; } if (($flags & 0x20) == 0x20) { $this->_flags |= self::GROUPING_IDENTITY; } } else { $this->_size = $this->_decodeSynchsafe32($this->_reader->readUInt32BE()); $this->_flags = $this->_reader->readUInt16BE(); } $dataLength = $this->_size; if ($this->hasFlag(self::DATA_LENGTH_INDICATOR)) { $dataLength = $this->_decodeSynchsafe32($this->_reader->readUInt32BE()); $this->_size -= 4; } $data = $this->_reader->read($this->_size); $this->_size = $dataLength; if ($this->hasFlag(self::UNSYNCHRONISATION) || $this->getOption('unsynchronisation', false) === true) { $data = $this->_decodeUnsynchronisation($data); } $this->_reader = new HausDesign_Io_StringReader($data); } }