From 305e52501e44d6661c1360663b6dce6fff2f61e4 Mon Sep 17 00:00:00 2001 From: Yury Popov Date: Fri, 15 May 2015 15:12:00 +0300 Subject: [PATCH] XML parser without NSScanner --- pxSVG/pxSVGImage.h | 4 +- pxSVG/pxSVGImage.m | 6 +-- pxSVG/pxSVGLayer.m | 23 ++++++----- pxSVG/pxXMLNode.h | 3 +- pxSVG/pxXMLNode.m | 99 ++++++++++++++++++++++++++++------------------ 5 files changed, 78 insertions(+), 57 deletions(-) diff --git a/pxSVG/pxSVGImage.h b/pxSVG/pxSVGImage.h index 555f48d..16be052 100644 --- a/pxSVG/pxSVGImage.h +++ b/pxSVG/pxSVGImage.h @@ -9,8 +9,8 @@ #import @interface pxSVGImage : NSObject -+ (instancetype) svgImageWithXML:(NSString*)data; -- (instancetype) initWithXML:(NSString*)data; ++ (instancetype) svgImageWithXML:(NSData*)data; +- (instancetype) initWithXML:(NSData*)data; @property (nonatomic,readonly) CGRect bounds; - (CALayer*)makeLayer; @end diff --git a/pxSVG/pxSVGImage.m b/pxSVG/pxSVGImage.m index fb91a7e..491b5a9 100644 --- a/pxSVG/pxSVGImage.m +++ b/pxSVG/pxSVGImage.m @@ -15,14 +15,14 @@ @interface pxSVGImage () @end @implementation pxSVGImage -+ (instancetype)svgImageWithXML:(NSString *)xml ++ (instancetype)svgImageWithXML:(NSData *)xml { return [[self alloc] initWithXML:xml]; } -- (instancetype)initWithXML:(NSString *)xml +- (instancetype)initWithXML:(NSData *)xml { pxXMLNode *xmlTree = - [[pxXMLNode parseTree:[[NSScanner alloc] initWithString:xml]] + [[pxXMLNode parseTree:xml] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"tagName=%@",@"svg"]] .firstObject; if (!xmlTree) return nil; diff --git a/pxSVG/pxSVGLayer.m b/pxSVG/pxSVGLayer.m index 1b463d3..852965f 100644 --- a/pxSVG/pxSVGLayer.m +++ b/pxSVG/pxSVGLayer.m @@ -72,21 +72,20 @@ - (void)loadURL:(NSURL *)url err = [NSError errorWithDomain:@"pxSVGLoader.httpStatus" code:((NSHTTPURLResponse*)resp).statusCode userInfo:nil]; if (!err && !data) err = [NSError errorWithDomain:@"pxSVGLoader.emptyData" code:0 userInfo:nil]; - NSString *str = data?[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]:nil; - data = nil, resp = nil; + resp = nil; if ([op isCancelled]) { - op = nil, str = nil, err = nil; + op = nil, data = nil, err = nil; return; } op = nil; if (err) { - str = nil; + data = nil; [weakself performSelectorOnMainThread:@selector(loadError:) withObject:err waitUntilDone:NO modes:@[NSRunLoopCommonModes]]; err = nil; return; } - [weakself performSelectorOnMainThread:@selector(loadString:) withObject:str waitUntilDone:NO modes:@[NSRunLoopCommonModes]]; - str = nil, err = nil; + [weakself performSelectorOnMainThread:@selector(loadData:) withObject:data waitUntilDone:NO modes:@[NSRunLoopCommonModes]]; + data = nil, err = nil; } }]; op.name = url.absoluteString; op.threadPriority = 0.1f; @@ -94,16 +93,11 @@ - (void)loadURL:(NSURL *)url } - (void)loadData:(NSData *)data -{ - [self loadString:[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]]; -} - -- (void)loadString:(NSString *)string { [self clean]; __weak pxSVGLayer *weakself = self; __block NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ @autoreleasepool { - pxSVGImage *img = [pxSVGImage svgImageWithXML:string]; + pxSVGImage *img = [pxSVGImage svgImageWithXML:data]; if ([op isCancelled]) { op = nil, img = nil; return; @@ -121,6 +115,11 @@ - (void)loadString:(NSString *)string [[self.class parseQueue] addOperation:self.parseOperation=op]; } +- (void)loadString:(NSString *)string +{ + [self loadData:[string dataUsingEncoding:NSUTF8StringEncoding]]; +} + - (void)loadImage:(pxSVGImage*)image { [self clean]; diff --git a/pxSVG/pxXMLNode.h b/pxSVG/pxXMLNode.h index 741df98..8cb236a 100644 --- a/pxSVG/pxXMLNode.h +++ b/pxSVG/pxXMLNode.h @@ -9,8 +9,7 @@ #import @interface pxXMLNode : NSObject -+ (NSArray*) parseTree:(NSScanner*)scanner; -+ (instancetype) parseNode:(NSString*)string childScanner:(NSScanner*)childScanner; ++ (NSArray*) parseTree:(NSData*)data; @property (readonly) NSString *tagName; @property (readonly) NSDictionary *attributes; @property (readonly) NSArray *childNodes; diff --git a/pxSVG/pxXMLNode.m b/pxSVG/pxXMLNode.m index 2749a1b..9b62ed7 100644 --- a/pxSVG/pxXMLNode.m +++ b/pxSVG/pxXMLNode.m @@ -16,47 +16,70 @@ @interface pxXMLNode () @implementation pxXMLNode -+ (NSArray *)parseTree:(NSScanner *)scanner ++ (NSArray *)parseTree:(NSData *)data { - NSMutableArray *nodes = [NSMutableArray new]; - NSString *tag; - pxXMLNode *node; - while (!scanner.isAtEnd) { - [scanner scanUpToString:@"<" intoString:nil]; - [scanner scanUpToString:@">" intoString:&tag]; - tag = [tag stringByAppendingString:@">"]; [scanner scanString:@">" intoString:nil]; - if ([tag hasPrefix:@"')) idx++; + tagRange.length = idx-tagRange.location; + idx++; + if (tagRange.length < 2) break; + if (bytes[tagRange.location+1] == '/') { + if (nodeStack.count == 0) break; + nodes = nodeStack.lastObject; + [nodeStack removeLastObject]; + continue; + } + if (bytes[tagRange.location+1] == '?') continue; + if (bytes[tagRange.location+1] == '!') continue; + { + tidx = 1; + attrRange.location = 1; + [attrs removeAllObjects]; + while ((tidx < tagRange.length) && ![seps characterIsMember:bytes[tagRange.location+tidx]]) tidx++; + attrRange.length = tidx-attrRange.location; + tagName = [[NSString alloc] initWithBytes:&bytes[tagRange.location+attrRange.location] length:attrRange.length encoding:NSUTF8StringEncoding]; + while ((tidx < tagRange.length) && [seps characterIsMember:bytes[tagRange.location+tidx]]) tidx++; + while (tidx < tagRange.length) { + attrRange.location = tidx; + while ((tidx < tagRange.length) && (bytes[tagRange.location+tidx] != '=') && (bytes[tagRange.location+tidx] != '/')) tidx++; + attrRange.length = tidx-attrRange.location; + if (attrRange.length == 0) break; + attrName = [[NSString alloc] initWithBytes:&bytes[tagRange.location+attrRange.location] length:attrRange.length encoding:NSUTF8StringEncoding]; + if (tagRange.length-idx < 2) break; + if ((bytes[tagRange.location+tidx] != '=') || (bytes[tagRange.location+tidx+1] != '"')) break; + tidx += 2; + attrRange.location = tidx; + while ((tidx < tagRange.length) && (bytes[tagRange.location+tidx] != '"')) tidx++; + attrRange.length = tidx-attrRange.location; + attrValue = [[NSString alloc] initWithBytes:&bytes[tagRange.location+attrRange.location] length:attrRange.length encoding:NSUTF8StringEncoding]; + tidx++; + while ((tidx < tagRange.length) && [seps characterIsMember:bytes[tagRange.location+tidx]]) tidx++; + [attrs setObject:attrValue?:@"" forKey:attrName]; + } + BOOL selfClose = bytes[tagRange.location+tagRange.length-1] == '/'; + node = [self new]; + node.tagName = tagName; + node.attributes = [NSDictionary dictionaryWithDictionary:attrs]; + [nodes addObject:node]; + if (selfClose) node.childNodes = @[]; + else { + [nodeStack addObject:nodes]; + node.childNodes = nodes = [[NSMutableArray alloc] initWithCapacity:100]; + } + } } - if ([tagName hasSuffix:@">"]) tagName = [tagName substringToIndex:tagName.length-1]; - BOOL selfClose = [[attrName stringByTrimmingCharactersInSet:seps] hasPrefix:@"/"]; - pxXMLNode *node = [self new]; - node.tagName = tagName; - node.attributes = attrs; - node.childNodes = selfClose?@[]:[self parseTree:childScanner]; - return node; + return (nodeStack.count>0)?nodeStack.firstObject:[NSArray arrayWithArray:nodes]; } - (NSString *)description