LCOV - code coverage report
Current view: top level - Core/OXPVerifier - OOFileScannerVerifierStage.m (source / functions) Hit Total Coverage
Test: coverxygen.info Lines: 0 20 0.0 %
Date: 2025-05-28 07:50:54 Functions: 0 0 -

          Line data    Source code
       1           0 : /*
       2             : 
       3             : OOFileScannerVerifierStage.m
       4             : 
       5             : 
       6             : Copyright (C) 2007-2013 Jens Ayton
       7             : 
       8             : Permission is hereby granted, free of charge, to any person obtaining a copy
       9             : of this software and associated documentation files (the "Software"), to deal
      10             : in the Software without restriction, including without limitation the rights
      11             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      12             : copies of the Software, and to permit persons to whom the Software is
      13             : furnished to do so, subject to the following conditions:
      14             : 
      15             : The above copyright notice and this permission notice shall be included in all
      16             : copies or substantial portions of the Software.
      17             : 
      18             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      19             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      20             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      21             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      22             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      23             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      24             : SOFTWARE.
      25             : 
      26             : */
      27             : 
      28             : 
      29             : /*      Design notes:
      30             :         In order to be able to look files up case-insenstively, but warn about
      31             :         case mismatches, the OOFileScannerVerifierStage builds its own
      32             :         representation of the file hierarchy. Dictionaries are used heavily: the
      33             :         _directoryListings is keyed by folder names mapped to lower case, and its
      34             :         entries map lowercase file names to actual case, that is, the case found
      35             :         in the file system. The companion dictionary _directoryCases maps
      36             :         lowercase directory names to actual case.
      37             :         
      38             :         The class design is based on the knowledge that Oolite uses a two-level
      39             :         namespace for files. Each file type has an appropriate folder, and files
      40             :         may either be in the appropriate folder or "bare". For instance, a texture
      41             :         file in an OXP may be either in the Textures subdirectory or in the root
      42             :         directory of the OXP. The root directory's contents are listed in
      43             :         _directoryListings with the empty string as key. This architecture means
      44             :         the OOFileScannerVerifierStage doesn't need to take full file system
      45             :         hierarchy into account.
      46             : */
      47             : 
      48             : #import "OOFileScannerVerifierStage.h"
      49             : 
      50             : #if OO_OXP_VERIFIER_ENABLED
      51             : 
      52             : #import "OOCollectionExtractors.h"
      53             : #import "ResourceManager.h"
      54             : 
      55           0 : static NSString * const kFileScannerStageName   = @"Scanning files";
      56           0 : static NSString * const kUnusedListerStageName  = @"Checking for unused files";
      57             : 
      58             : 
      59             : static BOOL CheckNameConflict(NSString *lcName, NSDictionary *directoryCases, NSDictionary *rootFiles, NSString **outExisting, NSString **outExistingType);
      60             : 
      61             : 
      62             : @interface OOFileScannerVerifierStage (OOPrivate)
      63             : 
      64           0 : - (void)scanForFiles;
      65             : 
      66           0 : - (void)checkRootFolders;
      67           0 : - (void)checkKnownFiles;
      68             : 
      69             : /*      Given an array of strings, return a dictionary mapping lowercase strings
      70             :         to the canonicial case given in the array. For instance, given
      71             :                 (Foo, BAR)
      72             :         
      73             :         it will return
      74             :                 { foo = Foo; bar = BAR }
      75             : */
      76           0 : - (NSDictionary *)lowercaseMap:(NSArray *)array;
      77             : 
      78           0 : - (NSDictionary *)scanDirectory:(NSString *)path;
      79           0 : - (void)checkPListFormat:(NSPropertyListFormat)format file:(NSString *)file folder:(NSString *)folder;
      80           0 : - (NSSet *)constructReadMeNames;
      81             : 
      82             : @end
      83             : 
      84             : 
      85             : @implementation OOFileScannerVerifierStage
      86             : 
      87           0 : - (void)dealloc
      88             : {
      89             :         [_basePath release];
      90             :         [_usedFiles release];
      91             :         [_caseWarnings release];
      92             :         [_directoryListings release];
      93             :         [_directoryCases release];
      94             :         [_badPLists release];
      95             :         
      96             :         [super dealloc];
      97             : }
      98             : 
      99             : 
     100           0 : - (NSString *)name
     101             : {
     102             :         return kFileScannerStageName;
     103             : }
     104             : 
     105             : 
     106           0 : - (void)run
     107             : {
     108             :         NSAutoreleasePool                       *pool = nil;
     109             :         
     110             :         _usedFiles = [[NSMutableSet alloc] init];
     111             :         _caseWarnings = [[NSMutableSet alloc] init];
     112             :         _badPLists = [[NSMutableSet alloc] init];
     113             :         
     114             :         pool = [[NSAutoreleasePool alloc] init];
     115             :         [self scanForFiles];
     116             :         [pool release];
     117             :         
     118             :         pool = [[NSAutoreleasePool alloc] init];
     119             :         [self checkRootFolders];
     120             :         [self checkKnownFiles];
     121             :         [pool release];
     122             : }
     123             : 
     124             : 
     125             : + (NSString *)nameForDependencyForVerifier:(OOOXPVerifier *)verifier
     126             : {
     127             :         OOFileScannerVerifierStage *stage = [verifier stageWithName:kFileScannerStageName];
     128             :         if (stage == nil)
     129             :         {
     130             :                 stage = [[OOFileScannerVerifierStage alloc] init];
     131             :                 [verifier registerStage:stage];
     132             :                 [stage release];
     133             :         }
     134             :         
     135             :         return kFileScannerStageName;
     136             : }
     137             : 
     138             : 
     139             : - (BOOL)fileExists:(NSString *)file
     140             :                   inFolder:(NSString *)folder
     141             :         referencedFrom:(NSString *)context
     142             :           checkBuiltIn:(BOOL)checkBuiltIn
     143             : {
     144             :         return [self pathForFile:file inFolder:folder referencedFrom:context checkBuiltIn:checkBuiltIn] != nil;
     145             : }
     146             : 
     147             : 
     148             : - (NSString *)pathForFile:(NSString *)file
     149             :                                  inFolder:(NSString *)folder
     150             :                    referencedFrom:(NSString *)context
     151             :                          checkBuiltIn:(BOOL)checkBuiltIn
     152             : {
     153             :         NSString                                *lcName = nil,
     154             :                                                         *lcDirName = nil,
     155             :                                                         *realDirName = nil,
     156             :                                                         *realFileName = nil,
     157             :                                                         *path = nil,
     158             :                                                         *expectedPath = nil;
     159             :         
     160             :         if (file == nil)  return nil;
     161             :         lcName = [file lowercaseString];
     162             :         
     163             :         if (folder != nil)
     164             :         {
     165             :                 lcDirName = [folder lowercaseString];
     166             :                 realFileName = [[_directoryListings oo_dictionaryForKey:lcDirName] objectForKey:lcName];
     167             :                 
     168             :                 if (realFileName != nil)
     169             :                 {
     170             :                         realDirName = [_directoryCases objectForKey:lcDirName];
     171             :                         path = [realDirName stringByAppendingPathComponent:realFileName];
     172             :                 }
     173             :         }
     174             :         
     175             :         if (path == nil)
     176             :         {
     177             :                 realFileName = [[_directoryListings oo_dictionaryForKey:@""] objectForKey:lcName];
     178             :                 
     179             :                 if (realFileName != nil)
     180             :                 {
     181             :                         path = realFileName;
     182             :                 }
     183             :         }
     184             :         
     185             :         if (path != nil)
     186             :         {
     187             :                 [_usedFiles addObject:path];
     188             :                 if (realDirName != nil && ![realDirName isEqual:folder])
     189             :                 {
     190             :                         // Case mismatch for folder name
     191             :                         if (![_caseWarnings containsObject:lcDirName])
     192             :                         {
     193             :                                 [_caseWarnings addObject:lcDirName];
     194             :                                 OOLog(@"verifyOXP.files.caseMismatch", @"***** ERROR: case mismatch: directory '%@' should be called '%@'.", realDirName, folder);
     195             :                         }
     196             :                 }
     197             :                 
     198             :                 if (![realFileName isEqual:file])
     199             :                 {
     200             :                         // Case mismatch for file name
     201             :                         if (![_caseWarnings containsObject:lcName])
     202             :                         {
     203             :                                 [_caseWarnings addObject:lcName];
     204             :                                 
     205             :                                 expectedPath = [self displayNameForFile:file andFolder:folder];
     206             :                                 
     207             :                                 if (context != nil)  context = [@" referenced in " stringByAppendingString:context];
     208             :                                 else  context = @"";
     209             :                                 
     210             :                                 OOLog(@"verifyOXP.files.caseMismatch", @"***** ERROR: case mismatch: request for file '%@'%@ resolved to '%@'.", expectedPath, context, path);
     211             :                         }
     212             :                 }
     213             :                 
     214             :                 return [_basePath stringByAppendingPathComponent:path];
     215             :         }
     216             :         
     217             :         // If we get here, the file wasn't found in the OXP.
     218             :         // FIXME: should check case for built-in files.
     219             :         if (checkBuiltIn)  return [ResourceManager pathForFileNamed:file inFolder:folder];
     220             :         
     221             :         return nil;
     222             : }
     223             : 
     224             : 
     225             : - (NSData *)dataForFile:(NSString *)file
     226             :                            inFolder:(NSString *)folder
     227             :                  referencedFrom:(NSString *)context
     228             :                    checkBuiltIn:(BOOL)checkBuiltIn
     229             : {
     230             :         NSString                                *path = nil;
     231             :         
     232             :         path = [self pathForFile:file inFolder:folder referencedFrom:context checkBuiltIn:checkBuiltIn];
     233             :         if (path == nil)  return nil;
     234             :         
     235             :         return [NSData dataWithContentsOfMappedFile:path];
     236             : }
     237             : 
     238             : 
     239             : - (id)plistNamed:(NSString *)file
     240             :                 inFolder:(NSString *)folder
     241             :   referencedFrom:(NSString *)context
     242             :         checkBuiltIn:(BOOL)checkBuiltIn
     243             : {
     244             :         NSData                                  *data = nil;
     245             :         NSString                                *errorString = nil;
     246             :         NSPropertyListFormat    format;
     247             :         id                                              plist = nil;
     248             :         NSArray                                 *errorLines = nil;
     249             :         NSEnumerator                    *errLineEnum = nil;
     250             :         NSString                                *displayName = nil,
     251             :                                                         *errorKey = nil;
     252             :         NSAutoreleasePool               *pool = nil;
     253             :         
     254             :         data = [self dataForFile:file inFolder:folder referencedFrom:context checkBuiltIn:checkBuiltIn];
     255             :         if (data == nil)  return nil;
     256             :         
     257             :         pool = [[NSAutoreleasePool alloc] init];
     258             :         
     259             :         plist = [NSPropertyListSerialization propertyListFromData:data
     260             :                                                                                          mutabilityOption:NSPropertyListImmutable
     261             :                                                                                                            format:&format
     262             :                                                                                          errorDescription:&errorString];
     263             :         
     264             : #if OOLITE_RELEASE_PLIST_ERROR_STRINGS
     265             :         [errorString autorelease];
     266             : #endif
     267             :         
     268             :         if (plist != nil)
     269             :         {
     270             :                 // PList is readable; check that it's in an official Oolite format.
     271             :                 [self checkPListFormat:format file:file folder:folder];
     272             :         }
     273             :         else
     274             :         {
     275             :                 /*      Couldn't parse plist; report problem.
     276             :                         This is complicated somewhat by the need to present a possibly
     277             :                         multi-line error description while maintaining our indentation.
     278             :                 */
     279             :                 displayName = [self displayNameForFile:file andFolder:folder];
     280             :                 errorKey = [displayName lowercaseString];
     281             :                 if (![_badPLists containsObject:errorKey])
     282             :                 {
     283             :                         [_badPLists addObject:errorKey];
     284             :                         OOLog(@"verifyOXP.plist.parseError", @"Could not interpret property list %@.", displayName);
     285             :                         OOLogIndent();
     286             :                         errorLines = [errorString componentsSeparatedByString:@"\n"];
     287             :                         for (errLineEnum = [errorLines objectEnumerator]; (errorString = [errLineEnum nextObject]); )
     288             :                         {
     289             :                                 while ([errorString hasPrefix:@"\t"])
     290             :                                 {
     291             :                                         errorString = [@"    " stringByAppendingString:[errorString substringFromIndex:1]];
     292             :                                 }
     293             :                                 OOLog(@"verifyOXP.plist.parseError", @"%@", errorString);
     294             :                         }
     295             :                         OOLogOutdent();
     296             :                 }
     297             :         }
     298             :         
     299             :         [plist retain];
     300             :         [pool release];
     301             :         
     302             :         return [plist autorelease];
     303             : }
     304             : 
     305             : 
     306             : - (id)displayNameForFile:(NSString *)file andFolder:(NSString *)folder
     307             : {
     308             :         if (file != nil && folder != nil)  return [folder stringByAppendingPathComponent:file];
     309             :         return file;
     310             : }
     311             : 
     312             : 
     313             : - (NSArray *)filesInFolder:(NSString *)folder
     314             : {
     315             :         if (folder == nil)  return nil;
     316             :         return [[_directoryListings objectForKey:[folder lowercaseString]] allValues];
     317             : }
     318             : 
     319             : @end
     320             : 
     321             : 
     322             : @implementation OOFileScannerVerifierStage (OOPrivate)
     323             : 
     324             : - (void)scanForFiles
     325             : {
     326             :         NSDirectoryEnumerator   *dirEnum = nil;
     327             :         NSString                                *name = nil,
     328             :                                                         *path = nil,
     329             :                                                         *type = nil,
     330             :                                                         *lcName = nil,
     331             :                                                         *existing = nil,
     332             :                                                         *existingType = nil;
     333             :         NSMutableDictionary             *directoryListings = nil,
     334             :                                                         *directoryCases = nil,
     335             :                                                         *rootFiles = nil;
     336             :         NSDictionary                    *dirFiles = nil;
     337             :         NSSet                                   *readMeNames = nil;
     338             :         
     339             :         _basePath = [[[self verifier] oxpPath] copy];
     340             :         
     341             :         _junkFileNames = [[self verifier] configurationSetForKey:@"junkFiles"];
     342             :         _skipDirectoryNames = [[self verifier] configurationSetForKey:@"skipDirectories"];
     343             :         
     344             :         directoryCases = [NSMutableDictionary dictionary];
     345             :         directoryListings = [NSMutableDictionary dictionary];
     346             :         rootFiles = [NSMutableDictionary dictionary];
     347             :         readMeNames = [self constructReadMeNames];
     348             :         
     349             :         dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:_basePath];
     350             :         while ((name = [dirEnum nextObject]))
     351             :         {
     352             :                 path = [_basePath stringByAppendingPathComponent:name];
     353             :                 type = [[dirEnum fileAttributes] fileType];
     354             :                 lcName = [name lowercaseString];
     355             :                 
     356             :                 if ([type isEqualToString:NSFileTypeDirectory])
     357             :                 {
     358             :                         [dirEnum skipDescendents];
     359             :                         
     360             :                         if ([_skipDirectoryNames containsObject:name])
     361             :                         {
     362             :                                 // Silently skip .svn and CVS
     363             :                                 OOLog(@"verifyOXP.verbose.listFiles", @"- Skipping %@/", name);
     364             :                         }
     365             :                         else if (!CheckNameConflict(lcName, directoryCases, rootFiles, &existing, &existingType))
     366             :                         {
     367             :                                 OOLog(@"verifyOXP.verbose.listFiles", @"- %@/", name);
     368             :                                 OOLogIndentIf(@"verifyOXP.verbose.listFiles");
     369             :                                 dirFiles = [self scanDirectory:path];
     370             :                                 [directoryListings setObject:dirFiles forKey:lcName];
     371             :                                 [directoryCases setObject:name forKey:lcName];
     372             :                                 OOLogOutdentIf(@"verifyOXP.verbose.listFiles");
     373             :                         }
     374             :                         else
     375             :                         {
     376             :                                 OOLog(@"verifyOXP.scanFiles.overloadedName", @"***** ERROR: %@ '%@' conflicts with %@ named '%@', ignoring. (OXPs must work on case-insensitive file systems!)", @"directory", name, existingType, existing);
     377             :                         }
     378             :                 }
     379             :                 else if ([type isEqualToString:NSFileTypeRegular])
     380             :                 {
     381             :                         if ([_junkFileNames containsObject:name])
     382             :                         {
     383             :                                 OOLog(@"verifyOXP.scanFiles.skipJunk", @"NOTE: skipping junk file %@.", name);
     384             :                         }
     385             :                         else if ([readMeNames containsObject:lcName])
     386             :                         {
     387             :                                 OOLog(@"verifyOXP.scanFiles.readMe", @"----- WARNING: apparent Read Me file (\"%@\") inside OXP. This is the wrong place for a Read Me file, because it will not be read.", name);
     388             :                         }
     389             :                         else if (!CheckNameConflict(lcName, directoryCases, rootFiles, &existing, &existingType))
     390             :                         {
     391             :                                 OOLog(@"verifyOXP.verbose.listFiles", @"- %@", name);
     392             :                                 [rootFiles setObject:name forKey:lcName];
     393             :                         }
     394             :                         else
     395             :                         {
     396             :                                 OOLog(@"verifyOXP.scanFiles.overloadedName", @"***** ERROR: %@ '%@' conflicts with %@ named '%@', ignoring. (OXPs must work on case-insensitive file systems!)", @"file", name, existingType, existing);
     397             :                         }
     398             :                 }
     399             :                 else if ([type isEqualToString:NSFileTypeSymbolicLink])
     400             :                 {
     401             :                         OOLog(@"verifyOXP.scanFiles.symLink", @"----- WARNING: \"%@\" is a symbolic link, ignoring.", name);
     402             :                 }
     403             :                 else
     404             :                 {
     405             :                         OOLog(@"verifyOXP.scanFiles.nonStandardFile", @"----- WARNING: \"%@\" is a non-standard file (%@), ignoring.", name, type);
     406             :                 }
     407             :         }
     408             :         
     409             :         _junkFileNames = nil;
     410             :         _skipDirectoryNames = nil;
     411             :         
     412             :         [directoryListings setObject:rootFiles forKey:@""];
     413             :         _directoryListings = [directoryListings copy];
     414             :         _directoryCases = [directoryCases copy];
     415             : }
     416             : 
     417             : 
     418             : - (void)checkRootFolders
     419             : {
     420             :         NSArray                                 *knownNames = nil;
     421             :         NSEnumerator                    *nameEnum = nil;
     422             :         NSString                                *name = nil;
     423             :         NSString                                *lcName = nil;
     424             :         NSString                                *actual = nil;
     425             :         
     426             :         knownNames = [[self verifier] configurationArrayForKey:@"knownRootDirectories"];
     427             :         for (nameEnum = [knownNames objectEnumerator]; (name = [nameEnum nextObject]); )
     428             :         {
     429             :                 if (![name isKindOfClass:[NSString class]])  continue;
     430             :                 
     431             :                 lcName = [name lowercaseString];
     432             :                 actual = [_directoryCases objectForKey:lcName];
     433             :                 if (actual == nil)  continue;
     434             :                 
     435             :                 if (![actual isEqualToString:name])
     436             :                 {
     437             :                         OOLog(@"verifyOXP.files.caseMismatch", @"***** ERROR: case mismatch: directory '%@' should be called '%@'.", actual, name);
     438             :                 }
     439             :                 [_caseWarnings addObject:lcName];
     440             :         }
     441             : }
     442             : 
     443             : 
     444           0 : - (void)checkConfigFiles
     445             : {
     446             :         NSArray                                 *knownNames = nil;
     447             :         NSEnumerator                    *nameEnum = nil;
     448             :         NSString                                *name = nil,
     449             :                 *lcName = nil,
     450             :                 *realFileName = nil;
     451             :         BOOL                                    inConfigDir;
     452             :         
     453             :         knownNames = [[self verifier] configurationArrayForKey:@"knownConfigFiles"];
     454             :         for (nameEnum = [knownNames objectEnumerator]; (name = [nameEnum nextObject]); )
     455             :         {
     456             :                 if (![name isKindOfClass:[NSString class]])  continue;
     457             :                 
     458             :                 /*      In theory, we could use -fileExists:inFolder:referencedFrom:checkBuiltIn:
     459             :                 here, but we want a different error message.
     460             :                 */
     461             :                 
     462             :                 lcName = [name lowercaseString];
     463             :                 realFileName = [[_directoryListings oo_dictionaryForKey:@"config"] objectForKey:lcName];
     464             :                 inConfigDir = realFileName != nil;
     465             :                 if (!inConfigDir)  realFileName = [[_directoryListings oo_dictionaryForKey:@""] objectForKey:lcName];
     466             :                 if (realFileName == nil)  continue;
     467             :                 
     468             :                 if (![realFileName isEqualToString:name])
     469             :                 {
     470             :                         if (inConfigDir)  realFileName = [@"Config" stringByAppendingPathComponent:realFileName];
     471             :                         OOLog(@"verifyOXP.files.caseMismatch", @"***** ERROR: case mismatch: configuration file '%@' should be called '%@'.", realFileName, name);
     472             :                 }
     473             :         }
     474             : }
     475             : 
     476             : 
     477             : - (void)checkKnownFiles
     478             : {
     479             :         NSDictionary                    *directories = nil;
     480             :         NSEnumerator                    *directoryEnum = nil;
     481             :         NSString                                *directory = nil,
     482             :                                                         *lcDirectory = nil;
     483             :         NSArray                                 *fileList = nil;
     484             :         NSEnumerator                    *nameEnum = nil;
     485             :         NSString                                *name = nil,
     486             :                                                         *lcName = nil,
     487             :                                                         *realFileName = nil;
     488             :         BOOL                                    inDirectory;
     489             :         
     490             :         directories = [[self verifier] configurationDictionaryForKey:@"knownFiles"];
     491             :         for (directoryEnum = [directories keyEnumerator]; (directory = [directoryEnum nextObject]); )
     492             :         {
     493             :                 fileList = [directories objectForKey:directory];
     494             :                 lcDirectory = [directory lowercaseString];
     495             :                 for (nameEnum = [fileList objectEnumerator]; (name = [nameEnum nextObject]); )
     496             :                 {
     497             :                         if (![name isKindOfClass:[NSString class]])  continue;
     498             :                         
     499             :                         /*      In theory, we could use -fileExists:inFolder:referencedFrom:checkBuiltIn:
     500             :                                 here, but we want a different error message.
     501             :                         */
     502             :                         
     503             :                         lcName = [name lowercaseString];
     504             :                         realFileName = [[_directoryListings oo_dictionaryForKey:lcDirectory] objectForKey:lcName];
     505             :                         inDirectory = (realFileName != nil);
     506             :                         if (!inDirectory)
     507             :                         {
     508             :                                 // Allow for files in root directory of OXP
     509             :                                 realFileName = [[_directoryListings oo_dictionaryForKey:@""] objectForKey:lcName];
     510             :                         }
     511             :                         if (realFileName == nil)  continue;
     512             :                         
     513             :                         if (![realFileName isEqualToString:name])
     514             :                         {
     515             :                                 if (inDirectory)  realFileName = [directory stringByAppendingPathComponent:realFileName];
     516             :                                 OOLog(@"verifyOXP.files.caseMismatch", @"***** ERROR: case mismatch: file '%@' should be called '%@'.", realFileName, name);
     517             :                         }
     518             :                 }
     519             :         }
     520             : }
     521             : 
     522             : 
     523             : - (NSDictionary *)lowercaseMap:(NSArray *)array
     524             : {
     525             :         NSUInteger                              i, count;
     526             :         NSString                                *canonical = nil,
     527             :                                                         *lowercase = nil;
     528             :         NSMutableDictionary             *result = nil;
     529             :         
     530             :         count = [array count];
     531             :         if (count == 0)  return [NSDictionary dictionary];
     532             :         result = [NSMutableDictionary dictionaryWithCapacity:count];
     533             :         
     534             :         for (i = 0; i != count; ++i)
     535             :         {
     536             :                 canonical = [array oo_stringAtIndex:i];
     537             :                 if (canonical != nil)
     538             :                 {
     539             :                         lowercase = [canonical lowercaseString];
     540             :                         [result setObject:canonical forKey:lowercase];
     541             :                 }
     542             :         }
     543             :         
     544             :         return result;
     545             : }
     546             : 
     547             : 
     548             : - (NSDictionary *)scanDirectory:(NSString *)path
     549             : {
     550             :         NSDirectoryEnumerator   *dirEnum = nil;
     551             :         NSMutableDictionary             *result = nil;
     552             :         NSString                                *name = nil,
     553             :                                                         *lcName = nil,
     554             :                                                         *type = nil,
     555             :                                                         *dirName = nil,
     556             :                                                         *relativeName = nil,
     557             :                                                         *existing = nil;
     558             :         
     559             :         result = [NSMutableDictionary dictionary];
     560             :         dirName = [path lastPathComponent];
     561             :         
     562             :         dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:path];
     563             :         while ((name = [dirEnum nextObject]))
     564             :         {
     565             :                 type = [[dirEnum fileAttributes] fileType];
     566             :                 relativeName = [dirName stringByAppendingPathComponent:name];
     567             :                 
     568             :                 if ([_junkFileNames containsObject:name])
     569             :                 {
     570             :                         OOLog(@"verifyOXP.scanFiles.skipJunk", @"NOTE: skipping junk file %@/%@.", dirName, name);
     571             :                 }
     572             :                 else if ([type isEqualToString:NSFileTypeRegular])
     573             :                 {
     574             :                         lcName = [name lowercaseString];
     575             :                         existing = [result objectForKey:lcName];
     576             :                         
     577             :                         if (existing == nil)
     578             :                         {
     579             :                                 OOLog(@"verifyOXP.verbose.listFiles", @"- %@", name);
     580             :                                 [result setObject:name forKey:lcName];
     581             :                         }
     582             :                         else
     583             :                         {
     584             :                                 OOLog(@"verifyOXP.scanFiles.overloadedName", @"***** ERROR: %@ '%@' conflicts with %@ named '%@', ignoring. (OXPs must work on case-insensitive file systems!)", @"file", relativeName, @"file", [dirName stringByAppendingPathComponent:existing]);
     585             :                         }
     586             :                 }
     587             :                 else
     588             :                 {
     589             :                         if ([type isEqualToString:NSFileTypeDirectory])
     590             :                         {
     591             :                                 [dirEnum skipDescendents];
     592             :                                 if (![_skipDirectoryNames containsObject:name])
     593             :                                 {
     594             :                                         OOLog(@"verifyOXP.scanFiles.directory", @"----- WARNING: \"%@\" is a nested directory, ignoring.", relativeName);
     595             :                                 }
     596             :                                 else
     597             :                                 {
     598             :                                         OOLog(@"verifyOXP.verbose.listFiles", @"- Skipping %@/%@/", dirName, name);
     599             :                                 }
     600             :                         }
     601             :                         else if ([type isEqualToString:NSFileTypeSymbolicLink])
     602             :                         {
     603             :                                 OOLog(@"verifyOXP.scanFiles.symLink", @"----- WARNING: \"%@\" is a symbolic link, ignoring.", relativeName);
     604             :                         }
     605             :                         else
     606             :                         {
     607             :                                 OOLog(@"verifyOXP.scanFiles.nonStandardFile", @"----- WARNING: \"%@\" is a non-standard file (%@), ignoring.", relativeName, type);
     608             :                         }
     609             :                 }
     610             :         }
     611             :         
     612             :         return result;
     613             : }
     614             : 
     615             : 
     616             : - (void)checkPListFormat:(NSPropertyListFormat)format file:(NSString *)file folder:(NSString *)folder
     617             : {
     618             :         NSString                                *weirdnessKey = nil;
     619             :         NSString                                *formatDesc = nil;
     620             :         NSString                                *displayPath = nil;
     621             :         
     622             :         if (format != NSPropertyListOpenStepFormat && format != NSPropertyListXMLFormat_v1_0)
     623             :         {
     624             :                 displayPath = [self displayNameForFile:file andFolder:folder];
     625             :                 weirdnessKey = [displayPath lowercaseString];
     626             :                 
     627             :                 if (![_badPLists containsObject:weirdnessKey])
     628             :                 {
     629             :                         // Warn about "non-standard" format
     630             :                         [_badPLists addObject:weirdnessKey];
     631             :                         
     632             :                         switch (format)
     633             :                         {
     634             :                                 case NSPropertyListBinaryFormat_v1_0:
     635             :                                         formatDesc = @"Apple binary format";
     636             :                                         break;
     637             :                                 
     638             : #if OOLITE_GNUSTEP
     639             :                                 case NSPropertyListGNUstepFormat:
     640             :                                         formatDesc = @"GNUstep text format";
     641             :                                         break;
     642             :                                 
     643             :                                 case NSPropertyListGNUstepBinaryFormat:
     644             :                                         formatDesc = @"GNUstep binary format";
     645             :                                         break;
     646             : #endif
     647             :                                 
     648             :                                 default:
     649             :                                         formatDesc = [NSString stringWithFormat:@"unknown format (%i)", (int)format];
     650             :                         }
     651             :                         
     652             :                         OOLog(@"verifyOXP.plist.weirdFormat", @"----- WARNING: Property list %@ is in %@; OpenStep text format and XML format are the recommended formats for Oolite.", displayPath, formatDesc);
     653             :                 }
     654             :         }
     655             : }
     656             : 
     657             : 
     658           0 : - (NSSet *)constructReadMeNames
     659             : {
     660             :         NSDictionary                    *dict = nil;
     661             :         NSArray                                 *stems = nil,
     662             :                                                         *extensions = nil;
     663             :         NSMutableSet                    *result = nil;
     664             :         NSUInteger                              i, j, stemCount, extCount;
     665             :         NSString                                *stem = nil,
     666             :                                                         *extension = nil;
     667             :         
     668             :         dict = [[self verifier] configurationDictionaryForKey:@"readMeNames"];
     669             :         stems = [dict oo_arrayForKey:@"stems"];
     670             :         extensions = [dict oo_arrayForKey:@"extensions"];
     671             :         stemCount = [stems count];
     672             :         extCount = [extensions count];
     673             :         if (stemCount * extCount == 0)  return nil;
     674             :         
     675             :         // Construct all stem+extension permutations
     676             :         result = [NSMutableSet setWithCapacity:stemCount * extCount];
     677             :         for (i = 0; i != stemCount; ++i)
     678             :         {
     679             :                 stem = [[stems oo_stringAtIndex:i] lowercaseString];
     680             :                 if (stem != nil)
     681             :                 {
     682             :                         for (j = 0; j != extCount; ++j)
     683             :                         {
     684             :                                 extension = [[extensions oo_stringAtIndex:j] lowercaseString];
     685             :                                 if (extension != nil)
     686             :                                 {
     687             :                                         [result addObject:[stem stringByAppendingString:extension]];
     688             :                                 }
     689             :                         }
     690             :                 }
     691             :         }
     692             :         
     693             :         return result;
     694             : }
     695             : 
     696             : @end
     697             : 
     698             : 
     699             : @implementation OOListUnusedFilesStage: OOOXPVerifierStage
     700             : 
     701             : - (NSString *)name
     702             : {
     703             :         return kUnusedListerStageName;
     704             : }
     705             : 
     706             : 
     707           0 : - (NSSet *)dependencies
     708             : {
     709             :         return [NSSet setWithObject:kFileScannerStageName];
     710             : }
     711             : 
     712             : 
     713           0 : - (void)run
     714             : {
     715             :         OOLog(@"verifyOXP.unusedFiles.unimplemented", @"%@", @"TODO: implement unused files check.");
     716             : }
     717             : 
     718             : 
     719             : + (NSString *)nameForReverseDependencyForVerifier:(OOOXPVerifier *)verifier
     720             : {
     721             :         OOListUnusedFilesStage *stage = [verifier stageWithName:kUnusedListerStageName];
     722             :         if (stage == nil)
     723             :         {
     724             :                 stage = [[OOListUnusedFilesStage alloc] init];
     725             :                 [verifier registerStage:stage];
     726             :                 [stage release];
     727             :         }
     728             :         
     729             :         return kUnusedListerStageName;
     730             : }
     731             : 
     732             : @end
     733             : 
     734             : 
     735             : @implementation OOOXPVerifier(OOFileScannerVerifierStage)
     736             : 
     737             : - (OOFileScannerVerifierStage *)fileScannerStage
     738             : {
     739             :         return [self stageWithName:kFileScannerStageName];
     740             : }
     741             : 
     742             : @end
     743             : 
     744             : 
     745             : @implementation OOFileHandlingVerifierStage
     746             : 
     747           0 : - (NSSet *)dependencies
     748             : {
     749             :         return [NSSet setWithObject:[OOFileScannerVerifierStage nameForDependencyForVerifier:[self verifier]]];
     750             : }
     751             : 
     752             : 
     753           0 : - (NSSet *)dependents
     754             : {
     755             :         return [NSSet setWithObject:[OOListUnusedFilesStage nameForReverseDependencyForVerifier:[self verifier]]];
     756             : }
     757             : 
     758             : @end
     759             : 
     760             : 
     761           0 : static BOOL CheckNameConflict(NSString *lcName, NSDictionary *directoryCases, NSDictionary *rootFiles, NSString **outExisting, NSString **outExistingType)
     762             : {
     763             :         NSString                                *existing = nil;
     764             :         
     765             :         existing = [directoryCases objectForKey:lcName];
     766             :         if (existing != nil)
     767             :         {
     768             :                 if (outExisting != NULL)  *outExisting = existing;
     769             :                 if (outExistingType != NULL)  *outExistingType = @"directory";
     770             :                 return YES;
     771             :         }
     772             :         
     773             :         existing = [rootFiles objectForKey:lcName];
     774             :         if (existing != nil)
     775             :         {
     776             :                 if (outExisting != NULL)  *outExisting = existing;
     777             :                 if (outExistingType != NULL)  *outExistingType = @"file";
     778             :                 return YES;
     779             :         }
     780             :         
     781             :         return NO;
     782             : }
     783             : 
     784             : #endif

Generated by: LCOV version 1.14