Oolite 1.91.0.7646-241128-10e222e
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 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- (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- (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
700
701- (NSString *)name
702{
704}
705
706
707- (NSSet *)dependencies
708{
709 return [NSSet setWithObject:kFileScannerStageName];
710}
711
712
713- (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
730}
731
732@end
733
734
736
737- (OOFileScannerVerifierStage *)fileScannerStage
738{
739 return [self stageWithName:kFileScannerStageName];
740}
741
742@end
743
744
745@implementation OOFileHandlingVerifierStage
746
747- (NSSet *)dependencies
748{
749 return [NSSet setWithObject:[OOFileScannerVerifierStage nameForDependencyForVerifier:[self verifier]]];
750}
751
752
753- (NSSet *)dependents
754{
755 return [NSSet setWithObject:[OOListUnusedFilesStage nameForReverseDependencyForVerifier:[self verifier]]];
756}
757
758@end
759
760
761static 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
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)