Giles's attempt to break the XML parsing deadlock for Oolite-windows
git-svn-id: http://svn.berlios.de/svnroot/repos/oolite-linux/trunk@92 127b21dd-08f5-0310-b4b7-95ae10353056
This commit is contained in:
parent
451232e5f2
commit
0693af0d5f
@ -82,4 +82,19 @@ BOOL always_include_addons;
|
||||
+ (NSMovie *) movieFromFilesNamed:(NSString *)filename inFolder:(NSString *)foldername;
|
||||
#endif
|
||||
|
||||
+ (NSMutableArray *) scanTokensFromString:(NSString*) values;
|
||||
+ (NSString *) decodeString:(NSString*) encodedString;
|
||||
+ (OOXMLElement) parseOOXMLElement:(NSScanner*) scanner upTo:(NSString*)closingTag;
|
||||
+ (NSObject*) parseXMLPropertyList:(NSString*)xmlString;
|
||||
+ (NSObject*) objectFromXMLElement:(NSArray*) xmlElement;
|
||||
+ (NSNumber*) trueFromXMLContent:(NSObject*) xmlContent;
|
||||
+ (NSNumber*) falseFromXMLContent:(NSObject*) xmlContent;
|
||||
+ (NSNumber*) realFromXMLContent:(NSObject*) xmlContent;
|
||||
+ (NSNumber*) integerFromXMLContent:(NSObject*) xmlContent;
|
||||
+ (NSString*) stringFromXMLContent:(NSObject*) xmlContent;
|
||||
+ (NSDate*) dateFromXMLContent:(NSObject*) xmlContent;
|
||||
+ (NSData*) dataFromXMLContent:(NSObject*) xmlContent;
|
||||
+ (NSArray*) arrayFromXMLContent:(NSObject*) xmlContent;
|
||||
+ (NSDictionary*) dictionaryFromXMLContent:(NSObject*) xmlContent;
|
||||
|
||||
@end
|
||||
|
@ -248,13 +248,8 @@ NSMutableDictionary* surface_cache;
|
||||
dictionary_cache = [[NSMutableDictionary alloc] initWithCapacity:32];
|
||||
if ([dictionary_cache objectForKey:dict_key])
|
||||
{
|
||||
// NSLog(@"DEBUG ResourceManager RETURNING CACHED '%@' dictionary", dict_key);
|
||||
return [NSDictionary dictionaryWithDictionary:(NSDictionary *)[dictionary_cache objectForKey:dict_key]]; // return the cached dictionary
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// NSLog(@"DEBUG ResourceManager LOADING '%@' dictionary", dict_key);
|
||||
// }
|
||||
|
||||
for (i = 0; i < [fpaths count]; i++)
|
||||
{
|
||||
@ -262,6 +257,11 @@ NSMutableDictionary* surface_cache;
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:filepath])
|
||||
{
|
||||
NSDictionary* found_dic = [NSDictionary dictionaryWithContentsOfFile:filepath];
|
||||
|
||||
// FIX FOR WINDOWS GNUSTEP NOT PARSING XML PLISTS
|
||||
if (!found_dic) // try parsing it using our home-grown XML parser
|
||||
found_dic = (NSDictionary*)[ResourceManager parseXMLPropertyList:[NSString stringWithContentsOfFile:filepath]];
|
||||
|
||||
if (found_dic)
|
||||
[results addObject:found_dic];
|
||||
else
|
||||
@ -273,6 +273,11 @@ NSMutableDictionary* surface_cache;
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:filepath])
|
||||
{
|
||||
NSDictionary* found_dic = [NSDictionary dictionaryWithContentsOfFile:filepath];
|
||||
|
||||
// FIX FOR WINDOWS GNUSTEP NOT PARSING XML PLISTS
|
||||
if (!found_dic) // try parsing it using our home-grown XML parser
|
||||
found_dic = (NSDictionary*)[ResourceManager parseXMLPropertyList:[NSString stringWithContentsOfFile:filepath]];
|
||||
|
||||
if (found_dic)
|
||||
[results addObject:found_dic];
|
||||
else
|
||||
@ -286,7 +291,6 @@ NSMutableDictionary* surface_cache;
|
||||
// got results we may want to cache
|
||||
//
|
||||
NSMutableDictionary *result = [NSMutableDictionary dictionaryWithCapacity:128];
|
||||
//NSLog(@"---> ResourceManager found %d file(s) with name '%@' (in folder '%@')", [results count], filename, foldername);
|
||||
if (!mergeFiles)
|
||||
{
|
||||
[result addEntriesFromDictionary:(NSDictionary *)[results objectAtIndex:[results count] - 1]];// the last loaded file
|
||||
@ -325,6 +329,11 @@ NSMutableDictionary* surface_cache;
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:filepath])
|
||||
{
|
||||
NSArray* found_array = [NSArray arrayWithContentsOfFile:filepath];
|
||||
|
||||
// FIX FOR WINDOWS GNUSTEP NOT PARSING XML PLISTS
|
||||
if (!found_array) // try parsing it using our home-grown XML parser
|
||||
found_array = (NSArray*)[ResourceManager parseXMLPropertyList:[NSString stringWithContentsOfFile:filepath]];
|
||||
|
||||
if (found_array)
|
||||
[results addObject:found_array];
|
||||
else
|
||||
@ -338,6 +347,11 @@ NSMutableDictionary* surface_cache;
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:filepath])
|
||||
{
|
||||
NSArray* found_array = [NSArray arrayWithContentsOfFile:filepath];
|
||||
|
||||
// FIX FOR WINDOWS GNUSTEP NOT PARSING XML PLISTS
|
||||
if (!found_array) // try parsing it using our home-grown XML parser
|
||||
found_array = (NSArray*)[ResourceManager parseXMLPropertyList:[NSString stringWithContentsOfFile:filepath]];
|
||||
|
||||
if (found_array)
|
||||
[results addObject:found_array];
|
||||
else
|
||||
@ -640,4 +654,421 @@ NSMutableDictionary* surface_cache;
|
||||
}
|
||||
#endif
|
||||
|
||||
+ (NSMutableArray *) scanTokensFromString:(NSString*) values
|
||||
{
|
||||
NSMutableArray* result = [NSMutableArray arrayWithCapacity:8];
|
||||
NSScanner* scanner = [NSScanner scannerWithString:values];
|
||||
NSString* token;
|
||||
while (![scanner isAtEnd])
|
||||
{
|
||||
[scanner scanCharactersFromSet:[NSCharacterSet whitespaceAndNewlineCharacterSet] intoString:(NSString * *)nil];
|
||||
if ([scanner scanUpToCharactersFromSet:[NSCharacterSet whitespaceAndNewlineCharacterSet] intoString:&token])
|
||||
[result addObject:[NSString stringWithString:token]];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+ (NSString *) decodeString:(NSString*) encodedString
|
||||
{
|
||||
if ([encodedString rangeOfString:@"&"].location == NSNotFound)
|
||||
return encodedString;
|
||||
//
|
||||
NSMutableString* result = [NSMutableString stringWithString:encodedString];
|
||||
//
|
||||
[result replaceOccurrencesOfString:@"&" withString:@"&" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [result length])];
|
||||
[result replaceOccurrencesOfString:@"<" withString:@"<" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [result length])];
|
||||
[result replaceOccurrencesOfString:@">" withString:@">" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [result length])];
|
||||
[result replaceOccurrencesOfString:@"'" withString:@"'" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [result length])];
|
||||
[result replaceOccurrencesOfString:@""" withString:@"\"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [result length])];
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
+ (OOXMLElement) parseOOXMLElement:(NSScanner*) scanner upTo:(NSString*)closingTag
|
||||
{
|
||||
OOXMLElement result, element;
|
||||
NSMutableArray* elements = [NSMutableArray arrayWithCapacity:4]; // arbitrarily choose 4
|
||||
BOOL done = NO;
|
||||
while ((!done)&&(![scanner isAtEnd]))
|
||||
{
|
||||
NSString* preamble;
|
||||
BOOL foundPreamble = [scanner scanUpToString:@"<" intoString:&preamble];
|
||||
BOOL foundOpenBracket = [scanner scanString:@"<" intoString:(NSString * *)nil];
|
||||
if (!foundOpenBracket)
|
||||
{
|
||||
// NSLog(@"XML >>>>> no '<' found.");
|
||||
//
|
||||
// no openbracket found
|
||||
if (foundPreamble)
|
||||
{
|
||||
// NSLog(@"XML >>>>> Returning preamble=\"%@\"", preamble);
|
||||
// return the text we got instead
|
||||
element.tag = nil;
|
||||
element.content = [ResourceManager decodeString:preamble];
|
||||
}
|
||||
else
|
||||
{
|
||||
// NSLog(@"XML >>>>> Returning \"\"");
|
||||
// no preamble, return an empty string
|
||||
element.tag = nil;
|
||||
element.content = @"";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// NSLog(@"XML >>>>> '<' found.");
|
||||
//
|
||||
NSString* tag;
|
||||
// look for closing '>'
|
||||
int openBracketLocation = [scanner scanLocation];
|
||||
BOOL foundTag = [scanner scanUpToString:@">" intoString:&tag];
|
||||
BOOL foundCloseBracket = [scanner scanString:@">" intoString:(NSString * *)nil];
|
||||
if (!foundCloseBracket)
|
||||
{
|
||||
// ERROR no closing bracket for tag
|
||||
NSException* myException = [NSException
|
||||
exceptionWithName: @"OOXMLException"
|
||||
reason: [NSString stringWithFormat:@"Tag without closing bracket: \"%@\"", tag]
|
||||
userInfo: nil];
|
||||
[myException raise];
|
||||
result.tag = nil;
|
||||
result.content = nil;
|
||||
return result;
|
||||
}
|
||||
if (!foundTag)
|
||||
{
|
||||
// ERROR empty tag
|
||||
NSException* myException = [NSException
|
||||
exceptionWithName: @"OOXMLException"
|
||||
reason: [NSString stringWithFormat:@"Empty tag \"<>\" encountered.", tag]
|
||||
userInfo: nil];
|
||||
[myException raise];
|
||||
result.tag = nil;
|
||||
result.content = nil;
|
||||
return result;
|
||||
}
|
||||
//
|
||||
// NSLog(@"XML >>>>> '>' found. tag = <%@>", tag);
|
||||
//
|
||||
// okay we have a < tag >
|
||||
//
|
||||
if ([tag hasPrefix:@"!"]||[tag hasPrefix:@"?"]||[tag hasSuffix:@"/"])
|
||||
{
|
||||
if ([tag hasPrefix:@"!--"])
|
||||
{
|
||||
// it's a comment
|
||||
[scanner setScanLocation:openBracketLocation + 3];
|
||||
NSString* comment;
|
||||
// BOOL foundComment = [scanner scanUpToString:@"-->" intoString:&comment];
|
||||
[scanner scanUpToString:@"-->" intoString:&comment];
|
||||
BOOL foundEndComment = [scanner scanString:@"-->" intoString:(NSString * *)nil];
|
||||
if (!foundEndComment)
|
||||
{
|
||||
// ERROR comment without closing -->
|
||||
NSException* myException = [NSException
|
||||
exceptionWithName: @"OOXMLException"
|
||||
reason: [NSString stringWithFormat:@"No closing --> for comment", tag]
|
||||
userInfo: nil];
|
||||
[myException raise];
|
||||
result.tag = nil;
|
||||
result.content = nil;
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
// got a well formed comment so...
|
||||
// if (foundComment)
|
||||
// NSLog(@"XML >>>>> Comment \"%@\"", comment);
|
||||
element.tag = nil;
|
||||
element.content = nil; // ignore the comment
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// it's a singleton
|
||||
NSArray* tagbits = [ResourceManager scanTokensFromString:tag];
|
||||
// lowercase first 'word' of the tag - with entities decoded
|
||||
tag = [ResourceManager decodeString:[(NSString*)[tagbits objectAtIndex:0] lowercaseString]];
|
||||
element.tag = tag;
|
||||
element.content = tagbits;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ([tag hasPrefix:@"/"])
|
||||
{
|
||||
// it's a closing tag
|
||||
if ([tag hasSuffix:closingTag])
|
||||
{
|
||||
element.tag = nil;
|
||||
if (foundPreamble)
|
||||
element.content = [ResourceManager decodeString:preamble];
|
||||
else
|
||||
element.content = nil;
|
||||
done = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ERROR closing tag without opening tag
|
||||
NSException* myException = [NSException
|
||||
exceptionWithName: @"OOXMLException"
|
||||
reason: [NSString stringWithFormat:@"Closing tag \"<%@>\" without opening tag.", tag]
|
||||
userInfo: nil];
|
||||
[myException raise];
|
||||
result.tag = nil;
|
||||
result.content = nil;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// at this point we have an opening tag for some content
|
||||
// so we'll recursively parse the rest of the text
|
||||
NSArray* tagbits = [ResourceManager scanTokensFromString:tag];
|
||||
if (![tagbits count])
|
||||
{
|
||||
// ERROR empty opening tag
|
||||
NSException* myException = [NSException
|
||||
exceptionWithName: @"OOXMLException"
|
||||
reason: [NSString stringWithFormat:@"Empty tag encountered.", tag]
|
||||
userInfo: nil];
|
||||
[myException raise];
|
||||
result.tag = nil;
|
||||
result.content = nil;
|
||||
return result;
|
||||
}
|
||||
// lowercase first 'word' of the tag - with entities decoded
|
||||
tag = [ResourceManager decodeString:[(NSString*)[tagbits objectAtIndex:0] lowercaseString]];
|
||||
//
|
||||
OOXMLElement inner_element = [ResourceManager parseOOXMLElement:scanner upTo:tag];
|
||||
element.tag = inner_element.tag;
|
||||
// if ([inner_element.content isKindOfClass:[NSArray class]])
|
||||
// {
|
||||
// NSArray* inner_element_array = (NSArray*)inner_element.content;
|
||||
// if ([inner_element_array count] == 1)
|
||||
// inner_element.content = [inner_element_array objectAtIndex:0];
|
||||
// }
|
||||
element.content = inner_element.content;
|
||||
}
|
||||
}
|
||||
}
|
||||
// we reach here with element set so we need to add it in to the elements array
|
||||
if ((element.tag)&&(element.content))
|
||||
{
|
||||
[elements addObject:[NSArray arrayWithObjects: element.tag, element.content, nil]];
|
||||
}
|
||||
}
|
||||
|
||||
// all done!
|
||||
result.tag = closingTag;
|
||||
if ([elements count])
|
||||
result.content = elements;
|
||||
else
|
||||
result.content = element.content;
|
||||
|
||||
// NSLog(@"DEBUG XML found '%@' = '%@'", result.tag, result.content);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
+ (NSObject*) parseXMLPropertyList:(NSString*)xmlString
|
||||
{
|
||||
NSScanner* scanner = [NSScanner scannerWithString:xmlString];
|
||||
OOXMLElement xml;
|
||||
NS_DURING
|
||||
xml = [ResourceManager parseOOXMLElement:scanner upTo:@"ROOT"];
|
||||
NS_HANDLER
|
||||
if ([[localException name] isEqual:@"OOXMLException"])
|
||||
{
|
||||
NSLog(@"\nDEBUG ***** %@ : %@ *****\n\n",[localException name], [localException reason]);
|
||||
NSRunAlertPanel(@"Oolite XML Exception", @"'%@'", @"Continue", nil, nil,localException);
|
||||
return nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
if (!xml.content)
|
||||
return nil;
|
||||
if (![xml.content isKindOfClass:[NSArray class]])
|
||||
return nil;
|
||||
NSArray* elements = (NSArray*)xml.content;
|
||||
int n_elements = [elements count];
|
||||
int i;
|
||||
for (i = 0; i < n_elements; i++)
|
||||
{
|
||||
NSArray* element = (NSArray*)[elements objectAtIndex:i];
|
||||
NSString* tag = (NSString*)[element objectAtIndex:0];
|
||||
NSObject* content = [element objectAtIndex:1];
|
||||
// NSLog(@"DEBUG XML found '%@' = %@", tag, content);
|
||||
if ([tag isEqual:@"plist"])
|
||||
{
|
||||
if ([content isKindOfClass:[NSArray class]])
|
||||
{
|
||||
NSArray* plist = (NSArray*)[(NSArray*)content objectAtIndex:0];
|
||||
// NSString* plistTag = (NSString*)[plist objectAtIndex:0];
|
||||
// NSLog(@"DEBUG XML found plist containing '%@'", plistTag);
|
||||
return [ResourceManager objectFromXMLElement:plist];
|
||||
}
|
||||
}
|
||||
}
|
||||
// with a well formed plist we should not reach here!
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSObject*) objectFromXMLElement:(NSArray*) xmlElement
|
||||
{
|
||||
// NSLog(@"XML DEBUG trying to get an NSObject out of %@", xmlElement);
|
||||
//
|
||||
if ([xmlElement count] != 2)
|
||||
{
|
||||
// bad xml element
|
||||
NSException* myException = [NSException
|
||||
exceptionWithName: @"OOXMLException"
|
||||
reason: [NSString stringWithFormat:@"Bad XMLElement %@ passed to objectFromXMLElement:", xmlElement]
|
||||
userInfo: nil];
|
||||
[myException raise];
|
||||
return nil;
|
||||
}
|
||||
NSString* tag = (NSString*)[xmlElement objectAtIndex:0];
|
||||
NSObject* content = [xmlElement objectAtIndex:1];
|
||||
//
|
||||
if ([tag isEqual:@"true/"])
|
||||
return [ResourceManager trueFromXMLContent:content];
|
||||
//
|
||||
if ([tag isEqual:@"false/"])
|
||||
return [ResourceManager trueFromXMLContent:content];
|
||||
//
|
||||
if ([tag isEqual:@"real"])
|
||||
return [ResourceManager realFromXMLContent:content];
|
||||
//
|
||||
if ([tag isEqual:@"integer"])
|
||||
return [ResourceManager integerFromXMLContent:content];
|
||||
//
|
||||
if ([tag isEqual:@"string"])
|
||||
return [ResourceManager stringFromXMLContent:content];
|
||||
//
|
||||
if ([tag isEqual:@"date"])
|
||||
return [ResourceManager dateFromXMLContent:content];
|
||||
//
|
||||
// if ([tag isEqual:@"data"])
|
||||
// return [Resourcemanager dataFromXMLContent:content];
|
||||
//
|
||||
if ([tag isEqual:@"array"])
|
||||
return [ResourceManager arrayFromXMLContent:content];
|
||||
//
|
||||
if ([tag isEqual:@"dict"])
|
||||
return [ResourceManager dictionaryFromXMLContent:content];
|
||||
//
|
||||
if ([tag isEqual:@"key"])
|
||||
return [ResourceManager stringFromXMLContent:content];
|
||||
//
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSNumber*) trueFromXMLContent:(NSObject*) xmlContent
|
||||
{
|
||||
return [NSNumber numberWithBool:YES];
|
||||
}
|
||||
|
||||
+ (NSNumber*) falseFromXMLContent:(NSObject*) xmlContent
|
||||
{
|
||||
return [NSNumber numberWithBool:NO];
|
||||
}
|
||||
|
||||
+ (NSNumber*) realFromXMLContent:(NSObject*) xmlContent
|
||||
{
|
||||
if ([xmlContent isKindOfClass:[NSString class]])
|
||||
{
|
||||
return [NSNumber numberWithDouble:[(NSString*)xmlContent doubleValue]];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSNumber*) integerFromXMLContent:(NSObject*) xmlContent
|
||||
{
|
||||
if ([xmlContent isKindOfClass:[NSString class]])
|
||||
{
|
||||
return [NSNumber numberWithInt:[(NSString*)xmlContent intValue]];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSString*) stringFromXMLContent:(NSObject*) xmlContent
|
||||
{
|
||||
if ([xmlContent isKindOfClass:[NSString class]])
|
||||
{
|
||||
return [NSString stringWithString:(NSString*)xmlContent];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSDate*) dateFromXMLContent:(NSObject*) xmlContent
|
||||
{
|
||||
if ([xmlContent isKindOfClass:[NSString class]])
|
||||
{
|
||||
return [NSDate dateWithString:(NSString*)xmlContent];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSData*) dataFromXMLContent:(NSObject*) xmlContent
|
||||
{
|
||||
// we don't use this for Oolite
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSArray*) arrayFromXMLContent:(NSObject*) xmlContent
|
||||
{
|
||||
if ([xmlContent isKindOfClass:[NSArray class]])
|
||||
{
|
||||
NSArray* xmlElementArray = (NSArray*)xmlContent;
|
||||
int n_objects = [xmlElementArray count];
|
||||
NSMutableArray* result = [NSMutableArray arrayWithCapacity:n_objects];
|
||||
int i;
|
||||
for (i = 0; i < n_objects; i++)
|
||||
{
|
||||
NSArray* xmlElement = [xmlElementArray objectAtIndex:i];
|
||||
NSObject* object = [ResourceManager objectFromXMLElement:xmlElement];
|
||||
if (object)
|
||||
[result addObject:object];
|
||||
else
|
||||
return nil;
|
||||
}
|
||||
return [NSArray arrayWithArray:result];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSDictionary*) dictionaryFromXMLContent:(NSObject*) xmlContent
|
||||
{
|
||||
if ([xmlContent isKindOfClass:[NSArray class]])
|
||||
{
|
||||
NSArray* xmlElementArray = (NSArray*)xmlContent;
|
||||
int n_objects = [xmlElementArray count];
|
||||
if (n_objects & 1)
|
||||
return nil; // must be an even number of objects in the array
|
||||
NSMutableDictionary* result = [NSMutableDictionary dictionaryWithCapacity: n_objects / 2];
|
||||
int i;
|
||||
for (i = 0; i < n_objects; i += 2)
|
||||
{
|
||||
NSArray* keyXmlElement = [xmlElementArray objectAtIndex:i];
|
||||
NSObject* key = [ResourceManager objectFromXMLElement:keyXmlElement];
|
||||
NSArray* objectXmlElement = [xmlElementArray objectAtIndex:i + 1];
|
||||
NSObject* object = [ResourceManager objectFromXMLElement:objectXmlElement];
|
||||
if (key && object)
|
||||
{
|
||||
[result setObject:object forKey:key];
|
||||
}
|
||||
else
|
||||
return nil;
|
||||
}
|
||||
return [NSDictionary dictionaryWithDictionary:result];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@end
|
||||
|
Loading…
x
Reference in New Issue
Block a user