00001 <?php
00004
00005
00007
00009
00010
00011
00012
00013
00015
00016 class getid3_write_real
00017 {
00018 var $filename;
00019 var $tag_data = array();
00020 var $warnings = array();
00021 var $errors = array();
00022 var $paddedlength = 512;
00023
00024 function getid3_write_real() {
00025 return true;
00026 }
00027
00028 function WriteReal() {
00029
00030 if (is_writeable($this->filename)) {
00031 if ($fp_source = @fopen($this->filename, 'r+b')) {
00032
00033
00034 $getID3 = new getID3;
00035 $OldThisFileInfo = $getID3->analyze($this->filename);
00036 if (empty($OldThisFileInfo['real']['chunks']) && !empty($OldThisFileInfo['real']['old_ra_header'])) {
00037 $this->errors[] = 'Cannot write Real tags on old-style file format';
00038 fclose($fp_source);
00039 return false;
00040 }
00041
00042 if (empty($OldThisFileInfo['real']['chunks'])) {
00043 $this->errors[] = 'Cannot write Real tags because cannot find DATA chunk in file';
00044 fclose($fp_source);
00045 return false;
00046 }
00047 foreach ($OldThisFileInfo['real']['chunks'] as $chunknumber => $chunkarray) {
00048 $oldChunkInfo[$chunkarray['name']] = $chunkarray;
00049 }
00050 if (!empty($oldChunkInfo['CONT']['length'])) {
00051 $this->paddedlength = max($oldChunkInfo['CONT']['length'], $this->paddedlength);
00052 }
00053
00054 $new_CONT_tag_data = $this->GenerateCONTchunk();
00055 $new_PROP_tag_data = $this->GeneratePROPchunk($OldThisFileInfo['real']['chunks'], $new_CONT_tag_data);
00056 $new__RMF_tag_data = $this->GenerateRMFchunk($OldThisFileInfo['real']['chunks']);
00057
00058 if (@$oldChunkInfo['.RMF']['length'] == strlen($new__RMF_tag_data)) {
00059 fseek($fp_source, $oldChunkInfo['.RMF']['offset'], SEEK_SET);
00060 fwrite($fp_source, $new__RMF_tag_data);
00061 } else {
00062 $this->errors[] = 'new .RMF tag ('.strlen($new__RMF_tag_data).' bytes) different length than old .RMF tag ('.$oldChunkInfo['.RMF']['length'].' bytes)';
00063 fclose($fp_source);
00064 return false;
00065 }
00066
00067 if (@$oldChunkInfo['PROP']['length'] == strlen($new_PROP_tag_data)) {
00068 fseek($fp_source, $oldChunkInfo['PROP']['offset'], SEEK_SET);
00069 fwrite($fp_source, $new_PROP_tag_data);
00070 } else {
00071 $this->errors[] = 'new PROP tag ('.strlen($new_PROP_tag_data).' bytes) different length than old PROP tag ('.$oldChunkInfo['PROP']['length'].' bytes)';
00072 fclose($fp_source);
00073 return false;
00074 }
00075
00076 if (@$oldChunkInfo['CONT']['length'] == strlen($new_CONT_tag_data)) {
00077
00078
00079 fseek($fp_source, $oldChunkInfo['CONT']['offset'], SEEK_SET);
00080 fwrite($fp_source, $new_CONT_tag_data);
00081 fclose($fp_source);
00082 return true;
00083
00084 } else {
00085
00086 if (empty($oldChunkInfo['CONT'])) {
00087
00088 $BeforeOffset = $oldChunkInfo['DATA']['offset'];
00089 $AfterOffset = $oldChunkInfo['DATA']['offset'];
00090 } else {
00091
00092 $BeforeOffset = $oldChunkInfo['CONT']['offset'];
00093 $AfterOffset = $oldChunkInfo['CONT']['offset'] + $oldChunkInfo['CONT']['length'];
00094 }
00095 if ($tempfilename = tempnam('*', 'getID3')) {
00096 ob_start();
00097 if ($fp_temp = fopen($tempfilename, 'wb')) {
00098
00099 rewind($fp_source);
00100 fwrite($fp_temp, fread($fp_source, $BeforeOffset));
00101 fwrite($fp_temp, $new_CONT_tag_data);
00102 fseek($fp_source, $AfterOffset, SEEK_SET);
00103 while ($buffer = fread($fp_source, GETID3_FREAD_BUFFER_SIZE)) {
00104 fwrite($fp_temp, $buffer, strlen($buffer));
00105 }
00106 fclose($fp_temp);
00107
00108 if (copy($tempfilename, $this->filename)) {
00109 unlink($tempfilename);
00110 fclose($fp_source);
00111 return true;
00112 }
00113 unlink($tempfilename);
00114 $this->errors[] = 'FAILED: copy('.$tempfilename.', '.$this->filename.') - '.strip_tags(ob_get_contents());
00115
00116 } else {
00117
00118 $this->errors[] = 'Could not open '.$tempfilename.' mode "wb" - '.strip_tags(ob_get_contents());
00119
00120 }
00121 ob_end_clean();
00122 }
00123 fclose($fp_source);
00124 return false;
00125
00126 }
00127
00128
00129 } else {
00130 $this->errors[] = 'Could not open '.$this->filename.' mode "r+b"';
00131 return false;
00132 }
00133 }
00134 $this->errors[] = 'File is not writeable: '.$this->filename;
00135 return false;
00136 }
00137
00138 function GenerateRMFchunk(&$chunks) {
00139 $oldCONTexists = false;
00140 foreach ($chunks as $key => $chunk) {
00141 $chunkNameKeys[$chunk['name']] = $key;
00142 if ($chunk['name'] == 'CONT') {
00143 $oldCONTexists = true;
00144 }
00145 }
00146 $newHeadersCount = $chunks[$chunkNameKeys['.RMF']]['headers_count'] + ($oldCONTexists ? 0 : 1);
00147
00148 $RMFchunk = "\x00\x00";
00149 $RMFchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['.RMF']]['file_version'], 4);
00150 $RMFchunk .= getid3_lib::BigEndian2String($newHeadersCount, 4);
00151
00152 $RMFchunk = '.RMF'.getid3_lib::BigEndian2String(strlen($RMFchunk) + 8, 4).$RMFchunk;
00153 return $RMFchunk;
00154 }
00155
00156 function GeneratePROPchunk(&$chunks, &$new_CONT_tag_data) {
00157 $old_CONT_length = 0;
00158 $old_DATA_offset = 0;
00159 $old_INDX_offset = 0;
00160 foreach ($chunks as $key => $chunk) {
00161 $chunkNameKeys[$chunk['name']] = $key;
00162 if ($chunk['name'] == 'CONT') {
00163 $old_CONT_length = $chunk['length'];
00164 } elseif ($chunk['name'] == 'DATA') {
00165 if (!$old_DATA_offset) {
00166 $old_DATA_offset = $chunk['offset'];
00167 }
00168 } elseif ($chunk['name'] == 'INDX') {
00169 if (!$old_INDX_offset) {
00170 $old_INDX_offset = $chunk['offset'];
00171 }
00172 }
00173 }
00174 $CONTdelta = strlen($new_CONT_tag_data) - $old_CONT_length;
00175
00176 $PROPchunk = "\x00\x00";
00177 $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['max_bit_rate'], 4);
00178 $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['avg_bit_rate'], 4);
00179 $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['max_packet_size'], 4);
00180 $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['avg_packet_size'], 4);
00181 $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['num_packets'], 4);
00182 $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['duration'], 4);
00183 $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['preroll'], 4);
00184 $PROPchunk .= getid3_lib::BigEndian2String(max(0, $old_INDX_offset + $CONTdelta), 4);
00185 $PROPchunk .= getid3_lib::BigEndian2String(max(0, $old_DATA_offset + $CONTdelta), 4);
00186 $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['num_streams'], 2);
00187 $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['flags_raw'], 2);
00188
00189 $PROPchunk = 'PROP'.getid3_lib::BigEndian2String(strlen($PROPchunk) + 8, 4).$PROPchunk;
00190 return $PROPchunk;
00191 }
00192
00193 function GenerateCONTchunk() {
00194 foreach ($this->tag_data as $key => $value) {
00195
00196 $this->tag_data[$key] = substr($value, 0, 65535);
00197 }
00198
00199 $CONTchunk = "\x00\x00";
00200
00201 $CONTchunk .= getid3_lib::BigEndian2String(strlen(@$this->tag_data['title']), 2);
00202 $CONTchunk .= @$this->tag_data['title'];
00203
00204 $CONTchunk .= getid3_lib::BigEndian2String(strlen(@$this->tag_data['artist']), 2);
00205 $CONTchunk .= @$this->tag_data['artist'];
00206
00207 $CONTchunk .= getid3_lib::BigEndian2String(strlen(@$this->tag_data['copyright']), 2);
00208 $CONTchunk .= @$this->tag_data['copyright'];
00209
00210 $CONTchunk .= getid3_lib::BigEndian2String(strlen(@$this->tag_data['comment']), 2);
00211 $CONTchunk .= @$this->tag_data['comment'];
00212
00213 if ($this->paddedlength > (strlen($CONTchunk) + 8)) {
00214 $CONTchunk .= str_repeat("\x00", $this->paddedlength - strlen($CONTchunk) - 8);
00215 }
00216
00217 $CONTchunk = 'CONT'.getid3_lib::BigEndian2String(strlen($CONTchunk) + 8, 4).$CONTchunk;
00218
00219 return $CONTchunk;
00220 }
00221
00222 function RemoveReal() {
00223
00224 if (is_writeable($this->filename)) {
00225 if ($fp_source = @fopen($this->filename, 'r+b')) {
00226
00227
00228 $getID3 = new getID3;
00229 $OldThisFileInfo = $getID3->analyze($this->filename);
00230 if (empty($OldThisFileInfo['real']['chunks']) && !empty($OldThisFileInfo['real']['old_ra_header'])) {
00231 $this->errors[] = 'Cannot remove Real tags from old-style file format';
00232 fclose($fp_source);
00233 return false;
00234 }
00235
00236 if (empty($OldThisFileInfo['real']['chunks'])) {
00237 $this->errors[] = 'Cannot remove Real tags because cannot find DATA chunk in file';
00238 fclose($fp_source);
00239 return false;
00240 }
00241 foreach ($OldThisFileInfo['real']['chunks'] as $chunknumber => $chunkarray) {
00242 $oldChunkInfo[$chunkarray['name']] = $chunkarray;
00243 }
00244
00245 if (empty($oldChunkInfo['CONT'])) {
00246
00247 fclose($fp_source);
00248 return true;
00249 }
00250
00251 $BeforeOffset = $oldChunkInfo['CONT']['offset'];
00252 $AfterOffset = $oldChunkInfo['CONT']['offset'] + $oldChunkInfo['CONT']['length'];
00253 if ($tempfilename = tempnam('*', 'getID3')) {
00254 ob_start();
00255 if ($fp_temp = fopen($tempfilename, 'wb')) {
00256
00257 rewind($fp_source);
00258 fwrite($fp_temp, fread($fp_source, $BeforeOffset));
00259 fseek($fp_source, $AfterOffset, SEEK_SET);
00260 while ($buffer = fread($fp_source, GETID3_FREAD_BUFFER_SIZE)) {
00261 fwrite($fp_temp, $buffer, strlen($buffer));
00262 }
00263 fclose($fp_temp);
00264
00265 if (copy($tempfilename, $this->filename)) {
00266 unlink($tempfilename);
00267 fclose($fp_source);
00268 return true;
00269 }
00270 unlink($tempfilename);
00271 $this->errors[] = 'FAILED: copy('.$tempfilename.', '.$this->filename.') - '.strip_tags(ob_get_contents());
00272
00273 } else {
00274
00275 $this->errors[] = 'Could not open '.$tempfilename.' mode "wb" - '.strip_tags(ob_get_contents());
00276
00277 }
00278 ob_end_clean();
00279 }
00280 fclose($fp_source);
00281 return false;
00282
00283
00284 } else {
00285 $this->errors[] = 'Could not open '.$this->filename.' mode "r+b"';
00286 return false;
00287 }
00288 }
00289 $this->errors[] = 'File is not writeable: '.$this->filename;
00290 return false;
00291 }
00292
00293 }
00294
00295 ?>