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 : #import "ResourceManager.h" 31 : #import "OOPListParsing.h" 32 : #import "GameController.h" 33 : #import "NSFileManagerOOExtensions.h" 34 : #import "unzip.h" 35 : 36 : @implementation NSFileManager (OOExtensions) 37 : 38 : - (NSArray *) commanderContentsOfPath:(NSString *)savePath 39 : { 40 : BOOL pathIsDirectory = NO; 41 : if ([[NSFileManager defaultManager] fileExistsAtPath:savePath isDirectory:&pathIsDirectory] && pathIsDirectory) 42 : { 43 : NSMutableArray *contents = [NSMutableArray arrayWithArray:[self oo_directoryContentsAtPath:savePath]]; 44 : 45 : // at this point we should strip out any files not loadable as Oolite saved games 46 : unsigned i; 47 : for (i = 0; i < [contents count]; i++) 48 : { 49 : NSString* path = [savePath stringByAppendingPathComponent: (NSString*)[contents objectAtIndex:i]]; 50 : 51 : // ensure it's not a directory 52 : if (![[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&pathIsDirectory] && pathIsDirectory) 53 : { 54 : 55 : // check file extension 56 : if (![[path pathExtension] isEqual:@"oolite-save"]) 57 : { 58 : [contents removeObjectAtIndex: i--]; 59 : continue; 60 : } 61 : 62 : // check to see if we can parse the file okay 63 : NSDictionary *cdr = OODictionaryFromFile(path); 64 : if (!cdr) 65 : { 66 : OOLog(@"savedGame.read.fail.notDictionary", @">>>> %@ could not be parsed as a saved game.", path); 67 : [contents removeObjectAtIndex: i--]; 68 : continue; 69 : } 70 : } 71 : 72 : // all okay - we can use this path! 73 : [contents replaceObjectAtIndex: i withObject: path]; 74 : 75 : } 76 : 77 : return contents; 78 : } 79 : else 80 : { 81 : OOLogERR(@"savedGame.read.fail.fileNotFound", @"File at path '%@' could not be found.", savePath); 82 : return nil; 83 : } 84 : } 85 : 86 : 87 : - (NSString *) defaultCommanderPath 88 : { 89 : NSString *savedir = [NSHomeDirectory() stringByAppendingPathComponent:@SAVEDIR]; 90 : BOOL pathIsDirectory = NO; 91 : 92 : // does it exist? 93 : if (![[NSFileManager defaultManager] fileExistsAtPath:savedir isDirectory:&pathIsDirectory]) 94 : { 95 : // it doesn't exist. 96 : if([self oo_createDirectoryAtPath:savedir attributes:nil]) 97 : { 98 : return savedir; 99 : } 100 : else 101 : { 102 : OOLogERR(@"savedGame.defaultPath.create.failed", @"Unable to create '%@'. Saved games will go to the home directory.", savedir); 103 : return NSHomeDirectory(); 104 : } 105 : } 106 : 107 : // is it a directory? 108 : if (!pathIsDirectory) 109 : { 110 : OOLogERR(@"savedGame.defaultPath.notDirectory", @"'%@' is not a directory, saved games will go to the home directory.", savedir); 111 : return NSHomeDirectory(); 112 : } 113 : 114 : return savedir; 115 : } 116 : 117 : 118 : #if OOLITE_MAC_OS_X 119 : 120 : - (NSArray *) oo_directoryContentsAtPath:(NSString *)path 121 : { 122 : return [self contentsOfDirectoryAtPath:path error:NULL]; 123 : } 124 : 125 : 126 : - (BOOL) oo_createDirectoryAtPath:(NSString *)path attributes:(NSDictionary *)attributes 127 : { 128 : return [self createDirectoryAtPath:path withIntermediateDirectories:YES attributes:attributes error:NULL]; 129 : } 130 : 131 : 132 : - (NSDictionary *) oo_fileAttributesAtPath:(NSString *)path traverseLink:(BOOL)traverseLink 133 : { 134 : if (traverseLink) 135 : { 136 : NSString *linkDest = nil; 137 : do 138 : { 139 : linkDest = [self destinationOfSymbolicLinkAtPath:path error:NULL]; 140 : if (linkDest != nil) path = linkDest; 141 : } while (linkDest != nil); 142 : } 143 : 144 : return [self attributesOfItemAtPath:path error:NULL]; 145 : } 146 : 147 : 148 : - (NSDictionary *) oo_fileSystemAttributesAtPath:(NSString *)path 149 : { 150 : return [self attributesOfFileSystemForPath:path error:NULL]; 151 : } 152 : 153 : 154 : - (BOOL) oo_removeItemAtPath:(NSString *)path 155 : { 156 : return [self removeItemAtPath:path error:NULL]; 157 : } 158 : 159 : 160 : - (BOOL) oo_moveItemAtPath:(NSString *)src toPath:(NSString *)dest 161 : { 162 : return [self moveItemAtPath:src toPath:dest error:NULL]; 163 : } 164 : 165 : #else 166 : 167 : - (NSArray *) oo_directoryContentsAtPath:(NSString *)path 168 : { 169 : return [self directoryContentsAtPath:path]; 170 : } 171 : 172 : 173 : - (BOOL) oo_createDirectoryAtPath:(NSString *)path attributes:(NSDictionary *)attributes 174 : { 175 : #if OOLITE_WINDOWS 176 : return [self createDirectoryAtPath:path attributes:attributes]; 177 : #else 178 : // has been in GNUStep since 2008, so it's probably safe to use now. 179 : // .... why do I say things like that, of course it's not safe - CIM 180 : return [self createDirectoryAtPath:path withIntermediateDirectories:YES attributes:attributes error:NULL]; 181 : #endif 182 : } 183 : 184 : 185 : - (NSDictionary *) oo_fileAttributesAtPath:(NSString *)path traverseLink:(BOOL)yorn 186 : { 187 : return [self fileAttributesAtPath:path traverseLink:yorn]; 188 : } 189 : 190 : 191 : - (NSDictionary *) oo_fileSystemAttributesAtPath:(NSString *)path 192 : { 193 : return [self fileSystemAttributesAtPath:path]; 194 : } 195 : 196 : 197 : - (BOOL) oo_removeItemAtPath:(NSString *)path 198 : { 199 : return [self removeFileAtPath:path handler:nil]; 200 : } 201 : 202 : 203 : - (BOOL) oo_moveItemAtPath:(NSString *)src toPath:(NSString *)dest 204 : { 205 : return [self movePath:src toPath:dest handler:nil]; 206 : } 207 : 208 : #endif 209 : 210 : 211 : #if OOLITE_SDL 212 : - (BOOL) chdirToSnapshotPath 213 : { 214 : // SDL: the default path for snapshots is oolite.app/oolite-saves/snapshots 215 : NSString *savedir = [[NSHomeDirectory() stringByAppendingPathComponent:@SAVEDIR] stringByAppendingPathComponent:@SNAPSHOTDIR]; 216 : 217 : if (![self changeCurrentDirectoryPath: savedir]) 218 : { 219 : // it probably doesn't exist. 220 : if (![self createDirectoryAtPath: savedir attributes: nil]) 221 : { 222 : OOLog(@"savedSnapshot.defaultPath.create.failed", @"Unable to create directory %@", savedir); 223 : return NO; 224 : } 225 : if (![self changeCurrentDirectoryPath: savedir]) 226 : { 227 : OOLog(@"savedSnapshot.defaultPath.chdir.failed", @"Created %@ but couldn't make it the current directory.", savedir); 228 : return NO; 229 : } 230 : } 231 : 232 : return YES; 233 : } 234 : #endif 235 : 236 : - (BOOL) oo_oxzFileExistsAtPath:(NSString *)path 237 : { 238 : NSUInteger i, cl; 239 : NSArray *components = [path pathComponents]; 240 : cl = [components count]; 241 : for (i = 0 ; i < cl ; i++) 242 : { 243 : NSString *component = [components objectAtIndex:i]; 244 : if ([[[component pathExtension] lowercaseString] isEqualToString:@"oxz"]) 245 : { 246 : break; 247 : } 248 : } 249 : // if i == cl then the path is entirely uncompressed 250 : if (i == cl) 251 : { 252 : BOOL directory = NO; 253 : BOOL result = [self fileExistsAtPath:path isDirectory:&directory]; 254 : if (directory) 255 : { 256 : return NO; 257 : } 258 : return result; 259 : } 260 : 261 : NSRange range; 262 : range.location = 0; range.length = i+1; 263 : NSString *zipFile = [NSString pathWithComponents:[components subarrayWithRange:range]]; 264 : range.location = i+1; range.length = cl-(i+1); 265 : NSString *containedFile = [NSString pathWithComponents:[components subarrayWithRange:range]]; 266 : 267 : unzFile uf = NULL; 268 : const char* zipname = [zipFile cStringUsingEncoding:NSUTF8StringEncoding]; 269 : if (zipname != NULL) 270 : { 271 : uf = unzOpen64(zipname); 272 : } 273 : if (uf == NULL) 274 : { 275 : // no such zip file 276 : return NO; 277 : } 278 : const char* filename = [containedFile cStringUsingEncoding:NSUTF8StringEncoding]; 279 : // unzLocateFile(*, *, 1) = case-sensitive extract 280 : BOOL result = YES; 281 : if (unzLocateFile(uf, filename, 1) != UNZ_OK) 282 : { 283 : result = NO; 284 : } 285 : else 286 : { 287 : int err = UNZ_OK; 288 : unz_file_info64 file_info = {0}; 289 : err = unzGetCurrentFileInfo64(uf, &file_info, NULL, 0, NULL, 0, NULL, 0); 290 : if (err != UNZ_OK) 291 : { 292 : result = NO; 293 : } 294 : else 295 : { 296 : 297 : 298 : } 299 : } 300 : unzClose(uf); 301 : return result; 302 : } 303 : 304 : 305 : 306 : 307 : @end 308 : 309 :