cog/Plugins/APL/APLFile.m

109 lines
3.7 KiB
Objective-C

#import "APLFile.h"
#import "Logging.h"
@implementation APLFile
+ createWithFile:(NSString*)f {
return [[APLFile alloc] initWithFile:f];
}
- (NSString*)readline:(NSFileHandle*)f { // rather hack-style substitution to fgets...
NSMutableData* d = [NSMutableData dataWithCapacity:100]; // it will grow, here should be most expected value (may gain few nanosecond from it =) )
while(true) {
NSData* byte = [f readDataOfLength:1];
if(!byte) {
[f seekToFileOffset:([f offsetInFile] - [d length])];
return nil;
}
[d appendData:byte];
if(*((const char*)[byte bytes]) == '\n') break;
}
NSString* s = [[NSString alloc] initWithData:d encoding:NSUTF8StringEncoding]; //! handle encoding error (in case binary data starts not from newline, impossible on real apl, but who knows...)
return s;
}
- (NSURL*)urlForPath:(NSString*)path relativeTo:(NSString*)baseFilename {
NSRange protocolRange = [path rangeOfString:@"://"];
if(protocolRange.location != NSNotFound)
return [NSURL URLWithString:path];
NSMutableString* unixPath = [path mutableCopy];
if(![unixPath hasPrefix:@"/"]) {
// Only relative paths would have windows backslashes.
[unixPath replaceOccurrencesOfString:@"\\" withString:@"/" options:0 range:NSMakeRange(0, [unixPath length])];
NSString* basePath = [[[baseFilename stringByStandardizingPath] stringByDeletingLastPathComponent] stringByAppendingString:@"/"];
[unixPath insertString:basePath atIndex:0];
}
NSURL* url = [NSURL URLWithString:[[NSURL fileURLWithPath:unixPath] absoluteString]];
return url;
}
- initWithFile:(NSString*)filename {
self = [super init];
if(self) {
// startBlock must be always >= 0
NSFileHandle* f = (NSFileHandle*)[NSFileHandle fileHandleForReadingAtPath:filename];
if(!f) {
ALog(@"Failed to open apl file '%@' for reading", f);
return nil;
}
NSString* header = @"[Monkey's Audio Image Link File]\r\n";
NSData* da = [f readDataOfLength:[header length]];
if(!da) {
ALog(@"Cannot read header");
return nil;
}
NSString* str = [[NSString alloc] initWithData:da encoding:NSASCIIStringEncoding];
if([str compare:header options:NSCaseInsensitiveSearch]) {
ALog(@"APL header mismatch");
return nil;
}
// now read by lines, skip empty, up to line <tagline> (or any starting with '-' - may be other tags can be present)
NSString* line = nil;
NSScanner* scanner = nil;
// NSCharacterSet *whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
while((line = [self readline:f])) {
if(![line compare:@"----- APE TAG (DO NOT TOUCH!!!) -----\r\n" options:NSCaseInsensitiveSearch]) break;
if([line characterAtIndex:0] == '-') break;
scanner = [[NSScanner alloc] initWithString:line];
NSString *field = nil, *value = nil;
if(![scanner scanUpToString:@"=" intoString:&field]) continue;
if(![scanner scanString:@"=" intoString:nil]) continue;
if(![scanner scanUpToString:@"\r\n" intoString:&value]) continue;
if(![field compare:@"Image File" options:NSCaseInsensitiveSearch]) {
file = [self urlForPath:value relativeTo:filename];
DLog(@"APL refers to file '%@' read '%@'", file, value);
continue;
}
if(![field compare:@"Start Block" options:NSCaseInsensitiveSearch]) {
startBlock = [value intValue]; //!!! bugs with files over 2GB
// DLog(@"APL start block %d (%@)", startBlock, value);
continue;
}
if(![field compare:@"Finish Block" options:NSCaseInsensitiveSearch]) {
endBlock = [value intValue]; //!!! bugs with files over 2GB
// DLog(@"APL start block %d (%@)", endBlock, value);
continue;
}
}
// check here for EOF? cocoa does not have this functionality :(
[f closeFile];
}
return self;
}
- (long)startBlock {
return startBlock;
}
- (long)endBlock {
return endBlock;
}
- (NSURL*)file {
return file;
}
@end