oolite/ResourceManager.m
2005-05-04 11:12:07 +00:00

527 lines
18 KiB
Objective-C

//
// ResourceManager.m
// Oolite
//
/*
*
* Oolite
*
* Created by Giles Williams on Sat Apr 03 2004.
* Copyright (c) 2004 for aegidian.org. All rights reserved.
*
Copyright (c) 2004, Giles C Williams
All rights reserved.
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike License.
To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/2.0/
or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
You are free:
• to copy, distribute, display, and perform the work
• to make derivative works
Under the following conditions:
• Attribution. You must give the original author credit.
• Noncommercial. You may not use this work for commercial purposes.
• Share Alike. If you alter, transform, or build upon this work,
you may distribute the resulting work only under a license identical to this one.
For any reuse or distribution, you must make clear to others the license terms of this work.
Any of these conditions can be waived if you get permission from the copyright holder.
Your fair use and other rights are in no way affected by the above.
*/
#import "ResourceManager.h"
#ifdef GNUSTEP
#import "Comparison.h"
#import "OOSound.h"
#import "OOMusic.h"
#endif
@implementation ResourceManager
static NSMutableArray* saved_paths;
static NSString* errors;
- (id) init
{
self = [super init];
always_include_addons = YES;
paths = [[ResourceManager paths] retain];
errors = nil;
return self;
}
- (id) initIncludingAddOns: (BOOL) include_addons;
{
self = [super init];
always_include_addons = include_addons;
paths = [[ResourceManager paths] retain];
errors = nil;
return self;
}
// caches allow us to load any given file once only
//
NSMutableDictionary* dictionary_cache;
NSMutableDictionary* array_cache;
NSMutableDictionary* image_cache;
NSMutableDictionary* sound_cache;
NSMutableDictionary* string_cache;
NSMutableDictionary* movie_cache;
- (void) dealloc
{
if (paths) [paths release];
// if (dictionary_cache) [dictionary_cache release];
// if (array_cache) [array_cache release];
// if (image_cache) [image_cache release];
// if (sound_cache) [sound_cache release];
[super dealloc];
}
+ (NSString *) errors
{
return errors;
}
+ (NSMutableArray *) paths
{
return [ResourceManager pathsUsingAddOns:always_include_addons];
}
+ (NSMutableArray *) pathsUsingAddOns:(BOOL) include_addons
{
// check if we need to clear the caches
if (always_include_addons != include_addons)
{
// clear the caches
if (dictionary_cache) [dictionary_cache release];
if (array_cache) [array_cache release];
if (image_cache) [image_cache release];
if (sound_cache) [sound_cache release];
if (string_cache) [string_cache release];
if (movie_cache) [movie_cache release];
dictionary_cache = nil;
array_cache = nil;
image_cache = nil;
sound_cache = nil;
string_cache = nil;
movie_cache = nil;
// set flag for further accesses
always_include_addons = include_addons;
//
[saved_paths release];
saved_paths = nil;
}
//
int i;
if (saved_paths)
return saved_paths;
if (errors)
{
[errors release];
errors = nil;
}
NSString *app_path = [[[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"Contents"] stringByAppendingPathComponent:@"Resources"];
NSString *addon_path = [[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"AddOns"];
NSMutableArray *file_paths = [NSMutableArray arrayWithCapacity:16];
[file_paths addObject:app_path];
if (include_addons)
{
[file_paths addObject:addon_path];
NSArray *possibleExpansions = [[NSFileManager defaultManager] directoryContentsAtPath:addon_path];
for (i = 0; i < [possibleExpansions count]; i++)
{
NSString *item = (NSString *)[possibleExpansions objectAtIndex:i];
if (([[item pathExtension] isEqual:@"oxp"])||([[item pathExtension] isEqual:@"oolite_expansion_pack"]))
{
BOOL require_test;
BOOL dir_test;
NSString *possibleExpansionPath = [addon_path stringByAppendingPathComponent:item];
[[NSFileManager defaultManager] fileExistsAtPath:possibleExpansionPath isDirectory:&dir_test];
if (dir_test)
{
// check for version compatibility
NSString *version = (NSString *)[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
NSString *requiresPath = [possibleExpansionPath stringByAppendingPathComponent:@"requires.plist"];
require_test = YES;
//NSLog(@"DEBUG checking possibleExpansionPath '%@'",possibleExpansionPath);
if ([[NSFileManager defaultManager] fileExistsAtPath:requiresPath])
{
NSDictionary *requirements = [NSDictionary dictionaryWithContentsOfFile:requiresPath];
if ([requirements objectForKey:@"version"])
{
//NSLog(@"DEBUG checking requirements '%@'", [requirements description]);
//NSLog(@"DEBUG checking [requirements objectForKey:@\"version\"] '%@'", [requirements objectForKey:@"version"]);
require_test = ([version isGreaterThanOrEqualTo:[requirements objectForKey:@"version"]]);
}
}
if (require_test)
[file_paths addObject:possibleExpansionPath];
else
{
NSBeep();
NSLog(@"ERROR %@ is incompatible with version %@ of Oolite",possibleExpansionPath,version);
if (!errors)
errors = [[NSString alloc] initWithFormat:@"\t'%@' is incompatible with version %@ of Oolite",[possibleExpansionPath lastPathComponent],version];
else
{
NSString* old_errors = errors;
errors = [[NSString alloc] initWithFormat:@"%@\n\t'%@' is incompatible with version %@ of Oolite",old_errors,[possibleExpansionPath lastPathComponent],version];
[old_errors release];
}
}
}
}
}
}
if (!saved_paths)
saved_paths =[file_paths retain];
NSLog(@"---> searching paths:\n%@", [file_paths description]);
return file_paths;
}
+ (NSDictionary *) dictionaryFromFilesNamed:(NSString *)filename inFolder:(NSString *)foldername andMerge:(BOOL) mergeFiles
{
NSMutableArray *results = [NSMutableArray arrayWithCapacity:16];
NSMutableArray *fpaths = [ResourceManager paths];
int i;
if (!filename)
return nil;
NSString* dict_key = [NSString stringWithFormat:@"%@:%@", foldername, filename];
if (!dictionary_cache)
dictionary_cache = [[NSMutableDictionary alloc] initWithCapacity:32];
if ([dictionary_cache objectForKey:dict_key])
return [NSDictionary dictionaryWithDictionary:(NSDictionary *)[dictionary_cache objectForKey:dict_key]]; // return the cached dictionary
for (i = 0; i < [fpaths count]; i++)
{
NSString *filepath = [(NSString *)[fpaths objectAtIndex:i] stringByAppendingPathComponent:filename];
if ([[NSFileManager defaultManager] fileExistsAtPath:filepath])
{
NSDictionary* found_dic = [NSDictionary dictionaryWithContentsOfFile:filepath];
if (found_dic)
[results addObject:found_dic];
else
NSLog(@"ERROR ***** could not parse %@ as a NSDictionary.", filepath);
}
if (foldername)
{
filepath = [[(NSString *)[fpaths objectAtIndex:i] stringByAppendingPathComponent:foldername] stringByAppendingPathComponent:filename];
if ([[NSFileManager defaultManager] fileExistsAtPath:filepath])
{
NSDictionary* found_dic = [NSDictionary dictionaryWithContentsOfFile:filepath];
if (found_dic)
[results addObject:found_dic];
else
NSLog(@"ERROR ***** could not parse %@ as a NSDictionary.", filepath);
}
}
}
if ([results count] == 0)
return nil;
//NSLog(@"---> ResourceManager found %d file(s) with name '%@' (in folder '%@')", [results count], filename, foldername);
if (!mergeFiles)
return [NSDictionary dictionaryWithDictionary:(NSDictionary *)[results objectAtIndex:[results count] - 1]];
NSMutableDictionary *result = [NSMutableDictionary dictionaryWithCapacity:128];
for (i = 0; i < [results count]; i++)
[result addEntriesFromDictionary:(NSDictionary *)[results objectAtIndex:i]];
if (result)
[dictionary_cache setObject:result forKey:dict_key];
return [NSDictionary dictionaryWithDictionary:result];
}
+ (NSArray *) arrayFromFilesNamed:(NSString *)filename inFolder:(NSString *)foldername andMerge:(BOOL) mergeFiles
{
NSMutableArray *results = [NSMutableArray arrayWithCapacity:16];
NSMutableArray *fpaths = [ResourceManager paths];
int i;
if (!filename)
return nil;
NSString* array_key = [NSString stringWithFormat:@"%@:%@", foldername, filename];
if (!array_cache)
array_cache = [[NSMutableDictionary alloc] initWithCapacity:32];
if ([array_cache objectForKey:array_key])
return [NSArray arrayWithArray:(NSArray *)[array_cache objectForKey:array_key]]; // return the cached array
for (i = 0; i < [fpaths count]; i++)
{
NSString *filepath = [(NSString *)[fpaths objectAtIndex:i] stringByAppendingPathComponent:filename];
if ([[NSFileManager defaultManager] fileExistsAtPath:filepath])
{
NSArray* found_array = [NSArray arrayWithContentsOfFile:filepath];
if (found_array)
[results addObject:found_array];
else
NSLog(@"ERROR ***** could not parse %@ as a NSArray.", filepath);
}
// [results addObject:[NSArray arrayWithContentsOfFile:filepath]];
if (foldername)
{
filepath = [[(NSString *)[fpaths objectAtIndex:i] stringByAppendingPathComponent:foldername] stringByAppendingPathComponent:filename];
if ([[NSFileManager defaultManager] fileExistsAtPath:filepath])
{
NSArray* found_array = [NSArray arrayWithContentsOfFile:filepath];
if (found_array)
[results addObject:found_array];
else
NSLog(@"ERROR ***** could not parse %@ as a NSArray.", filepath);
}
// [results addObject:[NSArray arrayWithContentsOfFile:filepath]];
}
}
if ([results count] == 0)
return nil;
//NSLog(@"---> ResourceManager found %d file(s) with name '%@' (in folder '%@')", [results count], filename, foldername);
if (!mergeFiles)
return [NSArray arrayWithArray:(NSArray *)[results objectAtIndex:[results count] - 1]];
NSMutableArray *result = [NSMutableArray arrayWithCapacity:128];
for (i = 0; i < [results count]; i++)
[result addObjectsFromArray:(NSArray *)[results objectAtIndex:i]];
if (result)
[array_cache setObject:result forKey:array_key];
return [NSArray arrayWithArray:result];
}
+ (NSSound *) soundNamed:(NSString *)filename inFolder:(NSString *)foldername
{
NSSound *result = nil;
NSMutableArray *fpaths = [ResourceManager paths];
int i, r;
r = 0;
if (!filename)
return nil;
NSString* sound_key = [NSString stringWithFormat:@"%@:%@", foldername, filename];
if (!sound_cache)
sound_cache = [[NSMutableDictionary alloc] initWithCapacity:32];
if ([sound_cache objectForKey:sound_key])
return (NSSound *)[sound_cache objectForKey:sound_key]; // return the cached sound
for (i = 0; i < [fpaths count]; i++)
{
NSString *filepath = [(NSString *)[fpaths objectAtIndex:i] stringByAppendingPathComponent:filename];
if ([[NSFileManager defaultManager] fileExistsAtPath:filepath])
{
#ifdef GNUSTEP
result = [[[OOSound alloc] initWithContentsOfFile:filepath byReference:NO] autorelease];
#else
result = [[[NSSound alloc] initWithContentsOfFile:filepath byReference:NO] autorelease];
#endif
r++;
}
if (foldername)
{
filepath = [[(NSString *)[fpaths objectAtIndex:i] stringByAppendingPathComponent:foldername] stringByAppendingPathComponent:filename];
//NSLog(@".... checking filepath '%@' for Sounds", filepath);
if ([[NSFileManager defaultManager] fileExistsAtPath:filepath])
{
#ifdef GNUSTEP
result = [[[OOSound alloc] initWithContentsOfFile:filepath byReference:NO] autorelease];
#else
result = [[[NSSound alloc] initWithContentsOfFile:filepath byReference:NO] autorelease];
#endif
r++;
}
}
}
if (result)
[sound_cache setObject:result forKey:sound_key];
//NSLog(@"---> ResourceManager found %d file(s) with name '%@' (in folder '%@')", r, filename, foldername);
return result;
}
+ (NSImage *) imageNamed:(NSString *)filename inFolder:(NSString *)foldername
{
NSImage *result = nil;
NSMutableArray *fpaths = [ResourceManager paths];
int i, r;
r = 0;
if (!filename)
return nil;
NSString* image_key = [NSString stringWithFormat:@"%@:%@", foldername, filename];
if (!image_cache)
image_cache = [[NSMutableDictionary alloc] initWithCapacity:32];
if ([image_cache objectForKey:image_key])
return (NSImage *)[image_cache objectForKey:image_key]; // return the cached image
for (i = 0; i < [fpaths count]; i++)
{
NSString *filepath = [(NSString *)[fpaths objectAtIndex:i] stringByAppendingPathComponent:filename];
if ([[NSFileManager defaultManager] fileExistsAtPath:filepath])
{
result = [[[NSImage alloc] initWithContentsOfFile:filepath] autorelease];
r++;
}
if (foldername)
{
filepath = [[(NSString *)[fpaths objectAtIndex:i] stringByAppendingPathComponent:foldername] stringByAppendingPathComponent:filename];
if ([[NSFileManager defaultManager] fileExistsAtPath:filepath])
{
result = [[[NSImage alloc] initWithContentsOfFile:filepath] autorelease];
r++;
}
}
}
if (result)
[image_cache setObject:result forKey:image_key];
//NSLog(@"---> ResourceManager found %d file(s) with name '%@' (in folder '%@')", r, filename, foldername);
return result;
}
+ (NSString *) stringFromFilesNamed:(NSString *)filename inFolder:(NSString *)foldername
{
NSString *result = nil;
NSMutableArray *fpaths = [ResourceManager paths];
int i, r;
r = 0;
if (!filename)
return nil;
NSString* string_key = [NSString stringWithFormat:@"%@:%@", foldername, filename];
if (!string_cache)
string_cache = [[NSMutableDictionary alloc] initWithCapacity:32];
if ([string_cache objectForKey:string_key])
return (NSString *)[string_cache objectForKey:string_key]; // return the cached string
for (i = 0; i < [fpaths count]; i++)
{
NSString *filepath = [(NSString *)[fpaths objectAtIndex:i] stringByAppendingPathComponent:filename];
if ([[NSFileManager defaultManager] fileExistsAtPath:filepath])
{
result = [NSString stringWithContentsOfFile:filepath];
r++;
}
if (foldername)
{
filepath = [[(NSString *)[fpaths objectAtIndex:i] stringByAppendingPathComponent:foldername] stringByAppendingPathComponent:filename];
if ([[NSFileManager defaultManager] fileExistsAtPath:filepath])
{
result = [NSString stringWithContentsOfFile:filepath];
r++;
}
}
}
if (result)
[string_cache setObject:result forKey:string_key];
//NSLog(@"---> ResourceManager found %d file(s) with name '%@' (in folder '%@')", r, filename, foldername);
return result;
}
#ifdef GNUSTEP
+ (id) movieFromFilesNamed:(NSString *)filename inFolder:(NSString *)foldername
{
OOMusic *result = nil;
NSMutableArray *fpaths = [ResourceManager paths];
int i, r;
r = 0;
if (!filename)
return nil;
NSString* movie_key = [NSString stringWithFormat:@"%@:%@", foldername, filename];
if (!movie_cache)
movie_cache = [[NSMutableDictionary alloc] initWithCapacity:32];
if ([movie_cache objectForKey:movie_key])
return (id)[movie_cache objectForKey:movie_key]; // return the cached movie
for (i = 0; i < [fpaths count]; i++)
{
NSString *filepath = [(NSString *)[fpaths objectAtIndex:i] stringByAppendingPathComponent:filename];
if ([[NSFileManager defaultManager] fileExistsAtPath:filepath])
result = [[OOMusic alloc] initWithContentsOfFile:filepath];
if (foldername)
{
filepath = [[(NSString *)[fpaths objectAtIndex:i] stringByAppendingPathComponent:foldername] stringByAppendingPathComponent:filename];
if ([[NSFileManager defaultManager] fileExistsAtPath:filepath])
{
//NSLog(@"DEBUG ResourceManager found %@ at %@",filename,filepath);
if (result)
[result release];
result = [[OOMusic alloc] initWithContentsOfFile:filepath];
}
}
}
//NSLog(@"---> ResourceManager found %d file(s) with name '%@' (in folder '%@')", r, filename, foldername);
if (result)
[movie_cache setObject:result forKey:movie_key];
return [result autorelease];
}
#else
+ (NSMovie *) movieFromFilesNamed:(NSString *)filename inFolder:(NSString *)foldername
{
NSMovie *result = nil;
NSMutableArray *fpaths = [ResourceManager paths];
int i, r;
r = 0;
if (!filename)
return nil;
NSString* movie_key = [NSString stringWithFormat:@"%@:%@", foldername, filename];
if (!movie_cache)
movie_cache = [[NSMutableDictionary alloc] initWithCapacity:32];
if ([movie_cache objectForKey:movie_key])
return (NSMovie *)[movie_cache objectForKey:movie_key]; // return the cached movie
for (i = 0; i < [fpaths count]; i++)
{
NSString *filepath = [(NSString *)[fpaths objectAtIndex:i] stringByAppendingPathComponent:filename];
if ([[NSFileManager defaultManager] fileExistsAtPath:filepath])
result = [[NSMovie alloc] initWithURL:[NSURL fileURLWithPath: filepath] byReference: NO];
if (foldername)
{
filepath = [[(NSString *)[fpaths objectAtIndex:i] stringByAppendingPathComponent:foldername] stringByAppendingPathComponent:filename];
if ([[NSFileManager defaultManager] fileExistsAtPath:filepath])
{
//NSLog(@"DEBUG ResourceManager found %@ at %@",filename,filepath);
if (result)
[result release];
result = [[NSMovie alloc] initWithURL:[NSURL fileURLWithPath: filepath] byReference: NO];
}
}
}
//NSLog(@"---> ResourceManager found %d file(s) with name '%@' (in folder '%@')", r, filename, foldername);
if ((result == nil)&&([filename hasSuffix:@"mp3"]))
{
// look for an alternative .mid file
NSString *midifilename = [[filename stringByDeletingPathExtension] stringByAppendingPathExtension:@"mid"];
result =[[ResourceManager movieFromFilesNamed:midifilename inFolder:foldername] retain];
}
if (result)
[movie_cache setObject:result forKey:movie_key];
return [result autorelease];
}
#endif
@end