00001 <?php
00004
00005
00007
00009
00010
00011
00012
00013
00015
00016
00017 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.apetag.php', __FILE__, true);
00018
00019 class getid3_write_apetag
00020 {
00021
00022 var $filename;
00023 var $tag_data;
00024 var $always_preserve_replaygain = true;
00025 var $warnings = array();
00026 var $errors = array();
00027
00028 function getid3_write_apetag() {
00029 return true;
00030 }
00031
00032 function WriteAPEtag() {
00033
00034
00035 $getID3 = new getID3;
00036 $ThisFileInfo = $getID3->analyze($this->filename);
00037
00038 if (isset($ThisFileInfo['ape']['tag_offset_start']) && isset($ThisFileInfo['lyrics3']['tag_offset_end'])) {
00039 if ($ThisFileInfo['ape']['tag_offset_start'] >= $ThisFileInfo['lyrics3']['tag_offset_end']) {
00040
00041
00042 if (!$this->DeleteAPEtag()) {
00043 return false;
00044 }
00045 $ThisFileInfo = $getID3->analyze($this->filename);
00046 }
00047 }
00048
00049 if ($this->always_preserve_replaygain) {
00050 $ReplayGainTagsToPreserve = array('mp3gain_minmax', 'mp3gain_album_minmax', 'mp3gain_undo', 'replaygain_track_peak', 'replaygain_track_gain', 'replaygain_album_peak', 'replaygain_album_gain');
00051 foreach ($ReplayGainTagsToPreserve as $rg_key) {
00052 if (isset($ThisFileInfo['ape']['items'][strtolower($rg_key)]['data'][0]) && !isset($this->tag_data[strtoupper($rg_key)][0])) {
00053 $this->tag_data[strtoupper($rg_key)][0] = $ThisFileInfo['ape']['items'][strtolower($rg_key)]['data'][0];
00054 }
00055 }
00056 }
00057
00058 if ($APEtag = $this->GenerateAPEtag()) {
00059 if ($fp = @fopen($this->filename, 'a+b')) {
00060 $oldignoreuserabort = ignore_user_abort(true);
00061 flock($fp, LOCK_EX);
00062
00063 $PostAPEdataOffset = $ThisFileInfo['avdataend'];
00064 if (isset($ThisFileInfo['ape']['tag_offset_end'])) {
00065 $PostAPEdataOffset = max($PostAPEdataOffset, $ThisFileInfo['ape']['tag_offset_end']);
00066 }
00067 if (isset($ThisFileInfo['lyrics3']['tag_offset_start'])) {
00068 $PostAPEdataOffset = max($PostAPEdataOffset, $ThisFileInfo['lyrics3']['tag_offset_start']);
00069 }
00070 fseek($fp, $PostAPEdataOffset, SEEK_SET);
00071 $PostAPEdata = '';
00072 if ($ThisFileInfo['filesize'] > $PostAPEdataOffset) {
00073 $PostAPEdata = fread($fp, $ThisFileInfo['filesize'] - $PostAPEdataOffset);
00074 }
00075
00076 fseek($fp, $PostAPEdataOffset, SEEK_SET);
00077 if (isset($ThisFileInfo['ape']['tag_offset_start'])) {
00078 fseek($fp, $ThisFileInfo['ape']['tag_offset_start'], SEEK_SET);
00079 }
00080 ftruncate($fp, ftell($fp));
00081 fwrite($fp, $APEtag, strlen($APEtag));
00082 if (!empty($PostAPEdata)) {
00083 fwrite($fp, $PostAPEdata, strlen($PostAPEdata));
00084 }
00085 flock($fp, LOCK_UN);
00086 fclose($fp);
00087 ignore_user_abort($oldignoreuserabort);
00088 return true;
00089
00090 }
00091 return false;
00092 }
00093 return false;
00094 }
00095
00096 function DeleteAPEtag() {
00097 $getID3 = new getID3;
00098 $ThisFileInfo = $getID3->analyze($this->filename);
00099 if (isset($ThisFileInfo['ape']['tag_offset_start']) && isset($ThisFileInfo['ape']['tag_offset_end'])) {
00100 if ($fp = @fopen($this->filename, 'a+b')) {
00101
00102 flock($fp, LOCK_EX);
00103 $oldignoreuserabort = ignore_user_abort(true);
00104
00105 fseek($fp, $ThisFileInfo['ape']['tag_offset_end'], SEEK_SET);
00106 $DataAfterAPE = '';
00107 if ($ThisFileInfo['filesize'] > $ThisFileInfo['ape']['tag_offset_end']) {
00108 $DataAfterAPE = fread($fp, $ThisFileInfo['filesize'] - $ThisFileInfo['ape']['tag_offset_end']);
00109 }
00110
00111 ftruncate($fp, $ThisFileInfo['ape']['tag_offset_start']);
00112 fseek($fp, $ThisFileInfo['ape']['tag_offset_start'], SEEK_SET);
00113
00114 if (!empty($DataAfterAPE)) {
00115 fwrite($fp, $DataAfterAPE, strlen($DataAfterAPE));
00116 }
00117
00118 flock($fp, LOCK_UN);
00119 fclose($fp);
00120 ignore_user_abort($oldignoreuserabort);
00121
00122 return true;
00123
00124 }
00125 return false;
00126 }
00127 return true;
00128 }
00129
00130
00131 function GenerateAPEtag() {
00132
00133
00134 $items = array();
00135 if (!is_array($this->tag_data)) {
00136 return false;
00137 }
00138 foreach ($this->tag_data as $key => $arrayofvalues) {
00139 if (!is_array($arrayofvalues)) {
00140 return false;
00141 }
00142
00143 $valuestring = '';
00144 foreach ($arrayofvalues as $value) {
00145 $valuestring .= str_replace("\x00", '', $value)."\x00";
00146 }
00147 $valuestring = rtrim($valuestring, "\x00");
00148
00149
00150 $tagitem = getid3_lib::LittleEndian2String(strlen($valuestring), 4);
00151
00152
00153 $tagitem .= "\x00\x00\x00\x00";
00154
00155 $tagitem .= $this->CleanAPEtagItemKey($key)."\x00";
00156 $tagitem .= $valuestring;
00157
00158 $items[] = $tagitem;
00159
00160 }
00161
00162 return $this->GenerateAPEtagHeaderFooter($items, true).implode('', $items).$this->GenerateAPEtagHeaderFooter($items, false);
00163 }
00164
00165 function GenerateAPEtagHeaderFooter(&$items, $isheader=false) {
00166 $tagdatalength = 0;
00167 foreach ($items as $itemdata) {
00168 $tagdatalength += strlen($itemdata);
00169 }
00170
00171 $APEheader = 'APETAGEX';
00172 $APEheader .= getid3_lib::LittleEndian2String(2000, 4);
00173 $APEheader .= getid3_lib::LittleEndian2String(32 + $tagdatalength, 4);
00174 $APEheader .= getid3_lib::LittleEndian2String(count($items), 4);
00175 $APEheader .= $this->GenerateAPEtagFlags(true, true, $isheader, 0, false);
00176 $APEheader .= str_repeat("\x00", 8);
00177
00178 return $APEheader;
00179 }
00180
00181 function GenerateAPEtagFlags($header=true, $footer=true, $isheader=false, $encodingid=0, $readonly=false) {
00182 $APEtagFlags = array_fill(0, 4, 0);
00183 if ($header) {
00184 $APEtagFlags[0] |= 0x80;
00185 }
00186 if (!$footer) {
00187 $APEtagFlags[0] |= 0x40;
00188 }
00189 if ($isheader) {
00190 $APEtagFlags[0] |= 0x20;
00191 }
00192
00193
00194
00195
00196
00197 $APEtagFlags[3] |= ($encodingid << 1);
00198
00199 if ($readonly) {
00200 $APEtagFlags[3] |= 0x01;
00201 }
00202
00203 return chr($APEtagFlags[3]).chr($APEtagFlags[2]).chr($APEtagFlags[1]).chr($APEtagFlags[0]);
00204 }
00205
00206 function CleanAPEtagItemKey($itemkey) {
00207 $itemkey = eregi_replace("[^\x20-\x7E]", '', $itemkey);
00208
00209
00210 switch (strtoupper($itemkey)) {
00211 case 'EAN/UPC':
00212 case 'ISBN':
00213 case 'LC':
00214 case 'ISRC':
00215 $itemkey = strtoupper($itemkey);
00216 break;
00217
00218 default:
00219 $itemkey = ucwords($itemkey);
00220 break;
00221 }
00222 return $itemkey;
00223
00224 }
00225
00226 }
00227
00228 ?>