Oolite 1.91.0.7644-241112-7f5034b
Loading...
Searching...
No Matches
OOAIStateMachineVerifierStage.m
Go to the documentation of this file.
1/*
2
3OOAIStateMachineVerifierStage.m
4
5
6Oolite
7Copyright (C) 2004-2013 Giles C Williams and contributors
8
9This program is free software; you can redistribute it and/or
10modify it under the terms of the GNU General Public License
11as published by the Free Software Foundation; either version 2
12of the License, or (at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22MA 02110-1301, USA.
23
24*/
25
28#import "OOPListParsing.h"
29
30#if OO_OXP_VERIFIER_ENABLED
31
32#import "ResourceManager.h"
33
34static NSString * const kStageName = @"Validating AIs";
35
36
37@interface OOAIStateMachineVerifierStage (Private)
38
39- (void) validateAI:(NSString *)aiName;
40
41@end
42
43
45
46- (void) dealloc
47{
48 [_whitelist release];
49 [_usedAIs release];
50
51 [super dealloc];
52}
53
54
55- (NSString *) name
56{
57 return kStageName;
58}
59
60
61- (BOOL) shouldRun
62{
63 return [_usedAIs count] != 0;
64}
65
66
67- (void) run
68{
69 NSArray *aiNames = nil;
70 NSEnumerator *aiEnum = nil;
71 NSString *aiName = nil;
72 NSMutableSet *whitelist = nil;
73
74 // Build whitelist. Note that we merge in aliases since the distinction doesn't matter when just validating.
75 whitelist = [[NSMutableSet alloc] init];
76 [whitelist addObjectsFromArray:[[ResourceManager whitelistDictionary] oo_arrayForKey:@"ai_methods"]];
77 [whitelist addObjectsFromArray:[[ResourceManager whitelistDictionary] oo_arrayForKey:@"ai_and_action_methods"]];
78 [whitelist addObjectsFromArray:[[[ResourceManager whitelistDictionary] oo_dictionaryForKey:@"ai_method_aliases"] allKeys]];
79 _whitelist = [whitelist copy];
80 [whitelist release];
81
82 aiNames = [[_usedAIs allObjects] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
83 for (aiEnum = [aiNames objectEnumerator]; (aiName = [aiEnum nextObject]); )
84 {
85 [self validateAI:aiName];
86 }
87
88 [_whitelist release];
89 _whitelist = nil;
90}
91
92
93+ (NSString *) nameForReverseDependencyForVerifier:(OOOXPVerifier *)verifier
94{
95 return kStageName;
96}
97
98
99- (void) stateMachineNamed:(NSString *)name usedByShip:(NSString *)shipName
100{
101 OOFileScannerVerifierStage *fileScanner = nil;
102
103 if (name == nil) return;
104 if ([_usedAIs containsObject:name]) return;
105 if (_usedAIs == nil) _usedAIs = [[NSMutableSet alloc] init];
106 [_usedAIs addObject:name];
107
108 fileScanner = [[self verifier] fileScannerStage];
109 if (![fileScanner fileExists:name
110 inFolder:@"AIs"
111 referencedFrom:[NSString stringWithFormat:@"shipdata.plist entry \"%@\"", shipName]
112 checkBuiltIn:YES])
113 {
114 OOLog(@"verifyOXP.validateAI.notFound", @"----- WARNING: AI state machine \"%@\" referenced in shipdata.plist entry \"%@\" could not be found in %@ or in Oolite.", name, shipName, [[self verifier] oxpDisplayName]);
115 }
116}
117
118@end
119
120
121@implementation OOAIStateMachineVerifierStage (Private)
122
123- (void) validateAI:(NSString *)aiName
124{
125 NSString *path = nil;
126 NSDictionary *aiStateMachine = nil;
127 NSEnumerator *stateEnum = nil;
128 NSString *stateKey = nil;
129 NSDictionary *stateHandlers = nil;
130 NSEnumerator *handlerEnum = nil;
131 NSString *handlerKey = nil;
132 NSArray *handlerActions = nil;
133 NSEnumerator *actionEnum = nil;
134 NSString *action = nil;
135 NSRange spaceRange;
136 NSString *selector = nil;
137 NSMutableSet *badSelectors = nil;
138 NSString *badSelectorDesc = nil;
139 NSUInteger index = 0;
140
141 OOLog(@"verifyOXP.verbose.validateAI", @"- Validating AI \"%@\".", aiName);
142 OOLogIndentIf(@"verifyOXP.verbose.validateAI");
143
144 // Attempt to load AI.
145 path = [[[self verifier] fileScannerStage] pathForFile:aiName inFolder:@"AIs" referencedFrom:@"AI list" checkBuiltIn:NO];
146 if (path == nil) return;
147
148 badSelectors = [NSMutableSet set];
149
150 aiStateMachine = OODictionaryFromFile(path);
151 if (aiStateMachine == nil)
152 {
153 OOLog(@"verifyOXP.validateAI.failed.notDictPlist", @"***** ERROR: could not interpret \"%@\" as a dictionary.", path);
154 return;
155 }
156
157 // Validate each state.
158 for (stateEnum = [aiStateMachine keyEnumerator]; (stateKey = [stateEnum nextObject]); )
159 {
160 stateHandlers = [aiStateMachine objectForKey:stateKey];
161 if (![stateHandlers isKindOfClass:[NSDictionary class]])
162 {
163 OOLog(@"verifyOXP.validateAI.failed.invalidFormat.state", @"***** ERROR: state \"%@\" in AI \"%@\" is not a dictionary.", stateKey, aiName);
164 continue;
165 }
166
167 // Verify handlers for this state.
168 for (handlerEnum = [stateHandlers keyEnumerator]; (handlerKey = [handlerEnum nextObject]); )
169 {
170 handlerActions = [stateHandlers objectForKey:handlerKey];
171 if (![handlerActions isKindOfClass:[NSArray class]])
172 {
173 OOLog(@"verifyOXP.validateAI.failed.invalidFormat.handler", @"***** ERROR: handler \"%@\" for state \"%@\" in AI \"%@\" is not an array, ignoring.", handlerKey, stateKey, aiName);
174 continue;
175 }
176
177 // Verify commands for this handler.
178 index = 0;
179 for (actionEnum = [handlerActions objectEnumerator]; (action = [actionEnum nextObject]); )
180 {
181 index++;
182 if (![action isKindOfClass:[NSString class]])
183 {
184 OOLog(@"verifyOXP.validateAI.failed.invalidFormat.action", @"***** ERROR: action %lu in handler \"%@\" for state \"%@\" in AI \"%@\" is not a string, ignoring.", index - 1, handlerKey, stateKey, aiName);
185 continue;
186 }
187
188 // Trim spaces from beginning and end.
189 action = [action stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
190
191 // Cut off parameters.
192 spaceRange = [action rangeOfString:@" "];
193 if (spaceRange.location == NSNotFound) selector = action;
194 else selector = [action substringToIndex:spaceRange.location];
195
196 // Check against whitelist.
197 if (![_whitelist containsObject:selector])
198 {
199 [badSelectors addObject:selector];
200 }
201 }
202 }
203 }
204
205 if ([badSelectors count] != 0)
206 {
207 badSelectorDesc = [[[badSelectors allObjects] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)] componentsJoinedByString:@", "];
208 OOLog(@"verifyOXP.validateAI.failed.badSelector", @"***** ERROR: the AI \"%@\" uses %lu unpermitted method%s: %@", aiName, [badSelectors count], ([badSelectors count] == 1) ? "" : "s", badSelectorDesc);
209 }
210
211 OOLogOutdentIf(@"verifyOXP.verbose.validateAI");
212}
213
214@end
215
216#endif
static NSString *const kStageName
#define OOLogOutdentIf(class)
Definition OOLogging.h:102
#define OOLog(class, format,...)
Definition OOLogging.h:88
#define OOLogIndentIf(class)
Definition OOLogging.h:101
NSDictionary * OODictionaryFromFile(NSString *path)
unsigned count
return nil
NSDictionary * whitelistDictionary()