#import "SVGKSourceLocalFile.h" #import "SVGKDefine_Private.h" @interface SVGKSourceLocalFile() @property (nonatomic, readwrite) BOOL wasRelative; @end @implementation SVGKSourceLocalFile -(NSString *)keyForAppleDictionaries { return self.filePath; } +(uint64_t) sizeInBytesOfFilePath:(NSString*) filePath { NSError* errorReadingFileAttributes; NSFileManager* fileManager = [NSFileManager defaultManager]; NSDictionary* atts = [fileManager attributesOfItemAtPath:filePath error:&errorReadingFileAttributes]; if( atts == nil ) return -1; else return atts.fileSize; } + (SVGKSourceLocalFile*)sourceFromFilename:(NSString*)p { NSInputStream* stream = [NSInputStream inputStreamWithFileAtPath:p]; //DO NOT DO THIS: let the parser do it at last possible moment (Apple has threading problems otherwise!) [stream open]; SVGKSourceLocalFile* s = [[SVGKSourceLocalFile alloc] initWithInputSteam:stream]; s.filePath = p; s.approximateLengthInBytesOr0 = [self sizeInBytesOfFilePath:p]; return s; } + (SVGKSourceLocalFile *)internalSourceAnywhereInBundle:(NSBundle *)bundle usingName:(NSString *)name { NSParameterAssert(name != nil); /** Apple's File APIs are very very bad and require you to strip the extension HALF the time. The other HALF the time, they fail unless you KEEP the extension. It's a mess! */ NSString *newName = [name stringByDeletingPathExtension]; NSString *extension = [name pathExtension]; if ([@"" isEqualToString:extension]) { extension = @"svg"; } /** First, try to find it in the project BUNDLE (this was HARD CODED at compile time; can never be changed!) */ NSString *pathToFileInBundle = nil; if( bundle != nil ) { pathToFileInBundle = [bundle pathForResource:newName ofType:extension]; } /** Second, try to find it in the Documents folder (this is where Apple expects you to store custom files at runtime) */ NSString* pathToFileInDocumentsFolder = nil; NSString* pathToDocumentsFolder = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; if( pathToDocumentsFolder != nil ) { pathToFileInDocumentsFolder = [[pathToDocumentsFolder stringByAppendingPathComponent:newName] stringByAppendingPathExtension:extension]; if( [[NSFileManager defaultManager] fileExistsAtPath:pathToFileInDocumentsFolder]) ; else pathToFileInDocumentsFolder = nil; // couldn't find a file there } if( pathToFileInBundle == nil && pathToFileInDocumentsFolder == nil ) { SVGKitLogWarn(@"[%@] MISSING FILE (not found in App-bundle, not found in Documents folder), COULD NOT CREATE DOCUMENT: filename = %@, extension = %@", [self class], newName, extension); return nil; } /** Prefer the Documents-folder version over the Bundle version (allows you to have a default, and override at runtime) */ SVGKSourceLocalFile* source = [SVGKSourceLocalFile sourceFromFilename: pathToFileInDocumentsFolder == nil ? pathToFileInBundle : pathToFileInDocumentsFolder]; return source; } + (SVGKSourceLocalFile *)internalSourceAnywhereInBundleUsingName:(NSString *)name { return [self internalSourceAnywhereInBundle:[NSBundle mainBundle] usingName:name]; } -(id)copyWithZone:(NSZone *)zone { id copy = [super copyWithZone:zone]; if( copy ) { /** clone bits */ [copy setFilePath:[self.filePath copy]]; [copy setWasRelative:self.wasRelative]; /** Finally, manually intialize the input stream, as required by super class */ [copy setStream:[NSInputStream inputStreamWithFileAtPath:self.filePath]]; } return copy; } - (SVGKSource *)sourceFromRelativePath:(NSString *)relative { NSString *absolute = ((NSURL*)[NSURL URLWithString:relative relativeToURL:[NSURL fileURLWithPath:self.filePath]]).path; if ([[NSFileManager defaultManager] fileExistsAtPath:absolute]) { SVGKSourceLocalFile* result = [SVGKSourceLocalFile sourceFromFilename:absolute]; result.wasRelative = true; return result; } return nil; } -(NSString *)description { BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:self.filePath]; return [NSString stringWithFormat:@"File: %@%@\"%@\" (%llu bytes)", self.wasRelative? @"(relative) " : @"", fileExists?@"":@"NOT FOUND! ", self.filePath, self.approximateLengthInBytesOr0 ]; } @end