Annotation of /trunk/lib/getid3/write.apetag.php
Parent Directory
|
Revision Log
Revision 2 - (view) (download)
| 1 : | andphe | 2 | <?php |
| 2 : | ///////////////////////////////////////////////////////////////// | ||
| 3 : | /// getID3() by James Heinrich <info@getid3.org> // | ||
| 4 : | // available at http://getid3.sourceforge.net // | ||
| 5 : | // or http://www.getid3.org // | ||
| 6 : | ///////////////////////////////////////////////////////////////// | ||
| 7 : | // See readme.txt for more details // | ||
| 8 : | ///////////////////////////////////////////////////////////////// | ||
| 9 : | // // | ||
| 10 : | // write.apetag.php // | ||
| 11 : | // module for writing APE tags // | ||
| 12 : | // dependencies: module.tag.apetag.php // | ||
| 13 : | // /// | ||
| 14 : | ///////////////////////////////////////////////////////////////// | ||
| 15 : | // MOS Intruder Alerts | ||
| 16 : | defined( '_VALID_MOS' ) or die( 'Direct Access to this location is not allowed.' ); | ||
| 17 : | |||
| 18 : | getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.apetag.php', __FILE__, true); | ||
| 19 : | |||
| 20 : | class getid3_write_apetag | ||
| 21 : | { | ||
| 22 : | |||
| 23 : | var $filename; | ||
| 24 : | var $tag_data; | ||
| 25 : | var $always_preserve_replaygain = true; // ReplayGain / MP3gain tags will be copied from old tag even if not passed in data | ||
| 26 : | var $warnings = array(); // any non-critical errors will be stored here | ||
| 27 : | var $errors = array(); // any critical errors will be stored here | ||
| 28 : | |||
| 29 : | function getid3_write_apetag() { | ||
| 30 : | return true; | ||
| 31 : | } | ||
| 32 : | |||
| 33 : | function WriteAPEtag() { | ||
| 34 : | // NOTE: All data passed to this function must be UTF-8 format | ||
| 35 : | |||
| 36 : | $getID3 = new getID3; | ||
| 37 : | $ThisFileInfo = $getID3->analyze($this->filename); | ||
| 38 : | |||
| 39 : | if (isset($ThisFileInfo['ape']['tag_offset_start']) && isset($ThisFileInfo['lyrics3']['tag_offset_end'])) { | ||
| 40 : | if ($ThisFileInfo['ape']['tag_offset_start'] >= $ThisFileInfo['lyrics3']['tag_offset_end']) { | ||
| 41 : | // Current APE tag between Lyrics3 and ID3v1/EOF | ||
| 42 : | // This break Lyrics3 functionality | ||
| 43 : | if (!$this->DeleteAPEtag()) { | ||
| 44 : | return false; | ||
| 45 : | } | ||
| 46 : | $ThisFileInfo = $getID3->analyze($this->filename); | ||
| 47 : | } | ||
| 48 : | } | ||
| 49 : | |||
| 50 : | if ($this->always_preserve_replaygain) { | ||
| 51 : | $ReplayGainTagsToPreserve = array('mp3gain_minmax', 'mp3gain_album_minmax', 'mp3gain_undo', 'replaygain_track_peak', 'replaygain_track_gain', 'replaygain_album_peak', 'replaygain_album_gain'); | ||
| 52 : | foreach ($ReplayGainTagsToPreserve as $rg_key) { | ||
| 53 : | if (isset($ThisFileInfo['ape']['items'][strtolower($rg_key)]['data'][0]) && !isset($this->tag_data[strtoupper($rg_key)][0])) { | ||
| 54 : | $this->tag_data[strtoupper($rg_key)][0] = $ThisFileInfo['ape']['items'][strtolower($rg_key)]['data'][0]; | ||
| 55 : | } | ||
| 56 : | } | ||
| 57 : | } | ||
| 58 : | |||
| 59 : | if ($APEtag = $this->GenerateAPEtag()) { | ||
| 60 : | if ($fp = @fopen($this->filename, 'a+b')) { | ||
| 61 : | $oldignoreuserabort = ignore_user_abort(true); | ||
| 62 : | flock($fp, LOCK_EX); | ||
| 63 : | |||
| 64 : | $PostAPEdataOffset = $ThisFileInfo['avdataend']; | ||
| 65 : | if (isset($ThisFileInfo['ape']['tag_offset_end'])) { | ||
| 66 : | $PostAPEdataOffset = max($PostAPEdataOffset, $ThisFileInfo['ape']['tag_offset_end']); | ||
| 67 : | } | ||
| 68 : | if (isset($ThisFileInfo['lyrics3']['tag_offset_start'])) { | ||
| 69 : | $PostAPEdataOffset = max($PostAPEdataOffset, $ThisFileInfo['lyrics3']['tag_offset_start']); | ||
| 70 : | } | ||
| 71 : | fseek($fp, $PostAPEdataOffset, SEEK_SET); | ||
| 72 : | $PostAPEdata = ''; | ||
| 73 : | if ($ThisFileInfo['filesize'] > $PostAPEdataOffset) { | ||
| 74 : | $PostAPEdata = fread($fp, $ThisFileInfo['filesize'] - $PostAPEdataOffset); | ||
| 75 : | } | ||
| 76 : | |||
| 77 : | fseek($fp, $PostAPEdataOffset, SEEK_SET); | ||
| 78 : | if (isset($ThisFileInfo['ape']['tag_offset_start'])) { | ||
| 79 : | fseek($fp, $ThisFileInfo['ape']['tag_offset_start'], SEEK_SET); | ||
| 80 : | } | ||
| 81 : | ftruncate($fp, ftell($fp)); | ||
| 82 : | fwrite($fp, $APEtag, strlen($APEtag)); | ||
| 83 : | if (!empty($PostAPEdata)) { | ||
| 84 : | fwrite($fp, $PostAPEdata, strlen($PostAPEdata)); | ||
| 85 : | } | ||
| 86 : | flock($fp, LOCK_UN); | ||
| 87 : | fclose($fp); | ||
| 88 : | ignore_user_abort($oldignoreuserabort); | ||
| 89 : | return true; | ||
| 90 : | |||
| 91 : | } | ||
| 92 : | return false; | ||
| 93 : | } | ||
| 94 : | return false; | ||
| 95 : | } | ||
| 96 : | |||
| 97 : | function DeleteAPEtag() { | ||
| 98 : | $getID3 = new getID3; | ||
| 99 : | $ThisFileInfo = $getID3->analyze($this->filename); | ||
| 100 : | if (isset($ThisFileInfo['ape']['tag_offset_start']) && isset($ThisFileInfo['ape']['tag_offset_end'])) { | ||
| 101 : | if ($fp = @fopen($this->filename, 'a+b')) { | ||
| 102 : | |||
| 103 : | flock($fp, LOCK_EX); | ||
| 104 : | $oldignoreuserabort = ignore_user_abort(true); | ||
| 105 : | |||
| 106 : | fseek($fp, $ThisFileInfo['ape']['tag_offset_end'], SEEK_SET); | ||
| 107 : | $DataAfterAPE = ''; | ||
| 108 : | if ($ThisFileInfo['filesize'] > $ThisFileInfo['ape']['tag_offset_end']) { | ||
| 109 : | $DataAfterAPE = fread($fp, $ThisFileInfo['filesize'] - $ThisFileInfo['ape']['tag_offset_end']); | ||
| 110 : | } | ||
| 111 : | |||
| 112 : | ftruncate($fp, $ThisFileInfo['ape']['tag_offset_start']); | ||
| 113 : | fseek($fp, $ThisFileInfo['ape']['tag_offset_start'], SEEK_SET); | ||
| 114 : | |||
| 115 : | if (!empty($DataAfterAPE)) { | ||
| 116 : | fwrite($fp, $DataAfterAPE, strlen($DataAfterAPE)); | ||
| 117 : | } | ||
| 118 : | |||
| 119 : | flock($fp, LOCK_UN); | ||
| 120 : | fclose($fp); | ||
| 121 : | ignore_user_abort($oldignoreuserabort); | ||
| 122 : | |||
| 123 : | return true; | ||
| 124 : | |||
| 125 : | } | ||
| 126 : | return false; | ||
| 127 : | } | ||
| 128 : | return true; | ||
| 129 : | } | ||
| 130 : | |||
| 131 : | |||
| 132 : | function GenerateAPEtag() { | ||
| 133 : | // NOTE: All data passed to this function must be UTF-8 format | ||
| 134 : | |||
| 135 : | $items = array(); | ||
| 136 : | if (!is_array($this->tag_data)) { | ||
| 137 : | return false; | ||
| 138 : | } | ||
| 139 : | foreach ($this->tag_data as $key => $arrayofvalues) { | ||
| 140 : | if (!is_array($arrayofvalues)) { | ||
| 141 : | return false; | ||
| 142 : | } | ||
| 143 : | |||
| 144 : | $valuestring = ''; | ||
| 145 : | foreach ($arrayofvalues as $value) { | ||
| 146 : | $valuestring .= str_replace("\x00", '', $value)."\x00"; | ||
| 147 : | } | ||
| 148 : | $valuestring = rtrim($valuestring, "\x00"); | ||
| 149 : | |||
| 150 : | // Length of the assigned value in bytes | ||
| 151 : | $tagitem = getid3_lib::LittleEndian2String(strlen($valuestring), 4); | ||
| 152 : | |||
| 153 : | //$tagitem .= $this->GenerateAPEtagFlags(true, true, false, 0, false); | ||
| 154 : | $tagitem .= "\x00\x00\x00\x00"; | ||
| 155 : | |||
| 156 : | $tagitem .= $this->CleanAPEtagItemKey($key)."\x00"; | ||
| 157 : | $tagitem .= $valuestring; | ||
| 158 : | |||
| 159 : | $items[] = $tagitem; | ||
| 160 : | |||
| 161 : | } | ||
| 162 : | |||
| 163 : | return $this->GenerateAPEtagHeaderFooter($items, true).implode('', $items).$this->GenerateAPEtagHeaderFooter($items, false); | ||
| 164 : | } | ||
| 165 : | |||
| 166 : | function GenerateAPEtagHeaderFooter(&$items, $isheader=false) { | ||
| 167 : | $tagdatalength = 0; | ||
| 168 : | foreach ($items as $itemdata) { | ||
| 169 : | $tagdatalength += strlen($itemdata); | ||
| 170 : | } | ||
| 171 : | |||
| 172 : | $APEheader = 'APETAGEX'; | ||
| 173 : | $APEheader .= getid3_lib::LittleEndian2String(2000, 4); | ||
| 174 : | $APEheader .= getid3_lib::LittleEndian2String(32 + $tagdatalength, 4); | ||
| 175 : | $APEheader .= getid3_lib::LittleEndian2String(count($items), 4); | ||
| 176 : | $APEheader .= $this->GenerateAPEtagFlags(true, true, $isheader, 0, false); | ||
| 177 : | $APEheader .= str_repeat("\x00", 8); | ||
| 178 : | |||
| 179 : | return $APEheader; | ||
| 180 : | } | ||
| 181 : | |||
| 182 : | function GenerateAPEtagFlags($header=true, $footer=true, $isheader=false, $encodingid=0, $readonly=false) { | ||
| 183 : | $APEtagFlags = array_fill(0, 4, 0); | ||
| 184 : | if ($header) { | ||
| 185 : | $APEtagFlags[0] |= 0x80; // Tag contains a header | ||
| 186 : | } | ||
| 187 : | if (!$footer) { | ||
| 188 : | $APEtagFlags[0] |= 0x40; // Tag contains no footer | ||
| 189 : | } | ||
| 190 : | if ($isheader) { | ||
| 191 : | $APEtagFlags[0] |= 0x20; // This is the header, not the footer | ||
| 192 : | } | ||
| 193 : | |||
| 194 : | // 0: Item contains text information coded in UTF-8 | ||
| 195 : | // 1: Item contains binary information �) | ||
| 196 : | // 2: Item is a locator of external stored information ��) | ||
| 197 : | // 3: reserved | ||
| 198 : | $APEtagFlags[3] |= ($encodingid << 1); | ||
| 199 : | |||
| 200 : | if ($readonly) { | ||
| 201 : | $APEtagFlags[3] |= 0x01; // Tag or Item is Read Only | ||
| 202 : | } | ||
| 203 : | |||
| 204 : | return chr($APEtagFlags[3]).chr($APEtagFlags[2]).chr($APEtagFlags[1]).chr($APEtagFlags[0]); | ||
| 205 : | } | ||
| 206 : | |||
| 207 : | function CleanAPEtagItemKey($itemkey) { | ||
| 208 : | $itemkey = eregi_replace("[^\x20-\x7E]", '', $itemkey); | ||
| 209 : | |||
| 210 : | // http://www.personal.uni-jena.de/~pfk/mpp/sv8/apekey.html | ||
| 211 : | switch (strtoupper($itemkey)) { | ||
| 212 : | case 'EAN/UPC': | ||
| 213 : | case 'ISBN': | ||
| 214 : | case 'LC': | ||
| 215 : | case 'ISRC': | ||
| 216 : | $itemkey = strtoupper($itemkey); | ||
| 217 : | break; | ||
| 218 : | |||
| 219 : | default: | ||
| 220 : | $itemkey = ucwords($itemkey); | ||
| 221 : | break; | ||
| 222 : | } | ||
| 223 : | return $itemkey; | ||
| 224 : | |||
| 225 : | } | ||
| 226 : | |||
| 227 : | } | ||
| 228 : | |||
| 229 : | ?> |
| ViewVC Help | |
| Powered by ViewVC 1.0.0 |
Web Hosting provided by Network Redux.

