1<?php 2 3///////////////////////////////////////////////////////////////// 4/// getID3() by James Heinrich <info@getid3.org> // 5// available at https://github.com/JamesHeinrich/getID3 // 6// or https://www.getid3.org // 7// or http://getid3.sourceforge.net // 8// see readme.txt for more details // 9///////////////////////////////////////////////////////////////// 10// // 11// module.misc.cue.php // 12// module for analyzing CUEsheet files // 13// dependencies: NONE // 14// // 15///////////////////////////////////////////////////////////////// 16// // 17// Module originally written [2009-Mar-25] by // 18// Nigel Barnes <ngbarnesØhotmail*com> // 19// Minor reformatting and similar small changes to integrate // 20// into getID3 by James Heinrich <info@getid3.org> // 21// /// 22///////////////////////////////////////////////////////////////// 23 24/* 25 * CueSheet parser by Nigel Barnes. 26 * 27 * This is a PHP conversion of CueSharp 0.5 by Wyatt O'Day (wyday.com/cuesharp) 28 */ 29 30/** 31 * A CueSheet class used to open and parse cuesheets. 32 * 33 */ 34 35if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 36 exit; 37} 38 39class getid3_cue extends getid3_handler 40{ 41 public $cuesheet = array(); 42 43 /** 44 * @return bool 45 */ 46 public function Analyze() { 47 $info = &$this->getid3->info; 48 49 $info['fileformat'] = 'cue'; 50 $this->readCueSheetFilename($info['filenamepath']); 51 $info['cue'] = $this->cuesheet; 52 return true; 53 } 54 55 /** 56 * @param string $filename 57 * 58 * @return array 59 */ 60 public function readCueSheetFilename($filename) 61 { 62 $filedata = file_get_contents($filename); 63 return $this->readCueSheet($filedata); 64 } 65 66 /** 67 * Parses a cue sheet file. 68 * 69 * @param string $filedata 70 * 71 * @return array 72 */ 73 public function readCueSheet(&$filedata) 74 { 75 $cue_lines = array(); 76 foreach (explode("\n", str_replace("\r", null, $filedata)) as $line) 77 { 78 if ( (strlen($line) > 0) && ($line[0] != '#')) 79 { 80 $cue_lines[] = trim($line); 81 } 82 } 83 $this->parseCueSheet($cue_lines); 84 85 return $this->cuesheet; 86 } 87 88 /** 89 * Parses the cue sheet array. 90 * 91 * @param array $file - The cuesheet as an array of each line. 92 */ 93 public function parseCueSheet($file) 94 { 95 //-1 means still global, all others are track specific 96 $track_on = -1; 97 98 for ($i=0; $i < count($file); $i++) 99 { 100 list($key) = explode(' ', strtolower($file[$i]), 2); 101 switch ($key) 102 { 103 case 'catalog': 104 case 'cdtextfile': 105 case 'isrc': 106 case 'performer': 107 case 'songwriter': 108 case 'title': 109 $this->parseString($file[$i], $track_on); 110 break; 111 case 'file': 112 $currentFile = $this->parseFile($file[$i]); 113 break; 114 case 'flags': 115 $this->parseFlags($file[$i], $track_on); 116 break; 117 case 'index': 118 case 'postgap': 119 case 'pregap': 120 $this->parseIndex($file[$i], $track_on); 121 break; 122 case 'rem': 123 $this->parseComment($file[$i], $track_on); 124 break; 125 case 'track': 126 $track_on++; 127 $this->parseTrack($file[$i], $track_on); 128 if (isset($currentFile)) // if there's a file 129 { 130 $this->cuesheet['tracks'][$track_on]['datafile'] = $currentFile; 131 } 132 break; 133 default: 134 //save discarded junk and place string[] with track it was found in 135 $this->parseGarbage($file[$i], $track_on); 136 break; 137 } 138 } 139 } 140 141 /** 142 * Parses the REM command. 143 * 144 * @param string $line - The line in the cue file that contains the TRACK command. 145 * @param integer $track_on - The track currently processing. 146 */ 147 public function parseComment($line, $track_on) 148 { 149 $explodedline = explode(' ', $line, 3); 150 $comment_REM = (isset($explodedline[0]) ? $explodedline[0] : ''); 151 $comment_type = (isset($explodedline[1]) ? $explodedline[1] : ''); 152 $comment_data = (isset($explodedline[2]) ? $explodedline[2] : ''); 153 if (($comment_REM == 'REM') && $comment_type) { 154 $comment_type = strtolower($comment_type); 155 $commment_data = trim($comment_data, ' "'); 156 if ($track_on != -1) { 157 $this->cuesheet['tracks'][$track_on]['comments'][$comment_type][] = $comment_data; 158 } else { 159 $this->cuesheet['comments'][$comment_type][] = $comment_data; 160 } 161 } 162 } 163 164 /** 165 * Parses the FILE command. 166 * 167 * @param string $line - The line in the cue file that contains the FILE command. 168 * 169 * @return array - Array of FILENAME and TYPE of file.. 170 */ 171 public function parseFile($line) 172 { 173 $line = substr($line, strpos($line, ' ') + 1); 174 $type = strtolower(substr($line, strrpos($line, ' '))); 175 176 //remove type 177 $line = substr($line, 0, strrpos($line, ' ') - 1); 178 179 //if quotes around it, remove them. 180 $line = trim($line, '"'); 181 182 return array('filename'=>$line, 'type'=>$type); 183 } 184 185 /** 186 * Parses the FLAG command. 187 * 188 * @param string $line - The line in the cue file that contains the TRACK command. 189 * @param integer $track_on - The track currently processing. 190 */ 191 public function parseFlags($line, $track_on) 192 { 193 if ($track_on != -1) 194 { 195 foreach (explode(' ', strtolower($line)) as $type) 196 { 197 switch ($type) 198 { 199 case 'flags': 200 // first entry in this line 201 $this->cuesheet['tracks'][$track_on]['flags'] = array( 202 '4ch' => false, 203 'data' => false, 204 'dcp' => false, 205 'pre' => false, 206 'scms' => false, 207 ); 208 break; 209 case 'data': 210 case 'dcp': 211 case '4ch': 212 case 'pre': 213 case 'scms': 214 $this->cuesheet['tracks'][$track_on]['flags'][$type] = true; 215 break; 216 default: 217 break; 218 } 219 } 220 } 221 } 222 223 /** 224 * Collect any unidentified data. 225 * 226 * @param string $line - The line in the cue file that contains the TRACK command. 227 * @param integer $track_on - The track currently processing. 228 */ 229 public function parseGarbage($line, $track_on) 230 { 231 if ( strlen($line) > 0 ) 232 { 233 if ($track_on == -1) 234 { 235 $this->cuesheet['garbage'][] = $line; 236 } 237 else 238 { 239 $this->cuesheet['tracks'][$track_on]['garbage'][] = $line; 240 } 241 } 242 } 243 244 /** 245 * Parses the INDEX command of a TRACK. 246 * 247 * @param string $line - The line in the cue file that contains the TRACK command. 248 * @param integer $track_on - The track currently processing. 249 */ 250 public function parseIndex($line, $track_on) 251 { 252 $type = strtolower(substr($line, 0, strpos($line, ' '))); 253 $line = substr($line, strpos($line, ' ') + 1); 254 $number = 0; 255 256 if ($type == 'index') 257 { 258 //read the index number 259 $number = intval(substr($line, 0, strpos($line, ' '))); 260 $line = substr($line, strpos($line, ' ') + 1); 261 } 262 263 //extract the minutes, seconds, and frames 264 $explodedline = explode(':', $line); 265 $minutes = (isset($explodedline[0]) ? $explodedline[0] : ''); 266 $seconds = (isset($explodedline[1]) ? $explodedline[1] : ''); 267 $frames = (isset($explodedline[2]) ? $explodedline[2] : ''); 268 269 switch ($type) { 270 case 'index': 271 $this->cuesheet['tracks'][$track_on][$type][$number] = array('minutes'=>intval($minutes), 'seconds'=>intval($seconds), 'frames'=>intval($frames)); 272 break; 273 case 'pregap': 274 case 'postgap': 275 $this->cuesheet['tracks'][$track_on][$type] = array('minutes'=>intval($minutes), 'seconds'=>intval($seconds), 'frames'=>intval($frames)); 276 break; 277 } 278 } 279 280 /** 281 * @param string $line 282 * @param int $track_on 283 */ 284 public function parseString($line, $track_on) 285 { 286 $category = strtolower(substr($line, 0, strpos($line, ' '))); 287 $line = substr($line, strpos($line, ' ') + 1); 288 289 //get rid of the quotes 290 $line = trim($line, '"'); 291 292 switch ($category) 293 { 294 case 'catalog': 295 case 'cdtextfile': 296 case 'isrc': 297 case 'performer': 298 case 'songwriter': 299 case 'title': 300 if ($track_on == -1) 301 { 302 $this->cuesheet[$category] = $line; 303 } 304 else 305 { 306 $this->cuesheet['tracks'][$track_on][$category] = $line; 307 } 308 break; 309 default: 310 break; 311 } 312 } 313 314 /** 315 * Parses the TRACK command. 316 * 317 * @param string $line - The line in the cue file that contains the TRACK command. 318 * @param integer $track_on - The track currently processing. 319 */ 320 public function parseTrack($line, $track_on) 321 { 322 $line = substr($line, strpos($line, ' ') + 1); 323 $track = ltrim(substr($line, 0, strpos($line, ' ')), '0'); 324 325 //find the data type. 326 $datatype = strtolower(substr($line, strpos($line, ' ') + 1)); 327 328 $this->cuesheet['tracks'][$track_on] = array('track_number'=>$track, 'datatype'=>$datatype); 329 } 330 331} 332 333