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:
Giles Williams 2005-07-09 22:00:55 +00:00
parent 451232e5f2
commit 0693af0d5f
2 changed files with 452 additions and 6 deletions

View File

@ -82,4 +82,19 @@ BOOL always_include_addons;
+ (NSMovie *) movieFromFilesNamed:(NSString *)filename inFolder:(NSString *)foldername; + (NSMovie *) movieFromFilesNamed:(NSString *)filename inFolder:(NSString *)foldername;
#endif #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 @end

View File

@ -248,13 +248,8 @@ NSMutableDictionary* surface_cache;
dictionary_cache = [[NSMutableDictionary alloc] initWithCapacity:32]; dictionary_cache = [[NSMutableDictionary alloc] initWithCapacity:32];
if ([dictionary_cache objectForKey:dict_key]) 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 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++) for (i = 0; i < [fpaths count]; i++)
{ {
@ -262,6 +257,11 @@ NSMutableDictionary* surface_cache;
if ([[NSFileManager defaultManager] fileExistsAtPath:filepath]) if ([[NSFileManager defaultManager] fileExistsAtPath:filepath])
{ {
NSDictionary* found_dic = [NSDictionary dictionaryWithContentsOfFile: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) if (found_dic)
[results addObject:found_dic]; [results addObject:found_dic];
else else
@ -273,6 +273,11 @@ NSMutableDictionary* surface_cache;
if ([[NSFileManager defaultManager] fileExistsAtPath:filepath]) if ([[NSFileManager defaultManager] fileExistsAtPath:filepath])
{ {
NSDictionary* found_dic = [NSDictionary dictionaryWithContentsOfFile: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) if (found_dic)
[results addObject:found_dic]; [results addObject:found_dic];
else else
@ -286,7 +291,6 @@ NSMutableDictionary* surface_cache;
// got results we may want to cache // got results we may want to cache
// //
NSMutableDictionary *result = [NSMutableDictionary dictionaryWithCapacity:128]; NSMutableDictionary *result = [NSMutableDictionary dictionaryWithCapacity:128];
//NSLog(@"---> ResourceManager found %d file(s) with name '%@' (in folder '%@')", [results count], filename, foldername);
if (!mergeFiles) if (!mergeFiles)
{ {
[result addEntriesFromDictionary:(NSDictionary *)[results objectAtIndex:[results count] - 1]];// the last loaded file [result addEntriesFromDictionary:(NSDictionary *)[results objectAtIndex:[results count] - 1]];// the last loaded file
@ -325,6 +329,11 @@ NSMutableDictionary* surface_cache;
if ([[NSFileManager defaultManager] fileExistsAtPath:filepath]) if ([[NSFileManager defaultManager] fileExistsAtPath:filepath])
{ {
NSArray* found_array = [NSArray arrayWithContentsOfFile: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) if (found_array)
[results addObject:found_array]; [results addObject:found_array];
else else
@ -338,6 +347,11 @@ NSMutableDictionary* surface_cache;
if ([[NSFileManager defaultManager] fileExistsAtPath:filepath]) if ([[NSFileManager defaultManager] fileExistsAtPath:filepath])
{ {
NSArray* found_array = [NSArray arrayWithContentsOfFile: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) if (found_array)
[results addObject:found_array]; [results addObject:found_array];
else else
@ -640,4 +654,421 @@ NSMutableDictionary* surface_cache;
} }
#endif #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:@"&amp;" withString:@"&" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [result length])];
[result replaceOccurrencesOfString:@"&lt;" withString:@"<" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [result length])];
[result replaceOccurrencesOfString:@"&gt;" withString:@">" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [result length])];
[result replaceOccurrencesOfString:@"&apos;" withString:@"'" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [result length])];
[result replaceOccurrencesOfString:@"&quot;" 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 @end