Add support for ID3v2.3 unsynchronisation

git-svn-id: http://php-reader.googlecode.com/svn/branches/zend@155 51a70ab9-7547-0410-9469-37e369ee0574
This commit is contained in:
svollbehr
2009-05-31 08:07:58 +00:00
parent 44b19c9e37
commit 752c03858a
2 changed files with 51 additions and 22 deletions

View File

@@ -43,7 +43,6 @@ require_once 'Zend/Media/Id3/Header.php';
* unique and predefined identifier which allows software to skip unknown
* frames.
*
* @todo Unsynchronisation not supported for ID3v2.3 tag
* @category Zend
* @package Zend_Media
* @subpackage ID3
@@ -134,6 +133,9 @@ final class Zend_Media_Id3v2 extends Zend_Media_Id3_Object
}
$this->_header = new Zend_Media_Id3_Header($this->_reader, $options);
$tagSize = $this->_header->getSize();
if ($this->_header->getVersion() < 3 ||
$this->_header->getVersion() > 4) {
require_once 'Zend/Media/Id3/Exception.php';
@@ -142,9 +144,10 @@ final class Zend_Media_Id3v2 extends Zend_Media_Id3_Object
}
if ($this->_header->getVersion() < 4 &&
$this->_header->hasFlag(Zend_Media_Id3_Header::UNSYNCHRONISATION)) {
require_once 'Zend/Media/Id3/Exception.php';
throw new Zend_Media_Id3_Exception
('Unsynchronisation not yet supported for this version of ID3v2 tag');
$data = $this->_reader->read($this->_header->getSize());
$this->_reader = new Zend_Io_StringReader
($this->_decodeUnsynchronisation($data));
$tagSize = $this->_reader->getSize();
}
$this->clearOption('unsyncronisation');
if ($this->_header->hasFlag(Zend_Media_Id3_Header::UNSYNCHRONISATION)) {
@@ -164,7 +167,7 @@ final class Zend_Media_Id3v2 extends Zend_Media_Id3_Object
$offset = $this->_reader->getOffset();
// Jump off the loop if we reached the end of the tag
if ($offset - $startOffset - 10 >= $this->_header->getSize() -
if ($offset - $startOffset - 10 >= $tagSize -
($this->hasFooter() ? 10 : 0) - 10 /* header */) {
break;
}
@@ -517,16 +520,34 @@ final class Zend_Media_Id3v2 extends Zend_Media_Id3_Object
$frame->write($buffer);
}
}
$data = $buffer->toString();
$datalen = strlen($data);
$padlen = 0;
$frameData = $buffer->toString();
$frameDataLength = strlen($frameData);
$paddingLength = 0;
// ID3v2.4.0 supports frame level unsynchronisation. The corresponding
// option is set to true when any of the frames use the
// unsynchronisation scheme.
if ($this->getOption('unsyncronisation', false) === true) {
$this->_header->setFlags
($this->_header->getFlags() |
Zend_Media_Id3_Header::UNSYNCHRONISATION);
}
// ID3v2.3.0 supports only tag level unsynchronisation
if ($this->getOption('version', 4) < 4) {
$frameData = $this->_encodeUnsynchronisation($frameData);
if (($len = strlen($frameData)) != $frameDataLength) {
$frameDataLength = $len;
$this->_header->setFlags
($this->_header->getFlags() |
Zend_Media_Id3_Header::UNSYNCHRONISATION);
} else {
$this->_header->setFlags
($this->_header->getFlags() &
~Zend_Media_Id3_Header::UNSYNCHRONISATION);
}
}
// The tag padding is calculated as follows. If the tag can be written
// in the space of the previous tag, the remaining space is used for
// padding. If there is no previous tag or the new tag is bigger than
@@ -534,45 +555,49 @@ final class Zend_Media_Id3v2 extends Zend_Media_Id3_Object
// 4096 bytes.
if ($this->hasFooter() === false) {
if ($this->_reader !== null &&
$datalen < $this->_header->getSize()) {
$padlen = $this->_header->getSize() - $datalen;
$frameDataLength < $this->_header->getSize()) {
$paddingLength = $this->_header->getSize() - $frameDataLength;
} else {
$padlen = 4096;
$paddingLength = 4096;
}
}
/* ID3v2.4.0 CRC calculated w/ padding */
if ($this->getOption('version', 4) >= 4) {
$data = str_pad($data, $datalen + $padlen, "\0");
$frameData =
str_pad($frameData, $frameDataLength += $paddingLength, "\0");
}
$extendedHeaderData = '';
$extendedHeaderDataLength = 0;
if ($this->hasExtendedHeader()) {
$this->_extendedHeader->setPadding($padlen);
$this->_extendedHeader->setPadding($paddingLength);
if ($this->_extendedHeader->hasFlag
(Zend_Media_Id3_ExtendedHeader::CRC32)) {
$crc = crc32($data);
$crc = crc32($frameData);
if ($crc & 0x80000000) {
$crc = -(($crc ^ 0xffffffff) + 1);
}
$this->_extendedHeader->setCrc($crc);
}
$buffer = new Zend_Io_StringWriter();
$this->_extendedHeader->write($buffer);
$extendedHeaderData = $buffer->toString();
$extendedHeaderDataLength = strlen($extendedHeaderData);
}
/* ID3v2.3.0 CRC calculated w/o padding */
if ($this->getOption('version', 4) < 4) {
$data = str_pad($data, $datalen + $padlen, "\0");
$frameData =
str_pad($frameData, $frameDataLength += $paddingLength, "\0");
}
$this->_header->setSize(strlen($data));
$this->_header->setSize($extendedHeaderDataLength + $frameDataLength);
$writer->write('ID3');
$this->_header->write($writer);
if ($this->hasExtendedHeader()) {
$this->_extendedHeader->write($writer);
}
$writer->write($data);
$writer->write($extendedHeaderData);
$writer->write($frameData);
if ($this->hasFooter()) {
$writer->write('3DI');
$this->_footer->write($writer);