summaryrefslogtreecommitdiffstats
path: root/modules/id3/getid3
diff options
context:
space:
mode:
Diffstat (limited to 'modules/id3/getid3')
-rw-r--r--modules/id3/getid3/getid3.php140
-rw-r--r--modules/id3/getid3/module.audio-video.asf.php9
-rw-r--r--modules/id3/getid3/module.audio-video.flv.php210
-rw-r--r--modules/id3/getid3/module.audio-video.riff.php4
-rw-r--r--modules/id3/getid3/module.audio.mp3.php33
-rw-r--r--modules/id3/getid3/module.tag.id3v2.php88
-rw-r--r--modules/id3/getid3/write.id3v2.php1
-rw-r--r--modules/id3/getid3/write.php8
-rw-r--r--modules/id3/getid3/write.real.php251
9 files changed, 568 insertions, 176 deletions
diff --git a/modules/id3/getid3/getid3.php b/modules/id3/getid3/getid3.php
index e87fcfb6..d0a8d479 100644
--- a/modules/id3/getid3/getid3.php
+++ b/modules/id3/getid3/getid3.php
@@ -10,7 +10,7 @@
/////////////////////////////////////////////////////////////////
// Defines
-define('GETID3_VERSION', '1.7.4');
+define('GETID3_VERSION', '1.7.5-200512251515');
define('GETID3_FREAD_BUFFER_SIZE', 16384); // read buffer size in bytes
@@ -111,26 +111,40 @@ class getID3
// ie for "C:/Program Files/Apache/" put "C:/PROGRA~1/APACHE/"
// IMPORTANT: This path must include the trailing slash
if (GETID3_OS_ISWINDOWS && !defined('GETID3_HELPERAPPSDIR')) {
-
$helperappsdir = GETID3_INCLUDEPATH.'..'.GETID3_OS_DIRSLASH.'helperapps'; // must not have any space in this path
if (!is_dir($helperappsdir)) {
+
$this->startup_error .= '"'.$helperappsdir.'" cannot be defined as GETID3_HELPERAPPSDIR because it does not exist';
+
} elseif (strpos(realpath($helperappsdir), ' ') !== false) {
+
$DirPieces = explode(GETID3_OS_DIRSLASH, realpath($helperappsdir));
- foreach ($DirPieces as $key => $value) {
- if ((strpos($value, '.') !== false) && (strpos($value, ' ') === false)) {
- if (strpos($value, '.') > 8) {
- $value = substr($value, 0, 6).'~1';
- }
- } elseif ((strpos($value, ' ') !== false) || strlen($value) > 8) {
- $value = substr($value, 0, 6).'~1';
- }
- $DirPieces[$key] = strtoupper($value);
- }
- $this->startup_error .= 'GETID3_HELPERAPPSDIR must not have any spaces in it - use 8dot3 naming convention if neccesary (on this server that would be something like "'.implode(GETID3_OS_DIRSLASH, $DirPieces).'" - NOTE: this may or may not be the actual 8.3 equivalent of "'.$helperappsdir.'", please double-check). You can run "dir /x" from the commandline to see the correct 8.3-style names. You need to edit the file "'.GETID3_INCLUDEPATH.'/getid3.php" around line '.(__LINE__ - 16);
+ $DirPieces8 = $DirPieces;
+
+ $CLIdir = $DirPieces[0].' && cd \\';
+ for ($i = 1; $i < count($DirPieces); $i++) {
+ if (strpos($DirPieces[$i], ' ') === false) {
+ $CLIdir .= ' && cd '.$DirPieces[$i];
+ } else {
+ ob_start();
+ system($CLIdir.' && dir /ad /x');
+ $subdirsraw = explode("\n", ob_get_contents());
+ ob_end_clean();
+ foreach ($subdirsraw as $line) {
+ if (eregi('^[0-9]{4}/[0-9]{2}/[0-9]{2} [0-9]{2}:[0-9]{2} [AP]M <DIR> ([^ ]{8}) '.preg_quote($DirPieces[$i]).'$', trim($line), $matches)) {
+ $CLIdir .= ' && cd '.$matches[1];
+ break;
+ }
+ }
+ $DirPieces8[$i] = $matches[1];
+ }
+ }
+ $helperappsdir = implode(GETID3_OS_DIRSLASH, $DirPieces8);
+
}
define('GETID3_HELPERAPPSDIR', realpath($helperappsdir).GETID3_OS_DIRSLASH);
+
}
}
@@ -436,7 +450,7 @@ class getID3
'group' => 'audio',
'module' => 'ac3',
'mime_type' => 'audio/ac3',
- ),
+ ),
// AAC - audio - Advanced Audio Coding (AAC) - ADIF format
'adif' => array(
@@ -446,7 +460,7 @@ class getID3
'option' => 'adif',
'mime_type' => 'application/octet-stream',
'fail_ape' => 'WARNING',
- ),
+ ),
// AAC - audio - Advanced Audio Coding (AAC) - ADTS format (very similar to MP3)
@@ -457,7 +471,7 @@ class getID3
'option' => 'adts',
'mime_type' => 'application/octet-stream',
'fail_ape' => 'WARNING',
- ),
+ ),
// AU - audio - NeXT/Sun AUdio (AU)
@@ -466,7 +480,7 @@ class getID3
'group' => 'audio',
'module' => 'au',
'mime_type' => 'audio/basic',
- ),
+ ),
// AVR - audio - Audio Visual Research
'avr' => array(
@@ -474,7 +488,7 @@ class getID3
'group' => 'audio',
'module' => 'avr',
'mime_type' => 'application/octet-stream',
- ),
+ ),
// BONK - audio - Bonk v0.9+
'bonk' => array(
@@ -482,7 +496,7 @@ class getID3
'group' => 'audio',
'module' => 'bonk',
'mime_type' => 'audio/xmms-bonk',
- ),
+ ),
// FLAC - audio - Free Lossless Audio Codec
'flac' => array(
@@ -490,7 +504,7 @@ class getID3
'group' => 'audio',
'module' => 'flac',
'mime_type' => 'audio/x-flac',
- ),
+ ),
// LA - audio - Lossless Audio (LA)
'la' => array(
@@ -498,7 +512,7 @@ class getID3
'group' => 'audio',
'module' => 'la',
'mime_type' => 'application/octet-stream',
- ),
+ ),
// LPAC - audio - Lossless Predictive Audio Compression (LPAC)
'lpac' => array(
@@ -506,7 +520,7 @@ class getID3
'group' => 'audio',
'module' => 'lpac',
'mime_type' => 'application/octet-stream',
- ),
+ ),
// MIDI - audio - MIDI (Musical Instrument Digital Interface)
'midi' => array(
@@ -514,7 +528,7 @@ class getID3
'group' => 'audio',
'module' => 'midi',
'mime_type' => 'audio/midi',
- ),
+ ),
// MAC - audio - Monkey's Audio Compressor
'mac' => array(
@@ -522,7 +536,7 @@ class getID3
'group' => 'audio',
'module' => 'monkey',
'mime_type' => 'application/octet-stream',
- ),
+ ),
// MOD - audio - MODule (assorted sub-formats)
'mod' => array(
@@ -531,7 +545,7 @@ class getID3
'module' => 'mod',
'option' => 'mod',
'mime_type' => 'audio/mod',
- ),
+ ),
// MOD - audio - MODule (Impulse Tracker)
'it' => array(
@@ -540,7 +554,7 @@ class getID3
'module' => 'mod',
'option' => 'it',
'mime_type' => 'audio/it',
- ),
+ ),
// MOD - audio - MODule (eXtended Module, various sub-formats)
'xm' => array(
@@ -549,7 +563,7 @@ class getID3
'module' => 'mod',
'option' => 'xm',
'mime_type' => 'audio/xm',
- ),
+ ),
// MOD - audio - MODule (ScreamTracker)
's3m' => array(
@@ -558,7 +572,7 @@ class getID3
'module' => 'mod',
'option' => 's3m',
'mime_type' => 'audio/s3m',
- ),
+ ),
// MPC - audio - Musepack / MPEGplus
'mpc' => array(
@@ -566,7 +580,7 @@ class getID3
'group' => 'audio',
'module' => 'mpc',
'mime_type' => 'application/octet-stream',
- ),
+ ),
// MP3 - audio - MPEG-audio Layer 3 (very similar to AAC-ADTS)
'mp3' => array(
@@ -574,7 +588,7 @@ class getID3
'group' => 'audio',
'module' => 'mp3',
'mime_type' => 'audio/mpeg',
- ),
+ ),
// OFR - audio - OptimFROG
'ofr' => array(
@@ -582,7 +596,7 @@ class getID3
'group' => 'audio',
'module' => 'optimfrog',
'mime_type' => 'application/octet-stream',
- ),
+ ),
// RKAU - audio - RKive AUdio compressor
'rkau' => array(
@@ -590,7 +604,7 @@ class getID3
'group' => 'audio',
'module' => 'rkau',
'mime_type' => 'application/octet-stream',
- ),
+ ),
// SHN - audio - Shorten
'shn' => array(
@@ -600,7 +614,7 @@ class getID3
'mime_type' => 'audio/xmms-shn',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
- ),
+ ),
// TTA - audio - TTA Lossless Audio Compressor (http://tta.corecodec.org)
'tta' => array(
@@ -608,7 +622,7 @@ class getID3
'group' => 'audio',
'module' => 'tta',
'mime_type' => 'application/octet-stream',
- ),
+ ),
// VOC - audio - Creative Voice (VOC)
'voc' => array(
@@ -616,7 +630,7 @@ class getID3
'group' => 'audio',
'module' => 'voc',
'mime_type' => 'audio/voc',
- ),
+ ),
// VQF - audio - transform-domain weighted interleave Vector Quantization Format (VQF)
'vqf' => array(
@@ -624,7 +638,7 @@ class getID3
'group' => 'audio',
'module' => 'vqf',
'mime_type' => 'application/octet-stream',
- ),
+ ),
// WV - audio - WavPack (v4.0+)
'wv' => array(
@@ -632,7 +646,7 @@ class getID3
'group' => 'audio',
'module' => 'wavpack',
'mime_type' => 'application/octet-stream',
- ),
+ ),
// Audio-Video formats
@@ -644,15 +658,23 @@ class getID3
'module' => 'asf',
'mime_type' => 'video/x-ms-asf',
'iconv_req' => false,
- ),
+ ),
- // BINK - audio/video - Bink / Smacker
+ // BINK - audio/video - Bink / Smacker
'bink' => array(
'pattern' => '^(BIK|SMK)',
'group' => 'audio-video',
'module' => 'bink',
'mime_type' => 'application/octet-stream',
- ),
+ ),
+
+ // FLV - audio/video - FLash Video
+ 'flv' => array(
+ 'pattern' => '^FLV\x01',
+ 'group' => 'audio-video',
+ 'module' => 'flv',
+ 'mime_type' => 'video/x-flv',
+ ),
// MKAV - audio/video - Mastroka
'matroska' => array(
@@ -660,7 +682,7 @@ class getID3
'group' => 'audio-video',
'module' => 'matroska',
'mime_type' => 'application/octet-stream',
- ),
+ ),
// MPEG - audio/video - MPEG (Moving Pictures Experts Group)
'mpeg' => array(
@@ -668,7 +690,7 @@ class getID3
'group' => 'audio-video',
'module' => 'mpeg',
'mime_type' => 'video/mpeg',
- ),
+ ),
// NSV - audio/video - Nullsoft Streaming Video (NSV)
'nsv' => array(
@@ -676,7 +698,7 @@ class getID3
'group' => 'audio-video',
'module' => 'nsv',
'mime_type' => 'application/octet-stream',
- ),
+ ),
// Ogg - audio/video - Ogg (Ogg-Vorbis, Ogg-FLAC, Speex, Ogg-Theora(*), Ogg-Tarkin(*))
'ogg' => array(
@@ -686,7 +708,7 @@ class getID3
'mime_type' => 'application/ogg',
'fail_id3' => 'WARNING',
'fail_ape' => 'WARNING',
- ),
+ ),
// QT - audio/video - Quicktime
'quicktime' => array(
@@ -694,7 +716,7 @@ class getID3
'group' => 'audio-video',
'module' => 'quicktime',
'mime_type' => 'video/quicktime',
- ),
+ ),
// RIFF - audio/video - Resource Interchange File Format (RIFF) / WAV / AVI / CD-audio / SDSS = renamed variant used by SmartSound QuickTracks (www.smartsound.com) / FORM = Audio Interchange File Format (AIFF)
'riff' => array(
@@ -703,7 +725,7 @@ class getID3
'module' => 'riff',
'mime_type' => 'audio/x-wave',
'fail_ape' => 'WARNING',
- ),
+ ),
// Real - audio/video - RealAudio, RealVideo
'real' => array(
@@ -711,7 +733,7 @@ class getID3
'group' => 'audio-video',
'module' => 'real',
'mime_type' => 'audio/x-realaudio',
- ),
+ ),
// SWF - audio/video - ShockWave Flash
'swf' => array(
@@ -719,7 +741,7 @@ class getID3
'group' => 'audio-video',
'module' => 'swf',
'mime_type' => 'application/x-shockwave-flash',
- ),
+ ),
// Still-Image formats
@@ -732,7 +754,7 @@ class getID3
'mime_type' => 'image/bmp',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
- ),
+ ),
// GIF - still image - Graphics Interchange Format
'gif' => array(
@@ -742,7 +764,7 @@ class getID3
'mime_type' => 'image/gif',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
- ),
+ ),
// JPEG - still image - Joint Photographic Experts Group (JPEG)
'jpg' => array(
@@ -752,7 +774,7 @@ class getID3
'mime_type' => 'image/jpeg',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
- ),
+ ),
// PCD - still image - Kodak Photo CD
'pcd' => array(
@@ -762,7 +784,7 @@ class getID3
'mime_type' => 'image/x-photo-cd',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
- ),
+ ),
// PNG - still image - Portable Network Graphics (PNG)
@@ -773,7 +795,7 @@ class getID3
'mime_type' => 'image/png',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
- ),
+ ),
// TIFF - still image - Tagged Information File Format (TIFF)
@@ -784,7 +806,7 @@ class getID3
'mime_type' => 'image/tiff',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
- ),
+ ),
// Data formats
@@ -798,7 +820,7 @@ class getID3
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
'iconv_req' => false,
- ),
+ ),
// RAR - data - RAR compressed data
'rar' => array(
@@ -808,7 +830,7 @@ class getID3
'mime_type' => 'application/octet-stream',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
- ),
+ ),
// SZIP - audio - SZIP compressed data
'szip' => array(
@@ -818,7 +840,7 @@ class getID3
'mime_type' => 'application/octet-stream',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
- ),
+ ),
// TAR - data - TAR compressed data
'tar' => array(
@@ -828,7 +850,7 @@ class getID3
'mime_type' => 'application/x-tar',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
- ),
+ ),
// GZIP - data - GZIP compressed data
'gz' => array(
@@ -838,7 +860,7 @@ class getID3
'mime_type' => 'application/x-gzip',
'fail_id3' => 'ERROR',
'fail_ape' => 'ERROR',
- ),
+ ),
// ZIP - data - ZIP compressed data
'zip' => array(
diff --git a/modules/id3/getid3/module.audio-video.asf.php b/modules/id3/getid3/module.audio-video.asf.php
index c11a04b2..c7e5aa1b 100644
--- a/modules/id3/getid3/module.audio-video.asf.php
+++ b/modules/id3/getid3/module.audio-video.asf.php
@@ -754,6 +754,11 @@ class getid3_asf
$thisfile_asf_comments['year'] = array( $this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
break;
+ case 'wm/lyrics':
+ case 'lyrics':
+ $thisfile_asf_comments['lyrics'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
+ break;
+
case 'isvbr':
if ($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']) {
$thisfile_audio['bitrate_mode'] = 'vbr';
@@ -769,12 +774,12 @@ class getid3_asf
$tempThisfileInfo = array('encoding'=>$ThisFileInfo['encoding']);
fwrite($tempfilehandle, $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
fclose($tempfilehandle);
-
+
$tempfilehandle = fopen($tempfile, "rb");
$id3 = new getid3_id3v2($tempfilehandle, $tempThisfileInfo);
fclose($tempfilehandle);
unlink($tempfile);
-
+
$ThisFileInfo['id3v2'] = $tempThisfileInfo['id3v2'];
}
break;
diff --git a/modules/id3/getid3/module.audio-video.flv.php b/modules/id3/getid3/module.audio-video.flv.php
new file mode 100644
index 00000000..54666bd2
--- /dev/null
+++ b/modules/id3/getid3/module.audio-video.flv.php
@@ -0,0 +1,210 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+// //
+// FLV module by Seth Kaufman <seth@whirl-i-gig.com> //
+// * version 0.1 (26 June 2005) //
+// minor modifications by James Heinrich <info@getid3.org> //
+// * version 0.1.1 (15 July 2005) //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio-video.flv.php //
+// module for analyzing Shockwave Flash Video files //
+// dependencies: NONE //
+// ///
+/////////////////////////////////////////////////////////////////
+
+
+class getid3_flv
+{
+
+ function getid3_flv(&$fd, &$ThisFileInfo, $ReturnAllTagData=false) {
+ fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);
+
+ $FLVfileData = fread($fd, $ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']);
+
+ $FLVmagic = substr($FLVfileData, 0, 3);
+ if ($FLVmagic != 'FLV') {
+ $ThisFileInfo['error'][] = 'Expecting "FLV" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$ThisFileInfo['flv']['header']['signature'].'"';
+ unset($ThisFileInfo['flv']);
+ unset($ThisFileInfo['fileformat']);
+ return false;
+ }
+ $ThisFileInfo['flv']['header']['signature'] = $FLVmagic;
+ $ThisFileInfo['flv']['header']['version'] = ord($FLVfileData{3});
+ $ThisFileInfo['fileformat'] = 'flv';
+
+ $TypeFlags = ord($FLVfileData{4});
+ $ThisFileInfo['flv']['header']['hasAudio'] = (bool) ($TypeFlags & 4);
+ $ThisFileInfo['flv']['header']['hasVideo'] = (bool) ($TypeFlags & 1);
+
+ $FrameSizeDataLength = getid3_lib::BigEndian2Int(substr($FLVfileData, 5, 4));
+
+ // FLV tags
+ $CurrentOffset = $FrameSizeDataLength;
+ $FLVdataLength = strlen($FLVfileData);
+
+ $Duration = 0;
+
+ $SoundFormat = null;
+ $VideoFormat = null;
+ while ($CurrentOffset < $FLVdataLength) {
+ // previous tag size
+ $PreviousTagLength = getid3_lib::BigEndian2Int(substr($FLVfileData, $CurrentOffset, 4));
+ $CurrentOffset += 4;
+
+ $TagType = ord(substr($FLVfileData, $CurrentOffset, 1));
+ $DataLength = getid3_lib::BigEndian2Int(substr($FLVfileData, $CurrentOffset + 1, 3));
+ $Timestamp = getid3_lib::BigEndian2Int(substr($FLVfileData, $CurrentOffset + 4, 3));
+
+ switch ($TagType) {
+ case 8:
+ if (is_null($SoundFormat)) {
+ $SoundInfo = ord(substr($FLVfileData, $CurrentOffset + 11, 1));
+ $SoundFormat = $SoundInfo & 0x07;
+ $ThisFileInfo['flv']['audio']['audioFormat'] = $SoundFormat;
+ $ThisFileInfo['flv']['audio']['audioRate'] = ($SoundInfo & 0x30) / 0x10;
+ $ThisFileInfo['flv']['audio']['audioSampleSize'] = ($SoundInfo & 0x40) / 0x40;
+ $ThisFileInfo['flv']['audio']['audioType'] = ($SoundInfo & 0x80) / 0x80;
+ }
+ break;
+
+ case 9:
+ if (is_null($VideoFormat)) {
+ $VideoInfo = ord(substr($FLVfileData, $CurrentOffset + 11, 1));
+ $VideoFormat = $VideoInfo & 0x07;
+ $ThisFileInfo['flv']['video']['videoCodec'] = $VideoFormat;
+
+ $PictureSizeType = (getid3_lib::BigEndian2Int(substr($FLVfileData, $CurrentOffset + 15, 2))) >> 7;
+ $PictureSizeType = $PictureSizeType & 0x0007;
+ $ThisFileInfo['flv']['header']['videoSizeType'] = $PictureSizeType;
+ switch ($PictureSizeType) {
+ case 0:
+ $PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVfileData, $CurrentOffset + 16, 2));
+ $PictureSizeEnc <<= 1;
+ $ThisFileInfo['video']['resolution_x'] = ($PictureSizeEnc & 0xFF00) >> 8;
+ $PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVfileData, $CurrentOffset + 17, 2));
+ $PictureSizeEnc <<= 1;
+ $ThisFileInfo['video']['resolution_y'] = ($PictureSizeEnc & 0xFF00) >> 8;
+ break;
+
+ case 1:
+ $PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVfileData, $CurrentOffset + 16, 4));
+ $PictureSizeEnc <<= 1;
+ $ThisFileInfo['video']['resolution_x'] = ($PictureSizeEnc & 0xFFFF0000) >> 16;
+
+ $PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVfileData, $CurrentOffset + 18, 4));
+ $PictureSizeEnc <<= 1;
+ $ThisFileInfo['video']['resolution_y'] = ($PictureSizeEnc & 0xFFFF0000) >> 16;
+ break;
+
+ case 2:
+ $ThisFileInfo['video']['resolution_x'] = 352;
+ $ThisFileInfo['video']['resolution_y'] = 288;
+ break;
+
+ case 3:
+ $ThisFileInfo['video']['resolution_x'] = 176;
+ $ThisFileInfo['video']['resolution_y'] = 144;
+ break;
+
+ case 4:
+ $ThisFileInfo['video']['resolution_x'] = 128;
+ $ThisFileInfo['video']['resolution_y'] = 96;
+ break;
+
+ case 5:
+ $ThisFileInfo['video']['resolution_x'] = 320;
+ $ThisFileInfo['video']['resolution_y'] = 240;
+ break;
+
+ case 6:
+ $ThisFileInfo['video']['resolution_x'] = 160;
+ $ThisFileInfo['video']['resolution_y'] = 120;
+ break;
+
+ default:
+ $ThisFileInfo['video']['resolution_x'] = 0;
+ $ThisFileInfo['video']['resolution_y'] = 0;
+ break;
+
+ }
+ }
+ break;
+
+ default:
+ // noop
+ break;
+ }
+
+ if ($Timestamp > $Duration) {
+ $Duration = $Timestamp;
+ }
+
+ $CurrentOffset += ($DataLength + 11);
+ }
+
+ $ThisFileInfo['playtime_seconds'] = $Duration / 1000;
+ $ThisFileInfo['bitrate'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) / $ThisFileInfo['playtime_seconds'];
+
+ if ($ThisFileInfo['flv']['header']['hasAudio']) {
+ $ThisFileInfo['audio']['codec'] = $this->FLVaudioFormat($ThisFileInfo['flv']['audio']['audioFormat']);
+ $ThisFileInfo['audio']['sample_rate'] = $this->FLVaudioRate($ThisFileInfo['flv']['audio']['audioRate']);
+ $ThisFileInfo['audio']['bits_per_sample'] = $this->FLVaudioBitDepth($ThisFileInfo['flv']['audio']['audioSampleSize']);
+
+ $ThisFileInfo['audio']['channels'] = $ThisFileInfo['flv']['audio']['audioType'] + 1; // 0=mono,1=stereo
+ $ThisFileInfo['audio']['lossless'] = ($ThisFileInfo['flv']['audio']['audioFormat'] ? false : true); // 0=uncompressed
+ $ThisFileInfo['audio']['dataformat'] = 'flv';
+ }
+ if (@$ThisFileInfo['flv']['header']['hasVideo']) {
+ $ThisFileInfo['video']['codec'] = $this->FLVvideoCodec($ThisFileInfo['flv']['video']['videoCodec']);
+ $ThisFileInfo['video']['dataformat'] = 'flv';
+ $ThisFileInfo['video']['lossless'] = false;
+ }
+
+ return true;
+ }
+
+
+ function FLVaudioFormat($id) {
+ $FLVaudioFormat = array(
+ 0 => 'uncompressed',
+ 1 => 'ADPCM',
+ 2 => 'mp3',
+ 5 => 'Nellymoser 8kHz mono',
+ 6 => 'Nellymoser',
+ );
+ return (@$FLVaudioFormat[$id] ? @$FLVaudioFormat[$id] : false);
+ }
+
+ function FLVaudioRate($id) {
+ $FLVaudioRate = array(
+ 0 => 5500,
+ 1 => 11025,
+ 2 => 22050,
+ 3 => 44100,
+ );
+ return (@$FLVaudioRate[$id] ? @$FLVaudioRate[$id] : false);
+ }
+
+ function FLVaudioBitDepth($id) {
+ $FLVaudioBitDepth = array(
+ 0 => 8,
+ 1 => 16,
+ );
+ return (@$FLVaudioBitDepth[$id] ? @$FLVaudioBitDepth[$id] : false);
+ }
+
+ function FLVvideoCodec($id) {
+ $FLVaudioBitDepth = array(
+ 2 => 'Sorenson H.263',
+ 3 => 'Screen video',
+ );
+ return (@$FLVaudioBitDepth[$id] ? @$FLVaudioBitDepth[$id] : false);
+ }
+
+}
+
+?> \ No newline at end of file
diff --git a/modules/id3/getid3/module.audio-video.riff.php b/modules/id3/getid3/module.audio-video.riff.php
index ebe3ee77..b2225a28 100644
--- a/modules/id3/getid3/module.audio-video.riff.php
+++ b/modules/id3/getid3/module.audio-video.riff.php
@@ -1953,8 +1953,6 @@ class getid3_riff
XMPG Xing MPEG (I-Frame only)
XVID XviD MPEG-4 (www.xvid.org)
XXAN ?XXAN?
- Y422 ADS Technologies Copy of UYVY used in Pyro WebCam firewire camera
- Y800 Simple, single Y plane for monochrome images
YU92 Intel YUV (YU92)
YUNV Nvidia Uncompressed YUV 4:2:2
YUVP Extended PAL format YUV palette (www.riff.org)
@@ -1965,6 +1963,8 @@ class getid3_riff
Y41T Brooktree PC1 YUV 4:1:1 with transparency
Y42B Weitek YUV 4:2:2 Planar
Y42T Brooktree UYUV 4:2:2 with transparency
+ Y422 ADS Technologies Copy of UYVY used in Pyro WebCam firewire camera
+ Y800 Simple, single Y plane for monochrome images
Y8 Grayscale video
YC12 Intel YUV 12 codec
YUV8 Winnov Caviar YUV8
diff --git a/modules/id3/getid3/module.audio.mp3.php b/modules/id3/getid3/module.audio.mp3.php
index d7b0b77a..5fb6110c 100644
--- a/modules/id3/getid3/module.audio.mp3.php
+++ b/modules/id3/getid3/module.audio.mp3.php
@@ -320,8 +320,9 @@ class getid3_mp3
'fast standard|19000' => 19000,
'r3mix|19500' => 19500, // 3.90, 3.90.1, 3.92
'r3mix|19600' => 19600, // 3.90.2, 3.90.3, 3.91
- 'r3mix|18000' => 18000); // 3.94, 3.95
- if (!isset($ExpectedLowpass[$ExplodedOptions[1].'|'.$thisfile_mpeg_audio_lame['lowpass_frequency']])) {
+ 'r3mix|18000' => 18000, // 3.94, 3.95
+ );
+ if (!isset($ExpectedLowpass[$ExplodedOptions[1].'|'.$thisfile_mpeg_audio_lame['lowpass_frequency']]) && ($thisfile_mpeg_audio_lame['lowpass_frequency'] < 22050) && (round($thisfile_mpeg_audio_lame['lowpass_frequency'] / 1000) < round($thisfile_mpeg_audio['sample_rate'] / 2000))) {
$encoder_options .= ' --lowpass '.$thisfile_mpeg_audio_lame['lowpass_frequency'];
}
break;
@@ -1636,23 +1637,17 @@ class getid3_mp3
if (isset($MPEGaudioVersionLookup[$rawarray['version']])) {
$decodedVersion = $MPEGaudioVersionLookup[$rawarray['version']];
} else {
- if ($echoerrors) {
- echo "\n".'invalid Version ('.$rawarray['version'].')';
- }
+ echo ($echoerrors ? "\n".'invalid Version ('.$rawarray['version'].')' : '');
return false;
}
if (isset($MPEGaudioLayerLookup[$rawarray['layer']])) {
$decodedLayer = $MPEGaudioLayerLookup[$rawarray['layer']];
} else {
- if ($echoerrors) {
- echo "\n".'invalid Layer ('.$rawarray['layer'].')';
- }
+ echo ($echoerrors ? "\n".'invalid Layer ('.$rawarray['layer'].')' : '');
return false;
}
if (!isset($MPEGaudioBitrateLookup[$decodedVersion][$decodedLayer][$rawarray['bitrate']])) {
- if ($echoerrors) {
- echo "\n".'invalid Bitrate ('.$rawarray['bitrate'].')';
- }
+ echo ($echoerrors ? "\n".'invalid Bitrate ('.$rawarray['bitrate'].')' : '');
if ($rawarray['bitrate'] == 15) {
// known issue in LAME 3.90 - 3.93.1 where free-format has bitrate ID of 15 instead of 0
// let it go through here otherwise file will not be identified
@@ -1664,27 +1659,19 @@ class getid3_mp3
}
}
if (!isset($MPEGaudioFrequencyLookup[$decodedVersion][$rawarray['sample_rate']])) {
- if ($echoerrors) {
- echo "\n".'invalid Frequency ('.$rawarray['sample_rate'].')';
- }
+ echo ($echoerrors ? "\n".'invalid Frequency ('.$rawarray['sample_rate'].')' : '');
return false;
}
if (!isset($MPEGaudioChannelModeLookup[$rawarray['channelmode']])) {
- if ($echoerrors) {
- echo "\n".'invalid ChannelMode ('.$rawarray['channelmode'].')';
- }
+ echo ($echoerrors ? "\n".'invalid ChannelMode ('.$rawarray['channelmode'].')' : '');
return false;
}
if (!isset($MPEGaudioModeExtensionLookup[$decodedLayer][$rawarray['modeextension']])) {
- if ($echoerrors) {
- echo "\n".'invalid Mode Extension ('.$rawarray['modeextension'].')';
- }
+ echo ($echoerrors ? "\n".'invalid Mode Extension ('.$rawarray['modeextension'].')' : '');
return false;
}
if (!isset($MPEGaudioEmphasisLookup[$rawarray['emphasis']])) {
- if ($echoerrors) {
- echo "\n".'invalid Emphasis ('.$rawarray['emphasis'].')';
- }
+ echo ($echoerrors ? "\n".'invalid Emphasis ('.$rawarray['emphasis'].')' : '');
return false;
}
// These are just either set or not set, you can't mess that up :)
diff --git a/modules/id3/getid3/module.tag.id3v2.php b/modules/id3/getid3/module.tag.id3v2.php
index c855bf21..8bb6c3cb 100644
--- a/modules/id3/getid3/module.tag.id3v2.php
+++ b/modules/id3/getid3/module.tag.id3v2.php
@@ -101,47 +101,51 @@ class getid3_id3v2
$thisfile_id3v2['tag_offset_start'] = $StartingOffset;
$thisfile_id3v2['tag_offset_end'] = $thisfile_id3v2['tag_offset_start'] + $thisfile_id3v2['headerlength'];
- // Extended Header
+ // Extended Header
if (isset($thisfile_id3v2_flags['exthead']) && $thisfile_id3v2_flags['exthead']) {
- // Extended header size 4 * %0xxxxxxx
- // Number of flag bytes $01
- // Extended Flags $xx
- // Where the 'Extended header size' is the size of the whole extended header, stored as a 32 bit synchsafe integer.
- $extheader = fread ($fd, 4);
- $thisfile_id3v2['extheaderlength'] = getid3_lib::BigEndian2Int($extheader, 1);
-
- // The extended flags field, with its size described by 'number of flag bytes', is defined as:
- // %0bcd0000
- // 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
- $extheaderflagbytes = fread ($fd, 1);
- $extheaderflags = fread ($fd, $extheaderflagbytes);
- $id3_exthead_flags = getid3_lib::BigEndian2Bin(substr($header, 5, 1));
- $thisfile_id3v2['exthead_flags']['update'] = substr($id3_exthead_flags, 1, 1);
- $thisfile_id3v2['exthead_flags']['CRC'] = substr($id3_exthead_flags, 2, 1);
- if ($thisfile_id3v2['exthead_flags']['CRC']) {
- $extheaderrawCRC = fread ($fd, 5);
- $thisfile_id3v2['exthead_flags']['CRC'] = getid3_lib::BigEndian2Int($extheaderrawCRC, 1);
- }
- $thisfile_id3v2['exthead_flags']['restrictions'] = substr($id3_exthead_flags, 3, 1);
- if ($thisfile_id3v2['exthead_flags']['restrictions']) {
- // Restrictions %ppqrrstt
- $extheaderrawrestrictions = fread ($fd, 1);
- $thisfile_id3v2['exthead_flags']['restrictions_tagsize'] = (bindec('11000000') & ord($extheaderrawrestrictions)) >> 6; // p - Tag size restrictions
- $thisfile_id3v2['exthead_flags']['restrictions_textenc'] = (bindec('00100000') & ord($extheaderrawrestrictions)) >> 5; // q - Text encoding restrictions
- $thisfile_id3v2['exthead_flags']['restrictions_textsize'] = (bindec('00011000') & ord($extheaderrawrestrictions)) >> 3; // r - Text fields size restrictions
- $thisfile_id3v2['exthead_flags']['restrictions_imgenc'] = (bindec('00000100') & ord($extheaderrawrestrictions)) >> 2; // s - Image encoding restrictions
- $thisfile_id3v2['exthead_flags']['restrictions_imgsize'] = (bindec('00000011') & ord($extheaderrawrestrictions)) >> 0; // t - Image size restrictions
+ // Extended header size 4 * %0xxxxxxx
+ // Number of flag bytes $01
+ // Extended Flags $xx
+ // Where the 'Extended header size' is the size of the whole extended header, stored as a 32 bit synchsafe integer.
+ $thisfile_id3v2['exthead_length'] = getid3_lib::BigEndian2Int(fread($fd, 4), 1);
+
+ $thisfile_id3v2['exthead_flag_bytes'] = ord(fread($fd, 1));
+ if ($thisfile_id3v2['exthead_flag_bytes'] == 1) {
+ // The extended flags field, with its size described by 'number of flag bytes', is defined as:
+ // %0bcd0000
+ // 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
+ $extheaderflags = fread($fd, $thisfile_id3v2['exthead_flag_bytes']);
+ $id3_exthead_flags = getid3_lib::BigEndian2Bin(substr($header, 5, 1));
+ $thisfile_id3v2['exthead_flags']['update'] = substr($id3_exthead_flags, 1, 1);
+ $thisfile_id3v2['exthead_flags']['CRC'] = substr($id3_exthead_flags, 2, 1);
+ if ($thisfile_id3v2['exthead_flags']['CRC']) {
+ $extheaderrawCRC = fread($fd, 5);
+ $thisfile_id3v2['exthead_flags']['CRC'] = getid3_lib::BigEndian2Int($extheaderrawCRC, 1);
+ }
+ $thisfile_id3v2['exthead_flags']['restrictions'] = substr($id3_exthead_flags, 3, 1);
+ if ($thisfile_id3v2['exthead_flags']['restrictions']) {
+ // Restrictions %ppqrrstt
+ $extheaderrawrestrictions = fread($fd, 1);
+ $thisfile_id3v2['exthead_flags']['restrictions_tagsize'] = (bindec('11000000') & ord($extheaderrawrestrictions)) >> 6; // p - Tag size restrictions
+ $thisfile_id3v2['exthead_flags']['restrictions_textenc'] = (bindec('00100000') & ord($extheaderrawrestrictions)) >> 5; // q - Text encoding restrictions
+ $thisfile_id3v2['exthead_flags']['restrictions_textsize'] = (bindec('00011000') & ord($extheaderrawrestrictions)) >> 3; // r - Text fields size restrictions
+ $thisfile_id3v2['exthead_flags']['restrictions_imgenc'] = (bindec('00000100') & ord($extheaderrawrestrictions)) >> 2; // s - Image encoding restrictions
+ $thisfile_id3v2['exthead_flags']['restrictions_imgsize'] = (bindec('00000011') & ord($extheaderrawrestrictions)) >> 0; // t - Image size restrictions
+ }
+ } else {
+ $ThisFileInfo['warning'][] = '$thisfile_id3v2[exthead_flag_bytes] = "'.$thisfile_id3v2['exthead_flag_bytes'].'" (expecting "1")';
+ fseek($fd, $thisfile_id3v2['exthead_length'] - 1, SEEK_CUR);
+ //return false;
}
} // end extended header
-
// create 'encoding' key - used by getid3::HandleAllTags()
// in ID3v2 every field can have it's own encoding type
// so force everything to UTF-8 so it can be handled consistantly
@@ -159,10 +163,10 @@ class getid3_id3v2
// Flags $xx xx
$sizeofframes = $thisfile_id3v2['headerlength'] - 10; // not including 10-byte initial header
- if (isset($thisfile_id3v2['extheaderlength'])) {
- $sizeofframes -= $thisfile_id3v2['extheaderlength'];
+ if (@$thisfile_id3v2['exthead_length']) {
+ $sizeofframes -= ($thisfile_id3v2['exthead_length'] + 4);
}
- if (isset($thisfile_id3v2_flags['isfooter']) && $thisfile_id3v2_flags['isfooter']) {
+ if (@$thisfile_id3v2_flags['isfooter']) {
$sizeofframes -= 10; // footer takes last 10 bytes of ID3v2 header, after frame data, before audio
}
if ($sizeofframes > 0) {
@@ -170,7 +174,7 @@ class getid3_id3v2
$framedata = fread($fd, $sizeofframes); // read all frames from file into $framedata variable
// if entire frame data is unsynched, de-unsynch it now (ID3v2.3.x)
- if (isset($thisfile_id3v2_flags['unsynch']) && $thisfile_id3v2_flags['unsynch'] && ($id3v2_majorversion <= 3)) {
+ if (@$thisfile_id3v2_flags['unsynch'] && ($id3v2_majorversion <= 3)) {
$framedata = $this->DeUnsynchronise($framedata);
}
// [in ID3v2.4.0] Unsynchronisation [S:6.1] is done on frame level, instead
@@ -179,7 +183,7 @@ class getid3_id3v2
// there exists an unsynchronised frame, while the new unsynchronisation flag in
// the frame header [S:4.1.2] indicates unsynchronisation.
- $framedataoffset = 10; // how many bytes into the stream - start from after the 10-byte header
+ $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)
while (isset($framedata) && (strlen($framedata) > 0)) { // cycle through until no more frame data is left to parse
if (strlen($framedata) <= $this->ID3v2HeaderLength($id3v2_majorversion)) {
// insufficient room left in ID3v2 header for actual data - must be padding
@@ -350,7 +354,7 @@ class getid3_id3v2
// ID3v2 size 4 * %0xxxxxxx
if (isset($thisfile_id3v2_flags['isfooter']) && $thisfile_id3v2_flags['isfooter']) {
- $footer = fread ($fd, 10);
+ $footer = fread($fd, 10);
if (substr($footer, 0, 3) == '3DI') {
$thisfile_id3v2['footer'] = true;
$thisfile_id3v2['majorversion_footer'] = ord($footer{3});
diff --git a/modules/id3/getid3/write.id3v2.php b/modules/id3/getid3/write.id3v2.php
index a575f20b..9d47e708 100644
--- a/modules/id3/getid3/write.id3v2.php
+++ b/modules/id3/getid3/write.id3v2.php
@@ -101,6 +101,7 @@ class getid3_write_id3v2
fclose($fp_source);
copy($tempfilename, $this->filename);
unlink($tempfilename);
+ ob_end_clean();
return true;
} else {
diff --git a/modules/id3/getid3/write.php b/modules/id3/getid3/write.php
index 40a79e9e..db09decd 100644
--- a/modules/id3/getid3/write.php
+++ b/modules/id3/getid3/write.php
@@ -394,6 +394,14 @@ class getid3_writetags
}
break;
+ case 'real':
+ $real_writer = new getid3_write_real;
+ $real_writer->filename = $this->filename;
+ if (($success = $real_writer->RemoveReal()) === false) {
+ $this->errors[] = 'RemoveReal() failed with message(s):<PRE><UL><LI>'.trim(implode('</LI><LI>', $real_writer->errors)).'</LI></UL></PRE>';
+ }
+ break;
+
default:
$this->errors[] = 'Invalid tag format to delete: "'.$tagformat.'"';
return false;
diff --git a/modules/id3/getid3/write.real.php b/modules/id3/getid3/write.real.php
index 5ede28d1..1e0240cc 100644
--- a/modules/id3/getid3/write.real.php
+++ b/modules/id3/getid3/write.real.php
@@ -16,7 +16,7 @@
class getid3_write_real
{
var $filename;
- var $tag_data;
+ var $tag_data = array();
var $warnings = array(); // any non-critical errors will be stored here
var $errors = array(); // any critical errors will be stored here
var $paddedlength = 512; // minimum length of CONT tag in bytes
@@ -33,50 +33,98 @@ class getid3_write_real
// Initialize getID3 engine
$getID3 = new getID3;
$OldThisFileInfo = $getID3->analyze($this->filename);
- if (empty($OldThisFileInfo['chunks']) && !empty($OldThisFileInfo['old_ra_header'])) {
+ if (empty($OldThisFileInfo['real']['chunks']) && !empty($OldThisFileInfo['real']['old_ra_header'])) {
$this->errors[] = 'Cannot write Real tags on old-style file format';
+ fclose($fp_source);
return false;
}
- $OldPROPinfo = false;
- $StartOfDATA = false;
- foreach ($OldThisFileInfo['chunks'] as $chunknumber => $chunkarray) {
- if ($chunkarray['name'] == 'PROP') {
- $OldPROPinfo = $chunkarray;
- } elseif ($chunkarray['name'] = 'DATA') {
- $StartOfDATA = $chunkarray['offset'];
- }
+ if (empty($OldThisFileInfo['real']['chunks'])) {
+ $this->errors[] = 'Cannot write Real tags because cannot find DATA chunk in file';
+ fclose($fp_source);
+ return false;
+ }
+ foreach ($OldThisFileInfo['real']['chunks'] as $chunknumber => $chunkarray) {
+ $oldChunkInfo[$chunkarray['name']] = $chunkarray;
+ }
+ if (!empty($oldChunkInfo['CONT']['length'])) {
+ $this->paddedlength = max($oldChunkInfo['CONT']['length'], $this->paddedlength);
}
- if (!empty($OldPROPinfo['length'])) {
- $this->paddedlength = max($OldPROPinfo['length'], $this->paddedlength);
+ $new_CONT_tag_data = $this->GenerateCONTchunk();
+ $new_PROP_tag_data = $this->GeneratePROPchunk($OldThisFileInfo['real']['chunks'], $new_CONT_tag_data);
+ $new__RMF_tag_data = $this->GenerateRMFchunk($OldThisFileInfo['real']['chunks']);
+
+ if (@$oldChunkInfo['.RMF']['length'] == strlen($new__RMF_tag_data)) {
+ fseek($fp_source, $oldChunkInfo['.RMF']['offset'], SEEK_SET);
+ fwrite($fp_source, $new__RMF_tag_data);
+ } else {
+ $this->errors[] = 'new .RMF tag ('.strlen($new__RMF_tag_data).' bytes) different length than old .RMF tag ('.$oldChunkInfo['.RMF']['length'].' bytes)';
+ fclose($fp_source);
+ return false;
}
- $new_real_tag_data = GenerateRealTag();
+ if (@$oldChunkInfo['PROP']['length'] == strlen($new_PROP_tag_data)) {
+ fseek($fp_source, $oldChunkInfo['PROP']['offset'], SEEK_SET);
+ fwrite($fp_source, $new_PROP_tag_data);
+ } else {
+ $this->errors[] = 'new PROP tag ('.strlen($new_PROP_tag_data).' bytes) different length than old PROP tag ('.$oldChunkInfo['PROP']['length'].' bytes)';
+ fclose($fp_source);
+ return false;
+ }
- if (@$OldPROPinfo['length'] == $new_real_tag_data) {
+ if (@$oldChunkInfo['CONT']['length'] == strlen($new_CONT_tag_data)) {
// new data length is same as old data length - just overwrite
- fseek($fp_source, $OldPROPinfo['offset'], SEEK_SET);
- fwrite($fp_source, $new_real_tag_data);
+ fseek($fp_source, $oldChunkInfo['CONT']['offset'], SEEK_SET);
+ fwrite($fp_source, $new_CONT_tag_data);
+ fclose($fp_source);
+ return true;
} else {
- if (empty($OldPROPinfo)) {
- // no existing PROP chunk
- $BeforeOffset = $StartOfDATA;
- $AfterOffset = $StartOfDATA;
+ if (empty($oldChunkInfo['CONT'])) {
+ // no existing CONT chunk
+ $BeforeOffset = $oldChunkInfo['DATA']['offset'];
+ $AfterOffset = $oldChunkInfo['DATA']['offset'];
} else {
// new data is longer than old data
- $BeforeOffset = $OldPROPinfo['offset'];
- $AfterOffset = $OldPROPinfo['offset'] + $OldPROPinfo['length'];
+ $BeforeOffset = $oldChunkInfo['CONT']['offset'];
+ $AfterOffset = $oldChunkInfo['CONT']['offset'] + $oldChunkInfo['CONT']['length'];
}
+ if ($tempfilename = tempnam('*', 'getID3')) {
+ ob_start();
+ if ($fp_temp = fopen($tempfilename, 'wb')) {
+
+ rewind($fp_source);
+ fwrite($fp_temp, fread($fp_source, $BeforeOffset));
+ fwrite($fp_temp, $new_CONT_tag_data);
+ fseek($fp_source, $AfterOffset, SEEK_SET);
+ while ($buffer = fread($fp_source, GETID3_FREAD_BUFFER_SIZE)) {
+ fwrite($fp_temp, $buffer, strlen($buffer));
+ }
+ fclose($fp_temp);
+
+ if (copy($tempfilename, $this->filename)) {
+ unlink($tempfilename);
+ fclose($fp_source);
+ return true;
+ }
+ unlink($tempfilename);
+ $this->errors[] = 'FAILED: copy('.$tempfilename.', '.$this->filename.') - '.strip_tags(ob_get_contents());
+ } else {
+
+ $this->errors[] = 'Could not open '.$tempfilename.' mode "wb" - '.strip_tags(ob_get_contents());
+
+ }
+ ob_end_clean();
+ }
+ fclose($fp_source);
+ return false;
}
- fclose($fp_source);
- return true;
} else {
$this->errors[] = 'Could not open '.$this->filename.' mode "r+b"';
@@ -87,28 +135,88 @@ class getid3_write_real
return false;
}
- function GenerateRealTag() {
- $RealCONT = "\x00\x00"; // object version
+ function GenerateRMFchunk(&$chunks) {
+ $oldCONTexists = false;
+ foreach ($chunks as $key => $chunk) {
+ $chunkNameKeys[$chunk['name']] = $key;
+ if ($chunk['name'] == 'CONT') {
+ $oldCONTexists = true;
+ }
+ }
+ $newHeadersCount = $chunks[$chunkNameKeys['.RMF']]['headers_count'] + ($oldCONTexists ? 0 : 1);
- $RealCONT .= BigEndian2String(strlen(@$this->tag_data['title']), 4);
- $RealCONT .= @$this->tag_data['title'];
+ $RMFchunk = "\x00\x00"; // object version
+ $RMFchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['.RMF']]['file_version'], 4);
+ $RMFchunk .= getid3_lib::BigEndian2String($newHeadersCount, 4);
- $RealCONT .= BigEndian2String(strlen(@$this->tag_data['artist']), 4);
- $RealCONT .= @$this->tag_data['artist'];
+ $RMFchunk = '.RMF'.getid3_lib::BigEndian2String(strlen($RMFchunk) + 8, 4).$RMFchunk; // .RMF chunk identifier + chunk length
+ return $RMFchunk;
+ }
+
+ function GeneratePROPchunk(&$chunks, &$new_CONT_tag_data) {
+ $old_CONT_length = 0;
+ $old_DATA_offset = 0;
+ $old_INDX_offset = 0;
+ foreach ($chunks as $key => $chunk) {
+ $chunkNameKeys[$chunk['name']] = $key;
+ if ($chunk['name'] == 'CONT') {
+ $old_CONT_length = $chunk['length'];
+ } elseif ($chunk['name'] == 'DATA') {
+ if (!$old_DATA_offset) {
+ $old_DATA_offset = $chunk['offset'];
+ }
+ } elseif ($chunk['name'] == 'INDX') {
+ if (!$old_INDX_offset) {
+ $old_INDX_offset = $chunk['offset'];
+ }
+ }
+ }
+ $CONTdelta = strlen($new_CONT_tag_data) - $old_CONT_length;
- $RealCONT .= BigEndian2String(strlen(@$this->tag_data['copyright']), 4);
- $RealCONT .= @$this->tag_data['copyright'];
+ $PROPchunk = "\x00\x00"; // object version
+ $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['max_bit_rate'], 4);
+ $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['avg_bit_rate'], 4);
+ $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['max_packet_size'], 4);
+ $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['avg_packet_size'], 4);
+ $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['num_packets'], 4);
+ $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['duration'], 4);
+ $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['preroll'], 4);
+ $PROPchunk .= getid3_lib::BigEndian2String(max(0, $old_INDX_offset + $CONTdelta), 4);
+ $PROPchunk .= getid3_lib::BigEndian2String(max(0, $old_DATA_offset + $CONTdelta), 4);
+ $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['num_streams'], 2);
+ $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['flags_raw'], 2);
- $RealCONT .= BigEndian2String(strlen(@$this->tag_data['comment']), 4);
- $RealCONT .= @$this->tag_data['comment'];
+ $PROPchunk = 'PROP'.getid3_lib::BigEndian2String(strlen($PROPchunk) + 8, 4).$PROPchunk; // PROP chunk identifier + chunk length
+ return $PROPchunk;
+ }
- if ($this->paddedlength > (strlen($RealCONT) + 8)) {
- $RealCONT .= str_repeat("\x00", $this->paddedlength - strlen($RealCONT) - 8);
+ function GenerateCONTchunk() {
+ foreach ($this->tag_data as $key => $value) {
+ // limit each value to 0xFFFF bytes
+ $this->tag_data[$key] = substr($value, 0, 65535);
}
- $RealCONT = 'CONT'.BigEndian2String(strlen($RealCONT) + 8, 4).$RealCONT; // CONT chunk identifier + chunk length
+ $CONTchunk = "\x00\x00"; // object version
+
+ $CONTchunk .= getid3_lib::BigEndian2String(strlen(@$this->tag_data['title']), 2);
+ $CONTchunk .= @$this->tag_data['title'];
+
+ $CONTchunk .= getid3_lib::BigEndian2String(strlen(@$this->tag_data['artist']), 2);
+ $CONTchunk .= @$this->tag_data['artist'];
+
+ $CONTchunk .= getid3_lib::BigEndian2String(strlen(@$this->tag_data['copyright']), 2);
+ $CONTchunk .= @$this->tag_data['copyright'];
- return $RealCONT;
+ $CONTchunk .= getid3_lib::BigEndian2String(strlen(@$this->tag_data['comment']), 2);
+ $CONTchunk .= @$this->tag_data['comment'];
+
+ if ($this->paddedlength > (strlen($CONTchunk) + 8)) {
+ $CONTchunk .= str_repeat("\x00", $this->paddedlength - strlen($CONTchunk) - 8);
+ }
+
+ $CONTchunk = 'CONT'.getid3_lib::BigEndian2String(strlen($CONTchunk) + 8, 4).$CONTchunk; // CONT chunk identifier + chunk length
+
+ return $CONTchunk;
}
function RemoveReal() {
@@ -116,22 +224,69 @@ class getid3_write_real
if (is_writeable($this->filename)) {
if ($fp_source = @fopen($this->filename, 'r+b')) {
-return false;
- //fseek($fp_source, -128, SEEK_END);
- //if (fread($fp_source, 3) == 'TAG') {
- // ftruncate($fp_source, filesize($this->filename) - 128);
- //} else {
- // // no real tag to begin with - do nothing
- //}
+ // Initialize getID3 engine
+ $getID3 = new getID3;
+ $OldThisFileInfo = $getID3->analyze($this->filename);
+ if (empty($OldThisFileInfo['real']['chunks']) && !empty($OldThisFileInfo['real']['old_ra_header'])) {
+ $this->errors[] = 'Cannot remove Real tags from old-style file format';
+ fclose($fp_source);
+ return false;
+ }
+
+ if (empty($OldThisFileInfo['real']['chunks'])) {
+ $this->errors[] = 'Cannot remove Real tags because cannot find DATA chunk in file';
+ fclose($fp_source);
+ return false;
+ }
+ foreach ($OldThisFileInfo['real']['chunks'] as $chunknumber => $chunkarray) {
+ $oldChunkInfo[$chunkarray['name']] = $chunkarray;
+ }
+
+ if (empty($oldChunkInfo['CONT'])) {
+ // no existing CONT chunk
+ fclose($fp_source);
+ return true;
+ }
+
+ $BeforeOffset = $oldChunkInfo['CONT']['offset'];
+ $AfterOffset = $oldChunkInfo['CONT']['offset'] + $oldChunkInfo['CONT']['length'];
+ if ($tempfilename = tempnam('*', 'getID3')) {
+ ob_start();
+ if ($fp_temp = fopen($tempfilename, 'wb')) {
+
+ rewind($fp_source);
+ fwrite($fp_temp, fread($fp_source, $BeforeOffset));
+ fseek($fp_source, $AfterOffset, SEEK_SET);
+ while ($buffer = fread($fp_source, GETID3_FREAD_BUFFER_SIZE)) {
+ fwrite($fp_temp, $buffer, strlen($buffer));
+ }
+ fclose($fp_temp);
+
+ if (copy($tempfilename, $this->filename)) {
+ unlink($tempfilename);
+ fclose($fp_source);
+ return true;
+ }
+ unlink($tempfilename);
+ $this->errors[] = 'FAILED: copy('.$tempfilename.', '.$this->filename.') - '.strip_tags(ob_get_contents());
+
+ } else {
+
+ $this->errors[] = 'Could not open '.$tempfilename.' mode "wb" - '.strip_tags(ob_get_contents());
+
+ }
+ ob_end_clean();
+ }
fclose($fp_source);
- return true;
+ return false;
+
} else {
$this->errors[] = 'Could not open '.$this->filename.' mode "r+b"';
+ return false;
}
- } else {
- $this->errors[] = $this->filename.' is not writeable';
}
+ $this->errors[] = 'File is not writeable: '.$this->filename;
return false;
}