// // CueSheet.m // CueSheet // // Created by Zaphod Beeblebrox on 10/8/07. // Copyright 2007 __MyCompanyName__. All rights reserved. // #import "CueSheet.h" #import "CueSheetTrack.h" @implementation CueSheet + (id)cueSheetWithFile:(NSString *)filename { return [[[CueSheet alloc] initWithFile:filename] autorelease]; } - (NSURL *)urlForPath:(NSString *)path relativeTo:(NSString *)baseFilename { if ([path hasPrefix:@"/"]) { return [NSURL fileURLWithPath:path]; } NSRange foundRange = [path rangeOfString:@"://"]; if (foundRange.location != NSNotFound) { return [NSURL URLWithString:path]; } NSString *basePath = [[[baseFilename stringByStandardizingPath] stringByDeletingLastPathComponent] stringByAppendingString:@"/"]; NSMutableString *unixPath = [path mutableCopy]; //Only relative paths would have windows backslashes. [unixPath replaceOccurrencesOfString:@"\\" withString:@"/" options:0 range:NSMakeRange(0, [unixPath length])]; return [NSURL fileURLWithPath:[basePath stringByAppendingString:[unixPath autorelease]]]; } - (void)parseFile:(NSString *)filename { NSError *error = nil; NSString *contents = [NSString stringWithContentsOfFile:filename encoding:NSUTF8StringEncoding error:&error]; if (error || !contents) { NSLog(@"Could not open file...%@ %@ %@", filename, contents, error); return; } NSMutableArray *entries = [[NSMutableArray alloc] init]; NSString *track = nil; NSString *path = nil; BOOL trackAdded = NO; NSCharacterSet *whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet]; NSString *line; NSScanner *scanner = nil; NSEnumerator *e = [[contents componentsSeparatedByString:@"\n"] objectEnumerator]; while (line = [e nextObject]) { [scanner release]; scanner = [[NSScanner alloc] initWithString:line]; NSString *command; if (![scanner scanUpToCharactersFromSet:whitespace intoString:&command]) { continue; } //FILE "filename.shn" WAVE if ([command isEqualToString:@"FILE"]) { track = nil; trackAdded = NO; if (![scanner scanString:@"\"" intoString:&command]) { continue; } //Read in the path if (![scanner scanUpToString:@"\"" intoString:&path]) { continue; } } //TRACK 01 AUDIO else if ([command isEqualToString:@"TRACK"]) { trackAdded = NO; if (![scanner scanUpToCharactersFromSet:whitespace intoString:&track]) { continue; } NSString *type = nil; if (![scanner scanUpToCharactersFromSet:whitespace intoString:&type] || ![type isEqualToString:@"AUDIO"]) { continue; } } //INDEX 01 00:00:10 //Note that time is written in Minutes:Seconds:Frames, where frames are 1/75 of a second else if ([command isEqualToString:@"INDEX"]) { if (trackAdded) { continue; } if (!path) { continue; } NSString *index = nil; if (![scanner scanUpToCharactersFromSet:whitespace intoString:&index] || [index intValue] != 1) { continue; } NSLog(@"Index: %@", index); [scanner scanCharactersFromSet:whitespace intoString:nil]; NSString *time = nil; if (![scanner scanUpToCharactersFromSet:whitespace intoString:&time]) { continue; } NSArray *msf = [time componentsSeparatedByString:@":"]; if ([msf count] != 3) { continue; } double seconds = (60*[[msf objectAtIndex:0] intValue]) + [[msf objectAtIndex:1] intValue] + ([[msf objectAtIndex:2] floatValue]/75); if (track == nil) { track = @"01"; } //Need to add basePath, and convert to URL [entries addObject: [CueSheetTrack trackWithURL:[self urlForPath:path relativeTo:filename] track: track time: seconds]]; trackAdded = YES; } } [scanner release]; tracks = [entries copy]; [entries release]; } - (id)initWithFile:(NSString *)filename { self = [super init]; if (self) { [self parseFile:filename]; } return self; } - (NSArray *)tracks { return tracks; } - (CueSheetTrack *)track:(NSString *)fragment { CueSheetTrack *t; NSEnumerator *e = [tracks objectEnumerator]; while (t = [e nextObject]) { if ([[t track] isEqualToString:fragment]) { return t; } } return nil; } @end