Oolite
Loading...
Searching...
No Matches
OOFileScannerVerifierStage.m
Go to the documentation of this file.
1/*
2
3OOFileScannerVerifierStage.m
4
5
6Copyright (C) 2007-2013 Jens Ayton
7
8Permission is hereby granted, free of charge, to any person obtaining a copy
9of this software and associated documentation files (the "Software"), to deal
10in the Software without restriction, including without limitation the rights
11to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12copies of the Software, and to permit persons to whom the Software is
13furnished to do so, subject to the following conditions:
14
15The above copyright notice and this permission notice shall be included in all
16copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24SOFTWARE.
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
49
50#if OO_OXP_VERIFIER_ENABLED
51
53#import "ResourceManager.h"
54
55static NSString * const kFileScannerStageName = @"Scanning files";
56static NSString * const kUnusedListerStageName = @"Checking for unused files";
57
58
59static BOOL CheckNameConflict(NSString *lcName, NSDictionary *directoryCases, NSDictionary *rootFiles, NSString **outExisting, NSString **outExistingType);
60
61
62@interface OOFileScannerVerifierStage (OOPrivate)
63
64- (void)scanForFiles;
65
66- (void)checkRootFolders;
67- (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- (NSDictionary *)lowercaseMap:(NSArray *)array;
77
78- (NSDictionary *)scanDirectory:(NSString *)path;
79- (void)checkPListFormat:(NSPropertyListFormat)format file:(NSString *)file folder:(NSString *)folder;
80- (NSSet *)constructReadMeNames;
81
82@end
83
84
85@implementation OOFileScannerVerifierStage
86
87- (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- (NSString *)name
101{
103}
104
105
106- (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
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 NSString *displayName = nil,
250 *errorKey = nil;
251 NSAutoreleasePool *pool = nil;
252
253 data = [self dataForFile:file inFolder:folder referencedFrom:context checkBuiltIn:checkBuiltIn];
254 if (data == nil) return nil;
255
256 pool = [[NSAutoreleasePool alloc] init];
257
258 plist = [NSPropertyListSerialization propertyListFromData:data
259 mutabilityOption:NSPropertyListImmutable
260 format:&format
261 errorDescription:&errorString];
262
263#if OOLITE_RELEASE_PLIST_ERROR_STRINGS
264 [errorString autorelease];
265#endif
266
267 if (plist != nil)
268 {
269 // PList is readable; check that it's in an official Oolite format.
270 [self checkPListFormat:format file:file folder:folder];
271 }
272 else
273 {
274 /* Couldn't parse plist; report problem.
275 This is complicated somewhat by the need to present a possibly
276 multi-line error description while maintaining our indentation.
277 */
278 displayName = [self displayNameForFile:file andFolder:folder];
279 errorKey = [displayName lowercaseString];
280 if (![_badPLists containsObject:errorKey])
281 {
282 [_badPLists addObject:errorKey];
283 OOLog(@"verifyOXP.plist.parseError", @"Could not interpret property list %@.", displayName);
284 OOLogIndent();
285 errorLines = [errorString componentsSeparatedByString:@"\n"];
286 foreach (errorString, errorLines)
287 {
288 while ([errorString hasPrefix:@"\t"])
289 {
290 errorString = [@" " stringByAppendingString:[errorString substringFromIndex:1]];
291 }
292 OOLog(@"verifyOXP.plist.parseError", @"%@", errorString);
293 }
294 OOLogOutdent();
295 }
296 }
297
298 [plist retain];
299 [pool release];
300
301 return [plist autorelease];
302}
303
304
305- (id)displayNameForFile:(NSString *)file andFolder:(NSString *)folder
306{
307 if (file != nil && folder != nil) return [folder stringByAppendingPathComponent:file];
308 return file;
309}
310
311
312- (NSArray *)filesInFolder:(NSString *)folder
313{
314 if (folder == nil) return nil;
315 return [[_directoryListings objectForKey:[folder lowercaseString]] allValues];
316}
317
318@end
319
320
321@implementation OOFileScannerVerifierStage (OOPrivate)
322
323- (void)scanForFiles
324{
325 NSDirectoryEnumerator *dirEnum = nil;
326 NSString *name = nil,
327 *path = nil,
328 *type = nil,
329 *lcName = nil,
330 *existing = nil,
331 *existingType = nil;
332 NSMutableDictionary *directoryListings = nil,
333 *directoryCases = nil,
334 *rootFiles = nil;
335 NSDictionary *dirFiles = nil;
336 NSSet *readMeNames = nil;
337
338 _basePath = [[[self verifier] oxpPath] copy];
339
340 _junkFileNames = [[self verifier] configurationSetForKey:@"junkFiles"];
341 _skipDirectoryNames = [[self verifier] configurationSetForKey:@"skipDirectories"];
342
343 directoryCases = [NSMutableDictionary dictionary];
344 directoryListings = [NSMutableDictionary dictionary];
345 rootFiles = [NSMutableDictionary dictionary];
346 readMeNames = [self constructReadMeNames];
347
348 dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:_basePath];
349 while ((name = [dirEnum nextObject]))
350 {
351 path = [_basePath stringByAppendingPathComponent:name];
352 type = [[dirEnum fileAttributes] fileType];
353 lcName = [name lowercaseString];
354
355 if ([type isEqualToString:NSFileTypeDirectory])
356 {
357 [dirEnum skipDescendents];
358
359 if ([_skipDirectoryNames containsObject:name])
360 {
361 // Silently skip .svn and CVS
362 OOLog(@"verifyOXP.verbose.listFiles", @"- Skipping %@/", name);
363 }
364 else if (!CheckNameConflict(lcName, directoryCases, rootFiles, &existing, &existingType))
365 {
366 OOLog(@"verifyOXP.verbose.listFiles", @"- %@/", name);
367 OOLogIndentIf(@"verifyOXP.verbose.listFiles");
368 dirFiles = [self scanDirectory:path];
369 [directoryListings setObject:dirFiles forKey:lcName];
370 [directoryCases setObject:name forKey:lcName];
371 OOLogOutdentIf(@"verifyOXP.verbose.listFiles");
372 }
373 else
374 {
375 OOLog(@"verifyOXP.scanFiles.overloadedName", @"***** ERROR: %@ '%@' conflicts with %@ named '%@', ignoring. (OXPs must work on case-insensitive file systems!)", @"directory", name, existingType, existing);
376 }
377 }
378 else if ([type isEqualToString:NSFileTypeRegular])
379 {
380 if ([_junkFileNames containsObject:name])
381 {
382 OOLog(@"verifyOXP.scanFiles.skipJunk", @"NOTE: skipping junk file %@.", name);
383 }
384 else if ([readMeNames containsObject:lcName])
385 {
386 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);
387 }
388 else if (!CheckNameConflict(lcName, directoryCases, rootFiles, &existing, &existingType))
389 {
390 OOLog(@"verifyOXP.verbose.listFiles", @"- %@", name);
391 [rootFiles setObject:name forKey:lcName];
392 }
393 else
394 {
395 OOLog(@"verifyOXP.scanFiles.overloadedName", @"***** ERROR: %@ '%@' conflicts with %@ named '%@', ignoring. (OXPs must work on case-insensitive file systems!)", @"file", name, existingType, existing);
396 }
397 }
398 else if ([type isEqualToString:NSFileTypeSymbolicLink])
399 {
400 OOLog(@"verifyOXP.scanFiles.symLink", @"----- WARNING: \"%@\" is a symbolic link, ignoring.", name);
401 }
402 else
403 {
404 OOLog(@"verifyOXP.scanFiles.nonStandardFile", @"----- WARNING: \"%@\" is a non-standard file (%@), ignoring.", name, type);
405 }
406 }
407
408 _junkFileNames = nil;
409 _skipDirectoryNames = nil;
410
411 [directoryListings setObject:rootFiles forKey:@""];
412 _directoryListings = [directoryListings copy];
413 _directoryCases = [directoryCases copy];
414}
415
416
417- (void)checkRootFolders
418{
419 NSArray *knownNames = nil;
420 NSString *name = nil;
421 NSString *lcName = nil;
422 NSString *actual = nil;
423
424 knownNames = [[self verifier] configurationArrayForKey:@"knownRootDirectories"];
425 foreach (name, knownNames)
426 {
427 if (![name isKindOfClass:[NSString class]]) continue;
428
429 lcName = [name lowercaseString];
430 actual = [_directoryCases objectForKey:lcName];
431 if (actual == nil) continue;
432
433 if (![actual isEqualToString:name])
434 {
435 OOLog(@"verifyOXP.files.caseMismatch", @"***** ERROR: case mismatch: directory '%@' should be called '%@'.", actual, name);
436 }
437 [_caseWarnings addObject:lcName];
438 }
439}
440
441
442- (void)checkConfigFiles
443{
444 NSArray *knownNames = nil;
445 NSString *name = nil,
446 *lcName = nil,
447 *realFileName = nil;
448 BOOL inConfigDir;
449
450 knownNames = [[self verifier] configurationArrayForKey:@"knownConfigFiles"];
451 foreach (name, knownNames)
452 {
453 if (![name isKindOfClass:[NSString class]]) continue;
454
455 /* In theory, we could use -fileExists:inFolder:referencedFrom:checkBuiltIn:
456 here, but we want a different error message.
457 */
458
459 lcName = [name lowercaseString];
460 realFileName = [[_directoryListings oo_dictionaryForKey:@"config"] objectForKey:lcName];
461 inConfigDir = realFileName != nil;
462 if (!inConfigDir) realFileName = [[_directoryListings oo_dictionaryForKey:@""] objectForKey:lcName];
463 if (realFileName == nil) continue;
464
465 if (![realFileName isEqualToString:name])
466 {
467 if (inConfigDir) realFileName = [@"Config" stringByAppendingPathComponent:realFileName];
468 OOLog(@"verifyOXP.files.caseMismatch", @"***** ERROR: case mismatch: configuration file '%@' should be called '%@'.", realFileName, name);
469 }
470 }
471}
472
473
474- (void)checkKnownFiles
475{
476 NSDictionary *directories = nil;
477 NSString *directory = nil,
478 *lcDirectory = nil;
479 NSArray *fileList = nil;
480 NSString *name = nil,
481 *lcName = nil,
482 *realFileName = nil;
483 BOOL inDirectory;
484
485 directories = [[self verifier] configurationDictionaryForKey:@"knownFiles"];
486 foreachkey (directory, directories)
487 {
488 fileList = [directories objectForKey:directory];
489 lcDirectory = [directory lowercaseString];
490 foreach (name, fileList)
491 {
492 if (![name isKindOfClass:[NSString class]]) continue;
493
494 /* In theory, we could use -fileExists:inFolder:referencedFrom:checkBuiltIn:
495 here, but we want a different error message.
496 */
497
498 lcName = [name lowercaseString];
499 realFileName = [[_directoryListings oo_dictionaryForKey:lcDirectory] objectForKey:lcName];
500 inDirectory = (realFileName != nil);
501 if (!inDirectory)
502 {
503 // Allow for files in root directory of OXP
504 realFileName = [[_directoryListings oo_dictionaryForKey:@""] objectForKey:lcName];
505 }
506 if (realFileName == nil) continue;
507
508 if (![realFileName isEqualToString:name])
509 {
510 if (inDirectory) realFileName = [directory stringByAppendingPathComponent:realFileName];
511 OOLog(@"verifyOXP.files.caseMismatch", @"***** ERROR: case mismatch: file '%@' should be called '%@'.", realFileName, name);
512 }
513 }
514 }
515}
516
517
518- (NSDictionary *)lowercaseMap:(NSArray *)array
519{
520 NSUInteger i, count;
521 NSString *canonical = nil,
522 *lowercase = nil;
523 NSMutableDictionary *result = nil;
524
525 count = [array count];
526 if (count == 0) return [NSDictionary dictionary];
527 result = [NSMutableDictionary dictionaryWithCapacity:count];
528
529 for (i = 0; i != count; ++i)
530 {
531 canonical = [array oo_stringAtIndex:i];
532 if (canonical != nil)
533 {
534 lowercase = [canonical lowercaseString];
535 [result setObject:canonical forKey:lowercase];
536 }
537 }
538
539 return result;
540}
541
542
543- (NSDictionary *)scanDirectory:(NSString *)path
544{
545 NSDirectoryEnumerator *dirEnum = nil;
546 NSMutableDictionary *result = nil;
547 NSString *name = nil,
548 *lcName = nil,
549 *type = nil,
550 *dirName = nil,
551 *relativeName = nil,
552 *existing = nil;
553
554 result = [NSMutableDictionary dictionary];
555 dirName = [path lastPathComponent];
556
557 dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:path];
558 while ((name = [dirEnum nextObject]))
559 {
560 type = [[dirEnum fileAttributes] fileType];
561 relativeName = [dirName stringByAppendingPathComponent:name];
562
563 if ([_junkFileNames containsObject:name])
564 {
565 OOLog(@"verifyOXP.scanFiles.skipJunk", @"NOTE: skipping junk file %@/%@.", dirName, name);
566 }
567 else if ([type isEqualToString:NSFileTypeRegular])
568 {
569 lcName = [name lowercaseString];
570 existing = [result objectForKey:lcName];
571
572 if (existing == nil)
573 {
574 OOLog(@"verifyOXP.verbose.listFiles", @"- %@", name);
575 [result setObject:name forKey:lcName];
576 }
577 else
578 {
579 OOLog(@"verifyOXP.scanFiles.overloadedName", @"***** ERROR: %@ '%@' conflicts with %@ named '%@', ignoring. (OXPs must work on case-insensitive file systems!)", @"file", relativeName, @"file", [dirName stringByAppendingPathComponent:existing]);
580 }
581 }
582 else
583 {
584 if ([type isEqualToString:NSFileTypeDirectory])
585 {
586 [dirEnum skipDescendents];
587 if (![_skipDirectoryNames containsObject:name])
588 {
589 OOLog(@"verifyOXP.scanFiles.directory", @"----- WARNING: \"%@\" is a nested directory, ignoring.", relativeName);
590 }
591 else
592 {
593 OOLog(@"verifyOXP.verbose.listFiles", @"- Skipping %@/%@/", dirName, name);
594 }
595 }
596 else if ([type isEqualToString:NSFileTypeSymbolicLink])
597 {
598 OOLog(@"verifyOXP.scanFiles.symLink", @"----- WARNING: \"%@\" is a symbolic link, ignoring.", relativeName);
599 }
600 else
601 {
602 OOLog(@"verifyOXP.scanFiles.nonStandardFile", @"----- WARNING: \"%@\" is a non-standard file (%@), ignoring.", relativeName, type);
603 }
604 }
605 }
606
607 return result;
608}
609
610
611- (void)checkPListFormat:(NSPropertyListFormat)format file:(NSString *)file folder:(NSString *)folder
612{
613 NSString *weirdnessKey = nil;
614 NSString *formatDesc = nil;
615 NSString *displayPath = nil;
616
617 if (format != NSPropertyListOpenStepFormat && format != NSPropertyListXMLFormat_v1_0)
618 {
619 displayPath = [self displayNameForFile:file andFolder:folder];
620 weirdnessKey = [displayPath lowercaseString];
621
622 if (![_badPLists containsObject:weirdnessKey])
623 {
624 // Warn about "non-standard" format
625 [_badPLists addObject:weirdnessKey];
626
627 switch (format)
628 {
629 case NSPropertyListBinaryFormat_v1_0:
630 formatDesc = @"Apple binary format";
631 break;
632
633#if OOLITE_GNUSTEP
634 case NSPropertyListGNUstepFormat:
635 formatDesc = @"GNUstep text format";
636 break;
637
638 case NSPropertyListGNUstepBinaryFormat:
639 formatDesc = @"GNUstep binary format";
640 break;
641#endif
642
643 default:
644 formatDesc = [NSString stringWithFormat:@"unknown format (%i)", (int)format];
645 }
646
647 OOLog(@"verifyOXP.plist.weirdFormat", @"----- WARNING: Property list %@ is in %@; OpenStep text format and XML format are the recommended formats for Oolite.", displayPath, formatDesc);
648 }
649 }
650}
651
652
653- (NSSet *)constructReadMeNames
654{
655 NSDictionary *dict = nil;
656 NSArray *stems = nil,
657 *extensions = nil;
658 NSMutableSet *result = nil;
659 NSUInteger i, j, stemCount, extCount;
660 NSString *stem = nil,
661 *extension = nil;
662
663 dict = [[self verifier] configurationDictionaryForKey:@"readMeNames"];
664 stems = [dict oo_arrayForKey:@"stems"];
665 extensions = [dict oo_arrayForKey:@"extensions"];
666 stemCount = [stems count];
667 extCount = [extensions count];
668 if (stemCount * extCount == 0) return nil;
669
670 // Construct all stem+extension permutations
671 result = [NSMutableSet setWithCapacity:stemCount * extCount];
672 for (i = 0; i != stemCount; ++i)
673 {
674 stem = [[stems oo_stringAtIndex:i] lowercaseString];
675 if (stem != nil)
676 {
677 for (j = 0; j != extCount; ++j)
678 {
679 extension = [[extensions oo_stringAtIndex:j] lowercaseString];
680 if (extension != nil)
681 {
682 [result addObject:[stem stringByAppendingString:extension]];
683 }
684 }
685 }
686 }
687
688 return result;
689}
690
691@end
692
693
695
696- (NSString *)name
697{
699}
700
701
702- (NSSet *)dependencies
703{
704 return [NSSet setWithObject:kFileScannerStageName];
705}
706
707
708- (void)run
709{
710 OOLog(@"verifyOXP.unusedFiles.unimplemented", @"%@", @"TODO: implement unused files check.");
711}
712
713
714+ (NSString *)nameForReverseDependencyForVerifier:(OOOXPVerifier *)verifier
715{
716 OOListUnusedFilesStage *stage = [verifier stageWithName:kUnusedListerStageName];
717 if (stage == nil)
718 {
719 stage = [[OOListUnusedFilesStage alloc] init];
720 [verifier registerStage:stage];
721 [stage release];
722 }
723
725}
726
727@end
728
729
731
732- (OOFileScannerVerifierStage *)fileScannerStage
733{
734 return [self stageWithName:kFileScannerStageName];
735}
736
737@end
738
739
740@implementation OOFileHandlingVerifierStage
741
742- (NSSet *)dependencies
743{
744 return [NSSet setWithObject:[OOFileScannerVerifierStage nameForDependencyForVerifier:[self verifier]]];
745}
746
747
748- (NSSet *)dependents
749{
750 return [NSSet setWithObject:[OOListUnusedFilesStage nameForReverseDependencyForVerifier:[self verifier]]];
751}
752
753@end
754
755
756static BOOL CheckNameConflict(NSString *lcName, NSDictionary *directoryCases, NSDictionary *rootFiles, NSString **outExisting, NSString **outExistingType)
757{
758 NSString *existing = nil;
759
760 existing = [directoryCases objectForKey:lcName];
761 if (existing != nil)
762 {
763 if (outExisting != NULL) *outExisting = existing;
764 if (outExistingType != NULL) *outExistingType = @"directory";
765 return YES;
766 }
767
768 existing = [rootFiles objectForKey:lcName];
769 if (existing != nil)
770 {
771 if (outExisting != NULL) *outExisting = existing;
772 if (outExistingType != NULL) *outExistingType = @"file";
773 return YES;
774 }
775
776 return NO;
777}
778
779#endif
#define foreachkey(VAR, DICT)
Definition OOCocoa.h:353
static NSString *const kUnusedListerStageName
static BOOL CheckNameConflict(NSString *lcName, NSDictionary *directoryCases, NSDictionary *rootFiles, NSString **outExisting, NSString **outExistingType)
static NSString *const kFileScannerStageName
#define OOLogOutdentIf(class)
Definition OOLogging.h:102
void OOLogOutdent(void)
Definition OOLogging.m:376
#define OOLog(class, format,...)
Definition OOLogging.h:88
#define OOLogIndentIf(class)
Definition OOLogging.h:101
void OOLogIndent(void)
Definition OOLogging.m:366
unsigned count
return nil
NSString * nameForDependencyForVerifier:(OOOXPVerifier *verifier)
NSString * nameForReverseDependencyForVerifier:(OOOXPVerifier *verifier)
id stageWithName:(NSString *name)
void registerStage:(OOOXPVerifierStage *stage)
NSString * pathForFileNamed:inFolder:(NSString *fileName,[inFolder] NSString *folderName)