Line data Source code
1 0 : /* 2 : 3 : NSFileManagerOOExtensions.m 4 : 5 : This extends NSFileManager and adds some methods to insulate the 6 : main oolite code from the gory details of creating/chdiring to the 7 : commander save directory. 8 : 9 : Oolite 10 : Copyright (C) 2004-2013 Giles C Williams and contributors 11 : 12 : This program is free software; you can redistribute it and/or 13 : modify it under the terms of the GNU General Public License 14 : as published by the Free Software Foundation; either version 2 15 : of the License, or (at your option) any later version. 16 : 17 : This program is distributed in the hope that it will be useful, 18 : but WITHOUT ANY WARRANTY; without even the implied warranty of 19 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 : GNU General Public License for more details. 21 : 22 : You should have received a copy of the GNU General Public License 23 : along with this program; if not, write to the Free Software 24 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 25 : MA 02110-1301, USA. 26 : 27 : */ 28 : 29 : #include <stdlib.h> 30 : #include <SDL.h> 31 : #import "ResourceManager.h" 32 : #import "OOPListParsing.h" 33 : #import "GameController.h" 34 : #import "NSFileManagerOOExtensions.h" 35 : #import "unzip.h" 36 : 37 : @implementation NSFileManager (OOExtensions) 38 : 39 : - (NSArray *) commanderContentsOfPath:(NSString *)savePath 40 : { 41 : BOOL pathIsDirectory = NO; 42 : if ([[NSFileManager defaultManager] fileExistsAtPath:savePath isDirectory:&pathIsDirectory] && pathIsDirectory) 43 : { 44 : NSMutableArray *contents = [NSMutableArray arrayWithArray:[self oo_directoryContentsAtPath:savePath]]; 45 : 46 : // at this point we should strip out any files not loadable as Oolite saved games 47 : unsigned i; 48 : for (i = 0; i < [contents count]; i++) 49 : { 50 : NSString* path = [savePath stringByAppendingPathComponent: (NSString*)[contents objectAtIndex:i]]; 51 : 52 : // ensure it's not a directory 53 : if (![[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&pathIsDirectory] && pathIsDirectory) 54 : { 55 : 56 : // check file extension 57 : if (![[path pathExtension] isEqual:@"oolite-save"]) 58 : { 59 : [contents removeObjectAtIndex: i--]; 60 : continue; 61 : } 62 : 63 : // check to see if we can parse the file okay 64 : NSDictionary *cdr = OODictionaryFromFile(path); 65 : if (!cdr) 66 : { 67 : OOLog(@"savedGame.read.fail.notDictionary", @">>>> %@ could not be parsed as a saved game.", path); 68 : [contents removeObjectAtIndex: i--]; 69 : continue; 70 : } 71 : } 72 : 73 : // all okay - we can use this path! 74 : [contents replaceObjectAtIndex: i withObject: path]; 75 : 76 : } 77 : 78 : return contents; 79 : } 80 : else 81 : { 82 : OOLogERR(@"savedGame.read.fail.fileNotFound", @"File at path '%@' could not be found.", savePath); 83 : return nil; 84 : } 85 : } 86 : 87 : 88 : - (NSString *) defaultCommanderPath 89 : { 90 : const char *savedirEnv = SDL_getenv("OO_SAVEDIR"); 91 : NSString *savedir; 92 : 93 : if (savedirEnv) 94 : { 95 : savedir = [NSString stringWithUTF8String:savedirEnv]; 96 : } 97 : else 98 : { 99 : savedir = [NSHomeDirectory() stringByAppendingPathComponent:@SAVEDIR]; 100 : } 101 : BOOL pathIsDirectory = NO; 102 : 103 : // does it exist? 104 : if (![[NSFileManager defaultManager] fileExistsAtPath:savedir isDirectory:&pathIsDirectory]) 105 : { 106 : // it doesn't exist. 107 : if([self oo_createDirectoryAtPath:savedir attributes:nil]) 108 : { 109 : return savedir; 110 : } 111 : else 112 : { 113 : OOLogERR(@"savedGame.defaultPath.create.failed", @"Unable to create '%@'. Saved games will go to the home directory.", savedir); 114 : return NSHomeDirectory(); 115 : } 116 : } 117 : 118 : // is it a directory? 119 : if (!pathIsDirectory) 120 : { 121 : OOLogERR(@"savedGame.defaultPath.notDirectory", @"'%@' is not a directory, saved games will go to the home directory.", savedir); 122 : return NSHomeDirectory(); 123 : } 124 : 125 : return savedir; 126 : } 127 : 128 : 129 : #if OOLITE_MAC_OS_X 130 : 131 : - (NSArray *) oo_directoryContentsAtPath:(NSString *)path 132 : { 133 : return [self contentsOfDirectoryAtPath:path error:NULL]; 134 : } 135 : 136 : 137 : - (BOOL) oo_createDirectoryAtPath:(NSString *)path attributes:(NSDictionary *)attributes 138 : { 139 : return [self createDirectoryAtPath:path withIntermediateDirectories:YES attributes:attributes error:NULL]; 140 : } 141 : 142 : 143 : - (NSDictionary *) oo_fileAttributesAtPath:(NSString *)path traverseLink:(BOOL)traverseLink 144 : { 145 : if (traverseLink) 146 : { 147 : NSString *linkDest = nil; 148 : do 149 : { 150 : linkDest = [self destinationOfSymbolicLinkAtPath:path error:NULL]; 151 : if (linkDest != nil) path = linkDest; 152 : } while (linkDest != nil); 153 : } 154 : 155 : return [self attributesOfItemAtPath:path error:NULL]; 156 : } 157 : 158 : 159 : - (NSDictionary *) oo_fileSystemAttributesAtPath:(NSString *)path 160 : { 161 : return [self attributesOfFileSystemForPath:path error:NULL]; 162 : } 163 : 164 : 165 : - (BOOL) oo_removeItemAtPath:(NSString *)path 166 : { 167 : return [self removeItemAtPath:path error:NULL]; 168 : } 169 : 170 : 171 : - (BOOL) oo_moveItemAtPath:(NSString *)src toPath:(NSString *)dest 172 : { 173 : return [self moveItemAtPath:src toPath:dest error:NULL]; 174 : } 175 : 176 : #else 177 : 178 : - (NSArray *) oo_directoryContentsAtPath:(NSString *)path 179 : { 180 : return [self directoryContentsAtPath:path]; 181 : } 182 : 183 : 184 : - (BOOL) oo_createDirectoryAtPath:(NSString *)path attributes:(NSDictionary *)attributes 185 : { 186 : #if OOLITE_WINDOWS && !OOLITE_MODERN_BUILD 187 : return [self createDirectoryAtPath:path attributes:attributes]; 188 : #else 189 : // has been in GNUStep since 2008, so it's probably safe to use now. 190 : // .... why do I say things like that, of course it's not safe - CIM 191 : return [self createDirectoryAtPath:path withIntermediateDirectories:YES attributes:attributes error:NULL]; 192 : #endif 193 : } 194 : 195 : 196 : - (NSDictionary *) oo_fileAttributesAtPath:(NSString *)path traverseLink:(BOOL)yorn 197 : { 198 : return [self fileAttributesAtPath:path traverseLink:yorn]; 199 : } 200 : 201 : 202 : - (NSDictionary *) oo_fileSystemAttributesAtPath:(NSString *)path 203 : { 204 : return [self fileSystemAttributesAtPath:path]; 205 : } 206 : 207 : 208 : - (BOOL) oo_removeItemAtPath:(NSString *)path 209 : { 210 : return [self removeFileAtPath:path handler:nil]; 211 : } 212 : 213 : 214 : - (BOOL) oo_moveItemAtPath:(NSString *)src toPath:(NSString *)dest 215 : { 216 : return [self movePath:src toPath:dest handler:nil]; 217 : } 218 : 219 : #endif 220 : 221 : 222 : #if OOLITE_SDL 223 : - (BOOL) chdirToSnapshotPath 224 : { 225 : const char *snapshotEnv = SDL_getenv("OO_SNAPSHOTSDIR"); 226 : NSString *savedir; 227 : 228 : if (snapshotEnv) 229 : { 230 : savedir = [NSString stringWithUTF8String:snapshotEnv]; 231 : } 232 : else 233 : { 234 : // SDL: the default path for snapshots is oolite.app/oolite-saves/snapshots 235 : savedir = [[NSHomeDirectory() stringByAppendingPathComponent:@SAVEDIR] stringByAppendingPathComponent:@SNAPSHOTDIR]; 236 : } 237 : 238 : if (![self changeCurrentDirectoryPath: savedir]) 239 : { 240 : // it probably doesn't exist. 241 : if (![self oo_createDirectoryAtPath: savedir attributes: nil]) 242 : { 243 : OOLog(@"savedSnapshot.defaultPath.create.failed", @"Unable to create directory %@", savedir); 244 : return NO; 245 : } 246 : if (![self changeCurrentDirectoryPath: savedir]) 247 : { 248 : OOLog(@"savedSnapshot.defaultPath.chdir.failed", @"Created %@ but couldn't make it the current directory.", savedir); 249 : return NO; 250 : } 251 : } 252 : 253 : return YES; 254 : } 255 : #endif 256 : 257 : - (BOOL) oo_oxzFileExistsAtPath:(NSString *)path 258 : { 259 : NSUInteger i, cl; 260 : NSArray *components = [path pathComponents]; 261 : cl = [components count]; 262 : for (i = 0 ; i < cl ; i++) 263 : { 264 : NSString *component = [components objectAtIndex:i]; 265 : if ([[[component pathExtension] lowercaseString] isEqualToString:@"oxz"]) 266 : { 267 : break; 268 : } 269 : } 270 : // if i == cl then the path is entirely uncompressed 271 : if (i == cl) 272 : { 273 : BOOL directory = NO; 274 : BOOL result = [self fileExistsAtPath:path isDirectory:&directory]; 275 : if (directory) 276 : { 277 : return NO; 278 : } 279 : return result; 280 : } 281 : 282 : NSRange range; 283 : range.location = 0; range.length = i+1; 284 : NSString *zipFile = [NSString pathWithComponents:[components subarrayWithRange:range]]; 285 : range.location = i+1; range.length = cl-(i+1); 286 : NSString *containedFile = [NSString pathWithComponents:[components subarrayWithRange:range]]; 287 : 288 : unzFile uf = NULL; 289 : const char* zipname = [zipFile cStringUsingEncoding:NSUTF8StringEncoding]; 290 : if (zipname != NULL) 291 : { 292 : uf = unzOpen64(zipname); 293 : } 294 : if (uf == NULL) 295 : { 296 : // no such zip file 297 : return NO; 298 : } 299 : const char* filename = [containedFile cStringUsingEncoding:NSUTF8StringEncoding]; 300 : // unzLocateFile(*, *, 1) = case-sensitive extract 301 : BOOL result = YES; 302 : if (unzLocateFile(uf, filename, 1) != UNZ_OK) 303 : { 304 : result = NO; 305 : } 306 : else 307 : { 308 : int err = UNZ_OK; 309 : unz_file_info64 file_info = {0}; 310 : err = unzGetCurrentFileInfo64(uf, &file_info, NULL, 0, NULL, 0, NULL, 0); 311 : if (err != UNZ_OK) 312 : { 313 : result = NO; 314 : } 315 : else 316 : { 317 : 318 : 319 : } 320 : } 321 : unzClose(uf); 322 : return result; 323 : } 324 : 325 : 326 : 327 : 328 : @end 329 : 330 :