diff --git a/Frameworks/RSParser/Feeds/FeedParser.swift b/Frameworks/RSParser/Feeds/FeedParser.swift index d4b4bbe85..083478074 100644 --- a/Frameworks/RSParser/Feeds/FeedParser.swift +++ b/Frameworks/RSParser/Feeds/FeedParser.swift @@ -8,7 +8,7 @@ import Foundation -// FeedParser knows about the various syndication feed types. +// FeedParser handles the various syndication feed types. // It might be a good idea to do a plugin-style architecture here instead — // but feed formats don’t appear all that often, so it’s probably not necessary. @@ -21,6 +21,8 @@ public struct FeedParser { // Can call with partial data — while still downloading, for instance. // If there’s not enough data, return .unknown. Ask again when there’s more data. // If it’s definitely not a feed, return .notAFeed. + // + // This should be fast enough to call on the main thread. if parserData.data.count < minNumberOfBytesRequired { return .unknown @@ -50,6 +52,13 @@ public struct FeedParser { public static func parseFeed(_ parserData: ParserData) throws -> ParsedFeed? { + // All the concrete parsers return a ParsedFeed struct. + // Related: ParsedItem, ParsedAuthor, ParsedHub, ParsedAttachment. + // + // This is probably fast enough to call on the main thread — + // but it’s probably a good idea to use a background queue if + // you might be doing a lot of parsing. (Such as in a feed reader.) + do { let type = feedType(parserData) @@ -65,7 +74,7 @@ public struct FeedParser { return RSSParser.parse(parserData) case .atom: - return AtomParser.parser(parserData) + return AtomParser.parse(parserData) case .unknown, .notAFeed: return nil diff --git a/Frameworks/RSParser/Feeds/XML/AtomParser.swift b/Frameworks/RSParser/Feeds/XML/AtomParser.swift new file mode 100644 index 000000000..151349af7 --- /dev/null +++ b/Frameworks/RSParser/Feeds/XML/AtomParser.swift @@ -0,0 +1,28 @@ +// +// AtomParser.swift +// RSParser +// +// Created by Brent Simmons on 6/25/17. +// Copyright © 2017 Ranchero Software, LLC. All rights reserved. +// + +import Foundation + +// RSSParser wraps the Objective-C RSAtomParser. +// +// The Objective-C parser creates RSParsedFeed, RSParsedArticle, etc. +// This wrapper then creates ParsedFeed, ParsedItem, etc. so that it creates +// the same things that JSONFeedParser and RSSInJSONParser create. +// +// In general, you should see FeedParser.swift for all your feed-parsing needs. + +public struct AtomParser { + + public static func parse(_ parserData: ParserData) -> ParsedFeed? { + + if let rsParsedFeed = RSAtomParser.parseFeed(with: parserData) { + return RSParsedFeedTransformer.parsedFeed(rsParsedFeed) + } + return nil + } +} diff --git a/Frameworks/RSParser/Feeds/XML/RSAtomParser.h b/Frameworks/RSParser/Feeds/XML/RSAtomParser.h index 854969241..27b5d80e4 100755 --- a/Frameworks/RSParser/Feeds/XML/RSAtomParser.h +++ b/Frameworks/RSParser/Feeds/XML/RSAtomParser.h @@ -6,8 +6,13 @@ // Copyright (c) 2015 Ranchero Software LLC. All rights reserved. // -#import "FeedParser.h" +@import Foundation; -@interface RSAtomParser : NSObject +@class ParserData; +@class RSParsedFeed; + +@interface RSAtomParser : NSObject + ++ (RSParsedFeed *)parseFeedWithData:(ParserData *)parserData; @end diff --git a/Frameworks/RSParser/Feeds/XML/RSAtomParser.m b/Frameworks/RSParser/Feeds/XML/RSAtomParser.m index 6ba48c63d..6bd657184 100755 --- a/Frameworks/RSParser/Feeds/XML/RSAtomParser.m +++ b/Frameworks/RSParser/Feeds/XML/RSAtomParser.m @@ -9,12 +9,11 @@ #import #import "RSAtomParser.h" #import "RSSAXParser.h" -#import "FeedParser.h" #import "RSParsedFeed.h" #import "RSParsedArticle.h" -#import "RSXMLData.h" -#import "NSString+RSXML.h" +#import "NSString+RSParser.h" #import "RSDateParser.h" +#import @interface RSAtomParser () @@ -44,57 +43,24 @@ #pragma mark - Class Methods -+ (BOOL)canParseFeed:(RSXMLData *)xmlData { ++ (RSParsedFeed *)parseFeedWithData:(ParserData *)parserData { - // Checking for ' entryRange.location) { - return NO; // Wrong order. - } - } - - return YES; + RSAtomParser *parser = [[[self class] alloc] initWithParserData:parserData]; + return [parser parseFeed]; } #pragma mark - Init -- (instancetype)initWithXMLData:(RSXMLData *)xmlData { +- (instancetype)initWithParserData:(ParserData *)parserData { self = [super init]; if (!self) { return nil; } - _feedData = xmlData.data; - _urlString = xmlData.urlString; + _feedData = parserData.data; + _urlString = parserData.url; _parser = [[RSSAXParser alloc] initWithDelegate:self]; _attributesStack = [NSMutableArray new]; _articles = [NSMutableArray new]; @@ -105,7 +71,7 @@ #pragma mark - API -- (RSParsedFeed *)parseFeed:(NSError **)error { +- (RSParsedFeed *)parseFeed { [self parse]; @@ -315,7 +281,7 @@ static const NSInteger kSelfLength = 5; - (NSString *)currentStringWithHTMLEntitiesDecoded { - return [self.parser.currentStringWithTrimmedWhitespace rs_stringByDecodingHTMLEntities]; + return [self.parser.currentStringWithTrimmedWhitespace rsparser_stringByDecodingHTMLEntities]; } diff --git a/Frameworks/RSParser/Feeds/XML/RSFeedParser.h b/Frameworks/RSParser/Feeds/XML/RSFeedParser.h deleted file mode 100755 index 1f849f266..000000000 --- a/Frameworks/RSParser/Feeds/XML/RSFeedParser.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// RSFeedParser.h -// RSParser -// -// Created by Brent Simmons on 1/4/15. -// Copyright (c) 2015 Ranchero Software LLC. All rights reserved. -// - -#import "FeedParser.h" - -// If you have a feed and don’t know or care what it is (RSS or Atom), -// then call RSParseFeed or RSParseFeedSync. - -@class RSXMLData; -@class RSParsedFeed; - -NS_ASSUME_NONNULL_BEGIN - -BOOL RSCanParseFeed(RSXMLData *xmlData); - - -typedef void (^RSParsedFeedBlock)(RSParsedFeed * _Nullable parsedFeed, NSError * _Nullable error); - -// callback is called on main queue. -void RSParseFeed(RSXMLData *xmlData, RSParsedFeedBlock callback); -RSParsedFeed * _Nullable RSParseFeedSync(RSXMLData *xmlData, NSError * _Nullable * _Nullable error); - -NS_ASSUME_NONNULL_END diff --git a/Frameworks/RSParser/Feeds/XML/RSFeedParser.m b/Frameworks/RSParser/Feeds/XML/RSFeedParser.m deleted file mode 100755 index 84b1de10c..000000000 --- a/Frameworks/RSParser/Feeds/XML/RSFeedParser.m +++ /dev/null @@ -1,216 +0,0 @@ -// -// FeedParser.m -// RSParser -// -// Created by Brent Simmons on 1/4/15. -// Copyright (c) 2015 Ranchero Software LLC. All rights reserved. -// - -#import "RSFeedParser.h" -#import "FeedParser.h" -#import "RSXMLData.h" -#import "RSRSSParser.h" -#import "RSAtomParser.h" - -static NSArray *parserClasses(void) { - - static NSArray *gParserClasses = nil; - - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - - gParserClasses = @[[RSRSSParser class], [RSAtomParser class]]; - }); - - return gParserClasses; -} - -static BOOL feedMayBeParseable(RSXMLData *xmlData) { - - /*Sanity checks.*/ - - if (!xmlData.data) { - return NO; - } - - /*TODO: check size, type, etc.*/ - - return YES; -} - -static BOOL optimisticCanParseRSSData(const char *bytes, NSUInteger numberOfBytes); -static BOOL optimisticCanParseAtomData(const char *bytes, NSUInteger numberOfBytes); -static BOOL optimisticCanParseRDF(const char *bytes, NSUInteger numberOfBytes); -static BOOL dataIsProbablyHTML(const char *bytes, NSUInteger numberOfBytes); -static BOOL dataIsSomeWeirdException(const char *bytes, NSUInteger numberOfBytes); -static BOOL dataHasLeftCaret(const char *bytes, NSUInteger numberOfBytes); - -static const NSUInteger maxNumberOfBytesToSearch = 4096; -static const NSUInteger minNumberOfBytesToSearch = 20; - -static Class parserClassForXMLData(RSXMLData *xmlData) { - - if (!feedMayBeParseable(xmlData)) { - return nil; - } - - // TODO: check for things like images and movies and return nil. - - const char *bytes = xmlData.data.bytes; - NSUInteger numberOfBytes = xmlData.data.length; - - if (numberOfBytes > minNumberOfBytesToSearch) { - - if (numberOfBytes > maxNumberOfBytesToSearch) { - numberOfBytes = maxNumberOfBytesToSearch; - } - - if (!dataHasLeftCaret(bytes, numberOfBytes)) { - return nil; - } - - if (optimisticCanParseRSSData(bytes, numberOfBytes)) { - return [RSRSSParser class]; - } - if (optimisticCanParseAtomData(bytes, numberOfBytes)) { - return [RSAtomParser class]; - } - - if (optimisticCanParseRDF(bytes, numberOfBytes)) { - return nil; //TODO: parse RDF feeds - } - - if (dataIsProbablyHTML(bytes, numberOfBytes)) { - return nil; - } - if (dataIsSomeWeirdException(bytes, numberOfBytes)) { - return nil; - } - } - - for (Class parserClass in parserClasses()) { - if ([parserClass canParseFeed:xmlData]) { - return [[parserClass alloc] initWithXMLData:xmlData]; - } - } - - return nil; -} - -static id parserForXMLData(RSXMLData *xmlData) { - - Class parserClass = parserClassForXMLData(xmlData); - if (!parserClass) { - return nil; - } - return [[parserClass alloc] initWithXMLData:xmlData]; -} - -static BOOL canParseXMLData(RSXMLData *xmlData) { - - return parserClassForXMLData(xmlData) != nil; -} - -static BOOL didFindString(const char *string, const char *bytes, NSUInteger numberOfBytes) { - - char *foundString = strnstr(bytes, string, numberOfBytes); - return foundString != NULL; -} - -static BOOL dataHasLeftCaret(const char *bytes, NSUInteger numberOfBytes) { - - return didFindString("<", bytes, numberOfBytes); -} - -static BOOL dataIsProbablyHTML(const char *bytes, NSUInteger numberOfBytes) { - - // Won’t catch every single case, which is fine. - - if (didFindString("' within first n characters should do it. - // TODO: handle RSS 1.0 - - @autoreleasepool { - - NSData *feedData = xmlData.data; - NSString *s = [[NSString alloc] initWithBytesNoCopy:(void *)feedData.bytes length:feedData.length encoding:NSUTF8StringEncoding freeWhenDone:NO]; - if (!s) { - s = [[NSString alloc] initWithData:feedData encoding:NSUTF8StringEncoding]; - } - if (!s) { - s = [[NSString alloc] initWithData:feedData encoding:NSUnicodeStringEncoding]; - } - if (!s) { - return NO; - } - - static const NSInteger numberOfCharactersToSearch = 4096; - NSRange rangeToSearch = NSMakeRange(0, numberOfCharactersToSearch); - if (s.length < numberOfCharactersToSearch) { - rangeToSearch.length = s.length; - } - - NSRange rssRange = [s rangeOfString:@"" options:NSLiteralSearch range:rangeToSearch]; - if (rssRange.length < 1 || channelRange.length < 1) { - return NO; - } - - if (rssRange.location > channelRange.location) { - return NO; // Wrong order. - } - } - - return YES; + RSRSSParser *parser = [[[self class] alloc] initWithParserData:parserData]; + return [parser parseFeed]; } - #pragma mark - Init -- (instancetype)initWithXMLData:(RSXMLData *)xmlData { +- (instancetype)initWithParserData:(ParserData *)parserData { self = [super init]; if (!self) { return nil; } - _feedData = xmlData.data; - _urlString = xmlData.urlString; + _feedData = parserData.data; + _urlString = parserData.url; _parser = [[RSSAXParser alloc] initWithDelegate:self]; _articles = [NSMutableArray new]; @@ -100,7 +66,7 @@ #pragma mark - API -- (RSParsedFeed *)parseFeed:(NSError **)error { +- (RSParsedFeed *)parseFeed { [self parse]; @@ -292,7 +258,7 @@ static const NSInteger kTrueLength = 5; - (NSString *)currentStringWithHTMLEntitiesDecoded { - return [self.parser.currentStringWithTrimmedWhitespace rs_stringByDecodingHTMLEntities]; + return [self.parser.currentStringWithTrimmedWhitespace rsparser_stringByDecodingHTMLEntities]; } - (void)addArticleElement:(const xmlChar *)localName prefix:(const xmlChar *)prefix { diff --git a/Frameworks/RSParser/Feeds/XML/RSSParser.swift b/Frameworks/RSParser/Feeds/XML/RSSParser.swift new file mode 100644 index 000000000..885790e16 --- /dev/null +++ b/Frameworks/RSParser/Feeds/XML/RSSParser.swift @@ -0,0 +1,28 @@ +// +// RSSParser.swift +// RSParser +// +// Created by Brent Simmons on 6/25/17. +// Copyright © 2017 Ranchero Software, LLC. All rights reserved. +// + +import Foundation + +// RSSParser wraps the Objective-C RSRSSParser. +// +// The Objective-C parser creates RSParsedFeed, RSParsedArticle, etc. +// This wrapper then creates ParsedFeed, ParsedItem, etc. so that it creates +// the same things that JSONFeedParser and RSSInJSONParser create. +// +// In general, you should see FeedParser.swift for all your feed-parsing needs. + +public struct RSSParser { + + public static func parse(_ parserData: ParserData) -> ParsedFeed? { + + if let rsParsedFeed = RSRSSParser.parseFeed(with: parserData) { + return RSParsedFeedTransformer.parsedFeed(rsParsedFeed) + } + return nil + } +} diff --git a/Frameworks/RSParser/HTML/RSHTMLLinkParser.h b/Frameworks/RSParser/HTML/RSHTMLLinkParser.h index b1281c555..eae931b16 100755 --- a/Frameworks/RSParser/HTML/RSHTMLLinkParser.h +++ b/Frameworks/RSParser/HTML/RSHTMLLinkParser.h @@ -10,12 +10,12 @@ /*Returns all some_text as RSHTMLLink object array.*/ -@class RSXMLData; +@class ParserData; @class RSHTMLLink; @interface RSHTMLLinkParser : NSObject -+ (NSArray *)htmlLinksWithData:(RSXMLData *)xmlData; ++ (NSArray *)htmlLinksWithParserData:(ParserData *)parserData; @end diff --git a/Frameworks/RSParser/HTML/RSHTMLLinkParser.m b/Frameworks/RSParser/HTML/RSHTMLLinkParser.m index 5dd591411..1000356f4 100755 --- a/Frameworks/RSParser/HTML/RSHTMLLinkParser.m +++ b/Frameworks/RSParser/HTML/RSHTMLLinkParser.m @@ -10,14 +10,14 @@ #import "RSHTMLLinkParser.h" #import "RSSAXHTMLParser.h" #import "RSSAXParser.h" -#import "RSXMLData.h" -#import "RSXMLInternal.h" +#import "RSParserInternal.h" +#import @interface RSHTMLLinkParser() @property (nonatomic, readonly) NSMutableArray *links; -@property (nonatomic, readonly) RSXMLData *xmlData; +@property (nonatomic, readonly) ParserData *parserData; @property (nonatomic, readonly) NSMutableArray *dictionaries; @property (nonatomic, readonly) NSURL *baseURL; @@ -38,19 +38,19 @@ #pragma mark - Class Methods -+ (NSArray *)htmlLinksWithData:(RSXMLData *)xmlData { ++ (NSArray *)HTMLMetadataWithParserData:(ParserData *)parserData { - RSHTMLLinkParser *parser = [[self alloc] initWithXMLData:xmlData]; + RSHTMLLinkParser *parser = [[self alloc] initWithParserData:parserData]; return parser.links; } #pragma mark - Init -- (instancetype)initWithXMLData:(RSXMLData *)xmlData { +- (instancetype)initWithParserData:(ParserData *)parserData { - NSParameterAssert(xmlData.data); - NSParameterAssert(xmlData.urlString); + NSParameterAssert(parserData.data); + NSParameterAssert(parserData.url); self = [super init]; if (!self) { @@ -58,9 +58,9 @@ } _links = [NSMutableArray new]; - _xmlData = xmlData; + _parserData = parserData; _dictionaries = [NSMutableArray new]; - _baseURL = [NSURL URLWithString:xmlData.urlString]; + _baseURL = [NSURL URLWithString:parserData.url]; [self parse]; @@ -73,7 +73,7 @@ - (void)parse { RSSAXHTMLParser *parser = [[RSSAXHTMLParser alloc] initWithDelegate:self]; - [parser parseData:self.xmlData.data]; + [parser parseData:self.parserData.data]; [parser finishParsing]; } @@ -127,7 +127,7 @@ static const NSInteger kAnchorLength = 2; [self.links addObject:link]; NSDictionary *d = [SAXParser attributesDictionary:attributes]; - if (!RSParser_IsEmpty(d)) { + if (!RSParserObjectIsEmpty(d)) { [self handleLinkAttributes:d]; } diff --git a/Frameworks/RSParser/HTML/RSHTMLMetadata.m b/Frameworks/RSParser/HTML/RSHTMLMetadata.m index 9f5a99c19..87662d8b4 100755 --- a/Frameworks/RSParser/HTML/RSHTMLMetadata.m +++ b/Frameworks/RSParser/HTML/RSHTMLMetadata.m @@ -7,7 +7,7 @@ // #import "RSHTMLMetadata.h" -#import "RSXMLInternal.h" +#import "RSParserInternal.h" static NSString *urlStringFromDictionary(NSDictionary *d); static NSString *absoluteURLStringWithRelativeURLString(NSString *relativeURLString, NSString *baseURLString); diff --git a/Frameworks/RSParser/HTML/RSHTMLMetadataParser.h b/Frameworks/RSParser/HTML/RSHTMLMetadataParser.h index 32616e2f9..f9361905c 100755 --- a/Frameworks/RSParser/HTML/RSHTMLMetadataParser.h +++ b/Frameworks/RSParser/HTML/RSHTMLMetadataParser.h @@ -10,17 +10,13 @@ @class RSHTMLMetadata; -@class RSXMLData; +@class ParserData; NS_ASSUME_NONNULL_BEGIN @interface RSHTMLMetadataParser : NSObject -+ (RSHTMLMetadata *)HTMLMetadataWithXMLData:(RSXMLData *)xmlData; - -- (instancetype)initWithXMLData:(RSXMLData *)xmlData; - -@property (nonatomic, readonly) RSHTMLMetadata *metadata; ++ (RSHTMLMetadata *)HTMLMetadataWithParserData:(ParserData *)parserData; @end diff --git a/Frameworks/RSParser/HTML/RSHTMLMetadataParser.m b/Frameworks/RSParser/HTML/RSHTMLMetadataParser.m index 4fa3ca3d2..ec15f8714 100755 --- a/Frameworks/RSParser/HTML/RSHTMLMetadataParser.m +++ b/Frameworks/RSParser/HTML/RSHTMLMetadataParser.m @@ -1,6 +1,6 @@ // // RSHTMLMetadataParser.m -// RSXML +// RSParser // // Created by Brent Simmons on 3/6/16. // Copyright © 2016 Ranchero Software, LLC. All rights reserved. @@ -8,16 +8,15 @@ #import #import "RSHTMLMetadataParser.h" -#import "RSXMLData.h" #import "RSHTMLMetadata.h" #import "RSSAXHTMLParser.h" #import "RSSAXParser.h" -#import "RSXMLInternal.h" - +#import "RSParserInternal.h" +#import @interface RSHTMLMetadataParser () -@property (nonatomic, readonly) RSXMLData *xmlData; +@property (nonatomic, readonly) ParserData *parserData; @property (nonatomic, readwrite) RSHTMLMetadata *metadata; @property (nonatomic) NSMutableArray *dictionaries; @property (nonatomic) BOOL didFinishParsing; @@ -30,26 +29,26 @@ #pragma mark - Class Methods -+ (RSHTMLMetadata *)HTMLMetadataWithXMLData:(RSXMLData *)xmlData { ++ (RSHTMLMetadata *)HTMLMetadataWithParserData:(ParserData *)parserData { - RSHTMLMetadataParser *parser = [[self alloc] initWithXMLData:xmlData]; + RSHTMLMetadataParser *parser = [[self alloc] initWithParserData:parserData]; return parser.metadata; } #pragma mark - Init -- (instancetype)initWithXMLData:(RSXMLData *)xmlData { +- (instancetype)initWithParserData:(ParserData *)parserData { - NSParameterAssert(xmlData.data); - NSParameterAssert(xmlData.urlString); + NSParameterAssert(parserData.data); + NSParameterAssert(parserData.url); self = [super init]; if (!self) { return nil; } - _xmlData = xmlData; + _parserData = parserData; _dictionaries = [NSMutableArray new]; [self parse]; @@ -63,10 +62,10 @@ - (void)parse { RSSAXHTMLParser *parser = [[RSSAXHTMLParser alloc] initWithDelegate:self]; - [parser parseData:self.xmlData.data]; + [parser parseData:self.parserData.data]; [parser finishParsing]; - self.metadata = [[RSHTMLMetadata alloc] initWithURLString:self.xmlData.urlString dictionaries:[self.dictionaries copy]]; + self.metadata = [[RSHTMLMetadata alloc] initWithURLString:self.parserData.url dictionaries:[self.dictionaries copy]]; } @@ -121,7 +120,7 @@ static const NSInteger kLinkLength = 5; } NSDictionary *d = [SAXParser attributesDictionary:attributes]; - if (!RSParser_IsEmpty(d)) { + if (!RSParserObjectIsEmpty(d)) { [self handleLinkAttributes:d]; } } diff --git a/Frameworks/RSParser/HTML/RSSAXHTMLParser.m b/Frameworks/RSParser/HTML/RSSAXHTMLParser.m index f585173e0..c059349aa 100755 --- a/Frameworks/RSParser/HTML/RSSAXHTMLParser.m +++ b/Frameworks/RSParser/HTML/RSSAXHTMLParser.m @@ -11,7 +11,7 @@ #import #import #import -#import "RSXMLInternal.h" +#import "RSParserInternal.h" @interface RSSAXHTMLParser () diff --git a/Frameworks/RSParser/OPML/RSOPMLAttributes.h b/Frameworks/RSParser/OPML/RSOPMLAttributes.h index 0ffd20242..688132fe5 100755 --- a/Frameworks/RSParser/OPML/RSOPMLAttributes.h +++ b/Frameworks/RSParser/OPML/RSOPMLAttributes.h @@ -1,6 +1,6 @@ // // RSOPMLAttributes.h -// RSXML +// RSParser // // Created by Brent Simmons on 2/28/16. // Copyright © 2016 Ranchero Software, LLC. All rights reserved. diff --git a/Frameworks/RSParser/OPML/RSOPMLAttributes.m b/Frameworks/RSParser/OPML/RSOPMLAttributes.m index 3bec885f2..89b591565 100755 --- a/Frameworks/RSParser/OPML/RSOPMLAttributes.m +++ b/Frameworks/RSParser/OPML/RSOPMLAttributes.m @@ -1,13 +1,13 @@ // // RSOPMLAttributes.m -// RSXML +// RSParser // // Created by Brent Simmons on 2/28/16. // Copyright © 2016 Ranchero Software, LLC. All rights reserved. // #import "RSOPMLAttributes.h" -#import "RSXMLInternal.h" +#import "RSParserInternal.h" NSString *OPMLTextKey = @"text"; diff --git a/Frameworks/RSParser/OPML/RSOPMLDocument.h b/Frameworks/RSParser/OPML/RSOPMLDocument.h index bd33f1666..8b08f5e3b 100755 --- a/Frameworks/RSParser/OPML/RSOPMLDocument.h +++ b/Frameworks/RSParser/OPML/RSOPMLDocument.h @@ -1,6 +1,6 @@ // // RSOPMLDocument.h -// RSXML +// RSParser // // Created by Brent Simmons on 2/28/16. // Copyright © 2016 Ranchero Software, LLC. All rights reserved. diff --git a/Frameworks/RSParser/OPML/RSOPMLDocument.m b/Frameworks/RSParser/OPML/RSOPMLDocument.m index ec22cd74d..0674bb862 100755 --- a/Frameworks/RSParser/OPML/RSOPMLDocument.m +++ b/Frameworks/RSParser/OPML/RSOPMLDocument.m @@ -1,6 +1,6 @@ // // RSOPMLDocument.m -// RSXML +// RSParser // // Created by Brent Simmons on 2/28/16. // Copyright © 2016 Ranchero Software, LLC. All rights reserved. diff --git a/Frameworks/RSParser/OPML/RSOPMLError.h b/Frameworks/RSParser/OPML/RSOPMLError.h new file mode 100755 index 000000000..276c62ed7 --- /dev/null +++ b/Frameworks/RSParser/OPML/RSOPMLError.h @@ -0,0 +1,19 @@ +// +// RSOPMLError.h +// RSParser +// +// Created by Brent Simmons on 2/28/16. +// Copyright © 2016 Ranchero Software, LLC. All rights reserved. +// + +@import Foundation; + +extern NSString *RSOPMLErrorDomain; + + +typedef NS_ENUM(NSInteger, RSOPMLErrorCode) { + RSOPMLErrorCodeDataIsWrongFormat = 1024 +}; + + +NSError *RSOPMLWrongFormatError(NSString *fileName); diff --git a/Frameworks/RSParser/OPML/RSOPMLError.m b/Frameworks/RSParser/OPML/RSOPMLError.m new file mode 100755 index 000000000..7aa3c5e9d --- /dev/null +++ b/Frameworks/RSParser/OPML/RSOPMLError.m @@ -0,0 +1,22 @@ +// +// RSOPMLError.m +// RSParser +// +// Created by Brent Simmons on 2/28/16. +// Copyright © 2016 Ranchero Software, LLC. All rights reserved. +// + +#import "RSOPMLError.h" + +NSString *RSOPMLErrorDomain = @"com.ranchero.OPML"; + +NSError *RSOPMLWrongFormatError(NSString *fileName) { + + NSString *localizedDescriptionFormatString = NSLocalizedString(@"The file ‘%@’ can’t be parsed because it’s not an OPML file.", @"OPML wrong format"); + NSString *localizedDescription = [NSString stringWithFormat:localizedDescriptionFormatString, fileName]; + + NSString *localizedFailureString = NSLocalizedString(@"The file is not an OPML file.", @"OPML wrong format"); + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: localizedDescription, NSLocalizedFailureReasonErrorKey: localizedFailureString}; + + return [[NSError alloc] initWithDomain:RSOPMLErrorDomain code:RSOPMLErrorCodeDataIsWrongFormat userInfo:userInfo]; +} diff --git a/Frameworks/RSParser/OPML/RSOPMLFeedSpecifier.h b/Frameworks/RSParser/OPML/RSOPMLFeedSpecifier.h index 785c4cab3..67e48572c 100755 --- a/Frameworks/RSParser/OPML/RSOPMLFeedSpecifier.h +++ b/Frameworks/RSParser/OPML/RSOPMLFeedSpecifier.h @@ -1,6 +1,6 @@ // // RSOPMLFeedSpecifier.h -// RSXML +// RSParser // // Created by Brent Simmons on 2/28/16. // Copyright © 2016 Ranchero Software, LLC. All rights reserved. diff --git a/Frameworks/RSParser/OPML/RSOPMLFeedSpecifier.m b/Frameworks/RSParser/OPML/RSOPMLFeedSpecifier.m index 784e8306f..a48d7526c 100755 --- a/Frameworks/RSParser/OPML/RSOPMLFeedSpecifier.m +++ b/Frameworks/RSParser/OPML/RSOPMLFeedSpecifier.m @@ -1,13 +1,13 @@ // // RSOPMLFeedSpecifier.m -// RSXML +// RSParser // // Created by Brent Simmons on 2/28/16. // Copyright © 2016 Ranchero Software, LLC. All rights reserved. // #import "RSOPMLFeedSpecifier.h" -#import "RSXMLInternal.h" +#import "RSParserInternal.h" @implementation RSOPMLFeedSpecifier diff --git a/Frameworks/RSParser/OPML/RSOPMLItem.h b/Frameworks/RSParser/OPML/RSOPMLItem.h index 853cf9bc4..e77ff008c 100755 --- a/Frameworks/RSParser/OPML/RSOPMLItem.h +++ b/Frameworks/RSParser/OPML/RSOPMLItem.h @@ -1,6 +1,6 @@ // // RSOPMLItem.h -// RSXML +// RSParser // // Created by Brent Simmons on 2/28/16. // Copyright © 2016 Ranchero Software, LLC. All rights reserved. diff --git a/Frameworks/RSParser/OPML/RSOPMLItem.m b/Frameworks/RSParser/OPML/RSOPMLItem.m index 39c7091da..58ce34338 100755 --- a/Frameworks/RSParser/OPML/RSOPMLItem.m +++ b/Frameworks/RSParser/OPML/RSOPMLItem.m @@ -1,6 +1,6 @@ // // RSOPMLItem.m -// RSXML +// RSParser // // Created by Brent Simmons on 2/28/16. // Copyright © 2016 Ranchero Software, LLC. All rights reserved. @@ -9,7 +9,7 @@ #import "RSOPMLItem.h" #import "RSOPMLAttributes.h" #import "RSOPMLFeedSpecifier.h" -#import "RSXMLInternal.h" +#import "RSParserInternal.h" @interface RSOPMLItem () diff --git a/Frameworks/RSParser/OPML/RSOPMLParser.h b/Frameworks/RSParser/OPML/RSOPMLParser.h index 825b9ac93..9f703be71 100755 --- a/Frameworks/RSParser/OPML/RSOPMLParser.h +++ b/Frameworks/RSParser/OPML/RSOPMLParser.h @@ -1,6 +1,6 @@ // // RSOPMLParser.h -// RSXML +// RSParser // // Created by Brent Simmons on 7/12/15. // Copyright © 2015 Ranchero Software, LLC. All rights reserved. @@ -9,21 +9,12 @@ @import Foundation; -@class RSXMLData; +@class ParserData; @class RSOPMLDocument; - -typedef void (^RSParsedOPMLBlock)(RSOPMLDocument *OPMLDocument, NSError *error); - -void RSParseOPML(RSXMLData *xmlData, RSParsedOPMLBlock callback); //async; calls back on main thread. - - @interface RSOPMLParser: NSObject -- (instancetype)initWithXMLData:(RSXMLData *)xmlData; - -@property (nonatomic, readonly) RSOPMLDocument *OPMLDocument; -@property (nonatomic, readonly) NSError *error; ++ (RSOPMLDocument *)parseOPMLWithParserData:(ParserData *)parserData error:(NSError **)error; @end diff --git a/Frameworks/RSParser/OPML/RSOPMLParser.m b/Frameworks/RSParser/OPML/RSOPMLParser.m index 842f30a46..da10f4fb6 100755 --- a/Frameworks/RSParser/OPML/RSOPMLParser.m +++ b/Frameworks/RSParser/OPML/RSOPMLParser.m @@ -1,6 +1,6 @@ // // RSOPMLParser.m -// RSXML +// RSParser // // Created by Brent Simmons on 7/12/15. // Copyright © 2015 Ranchero Software, LLC. All rights reserved. @@ -8,24 +8,24 @@ #import "RSOPMLParser.h" #import -#import "RSXMLData.h" #import "RSSAXParser.h" #import "RSOPMLItem.h" #import "RSOPMLDocument.h" #import "RSOPMLAttributes.h" -#import "RSXMLError.h" +#import +#import "RSOPMLError.h" -void RSParseOPML(RSXMLData *xmlData, RSParsedOPMLBlock callback) { +void RSParseOPML(ParserData *parserData, RSParsedOPMLBlock callback) { - NSCParameterAssert(xmlData); + NSCParameterAssert(parserData); NSCParameterAssert(callback); dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{ @autoreleasepool { - RSOPMLParser *parser = [[RSOPMLParser alloc] initWithXMLData:xmlData]; + RSOPMLParser *parser = [[RSOPMLParser alloc] initWithParserData:parserData]; RSOPMLDocument *document = parser.OPMLDocument; NSError *error = parser.error; @@ -50,17 +50,30 @@ void RSParseOPML(RSXMLData *xmlData, RSParsedOPMLBlock callback) { @implementation RSOPMLParser +#pragma mark - Class Methods + ++ (RSOPMLDocument *)parseOPMLWithParserData:(ParserData *)parserData error:(NSError **)error { + + RSOPMLParser *parser = [[RSOPMLParser alloc] initWithParserData:parserData]; + + RSOPMLDocument *document = parser.OPMLDocument; + if (parser.error) { + *error = parser.error; + return nil; + } + return document; +} #pragma mark - Init -- (instancetype)initWithXMLData:(RSXMLData *)XMLData { +- (instancetype)initWithParserData:(ParserData *)parserData { self = [super init]; if (!self) { return nil; } - [self parse:XMLData]; + [self parse:parserData]; return self; } @@ -68,22 +81,22 @@ void RSParseOPML(RSXMLData *xmlData, RSParsedOPMLBlock callback) { #pragma mark - Private -- (void)parse:(RSXMLData *)XMLData { +- (void)parse:(ParserData *)parserData { @autoreleasepool { - if (![self canParseData:XMLData.data]) { + if (![self canParseData:parserData.data]) { NSString *filename = nil; - NSURL *url = [NSURL URLWithString:XMLData.urlString]; + NSURL *url = [NSURL URLWithString:parserData.url]; if (url && url.isFileURL) { filename = url.path.lastPathComponent; } - if ([XMLData.urlString hasPrefix:@"http"]) { - filename = XMLData.urlString; + if ([parserData.url hasPrefix:@"http"]) { + filename = parserData.url; } if (!filename) { - filename = XMLData.urlString; + filename = parserData.url; } self.error = RSOPMLWrongFormatError(filename); return; @@ -95,7 +108,7 @@ void RSParseOPML(RSXMLData *xmlData, RSParsedOPMLBlock callback) { self.OPMLDocument = [RSOPMLDocument new]; [self pushItem:self.OPMLDocument]; - [parser parseData:XMLData.data]; + [parser parseData:parserData.data]; [parser finishParsing]; } } diff --git a/Frameworks/RSParser/ParserData.swift b/Frameworks/RSParser/ParserData.swift index 20e24dc0d..5cc1b1ae2 100644 --- a/Frameworks/RSParser/ParserData.swift +++ b/Frameworks/RSParser/ParserData.swift @@ -8,14 +8,15 @@ import Foundation -public final class ParserData { +@objc public final class ParserData: NSObject { - let url: String - let data: Data + public let url: String + public let data: Data public init(url: String, data: Data) { self.url = url self.data = data + super.init() } } diff --git a/Frameworks/RSParser/README.md b/Frameworks/RSParser/README.md new file mode 100644 index 000000000..7a530aa12 --- /dev/null +++ b/Frameworks/RSParser/README.md @@ -0,0 +1,67 @@ +# RSParser + +(Note: I haven’t written tests yet. It’s possible that none of this works.) + +(Also note: this framework is intended to supersede my [RSXML](https://github.com/brentsimmons/RSXML) framework. Use this one instead. Well, once it’s working, that is.) + +## What’s inside + +This framework includes parsers for: + +* [RSS](http://cyber.harvard.edu/rss/rss.html), [Atom](https://tools.ietf.org/html/rfc4287), [JSON Feed](https://jsonfeed.org/), and [RSS-in-JSON](https://github.com/scripting/Scripting-News/blob/master/rss-in-json/README.md) +* [OPML](http://dev.opml.org/) +* Internet dates +* HTML metadata and links +* HTML entities + +It also includes Objective-C wrappers for libXML2’s XML SAX and HTML SAX parsers. You can write your own parsers on top of these. + +This framework builds for macOS. It *could* be made to build for iOS also, but I haven’t gotten around to it yet. + +## How to parse feeds + +To get the type of a feed, even with partial data, call `FeedParser.feedType(parserData)`, which will return a `FeedType`. + +To parse a feed, call `FeedParser.parseFeed(parserData)`, which will return a `ParsedFeed`. Also see related structs: `ParsedAuthor`, `ParsedItem`, `ParsedAttachment`, and `ParsedHub`. + +You do *not* need to know the type of feed when calling `FeedParser.parseFeed` — it will figure it out and use the correct concrete parser. + +However, if you do want to use a concrete parser directly, see `RSSInJSONParser`, `JSONFeedParser`, `RSSParser`, and `AtomParser`. + +(Note: if you want to write a feed reader app, please do! You have my blessing and encouragement. Let me know when it’s shipping so I can check it out.) + +## How to parse OPML + +Call `+[RSOPMLParser parseOPMLWithParserData:error:]`, which returns an `RSOPMLDocument`. See related objects: `RSOPMLItem`, `RSOPMLAttributes`, `RSOPMLFeedSpecifier`, and `RSOPMLError`. + +## How to parse dates + +Call `RSDateWithString` or `RSDateWithBytes` (see `RSDateParser`). These handle the common internet date formats. You don’t need to know which format. + +## How to parse HTML + +To get an array of ` +// To parse RSS, Atom, JSON Feed, and RSS-in-JSON the easy way, see FeedParser.swift. + +// Dates + #import + +// OPML + +#import +#import +#import +#import +#import +#import + +// For writing your own XML parser. + +#import + +// You should use FeedParser (Swift) instead of these two specific parsers +// and the objects they create. +// But they’re available if you want them. + +#import +#import +#import +#import + +// HTML + +#import +#import +#import +#import // For writing your own HTML parser. + +// Utilities + +#import #import - -//#import -//#import -// -//#import -//#import -//#import -//#import -//#import -//#import -// -//#import -//#import -//#import -//#import -//#import -// -//#import -// -//#import -//#import -// -//// HTML -// -//#import -// -//#import -//#import -//#import - diff --git a/Frameworks/RSParser/RSParser.xcodeproj/project.pbxproj b/Frameworks/RSParser/RSParser.xcodeproj/project.pbxproj index e185a4351..cf6e463e7 100644 --- a/Frameworks/RSParser/RSParser.xcodeproj/project.pbxproj +++ b/Frameworks/RSParser/RSParser.xcodeproj/project.pbxproj @@ -7,26 +7,32 @@ objects = { /* Begin PBXBuildFile section */ + 84285AA81F005D53002E8708 /* RSSParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84285AA71F005D53002E8708 /* RSSParser.swift */; }; + 84285AAA1F006456002E8708 /* RSParsedFeedTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84285AA91F006456002E8708 /* RSParsedFeedTransformer.swift */; }; + 84285AAC1F006754002E8708 /* AtomParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84285AAB1F006754002E8708 /* AtomParser.swift */; }; + 84285AAF1F006BC0002E8708 /* libxml2.2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 84285AAE1F006BC0002E8708 /* libxml2.2.tbd */; }; + 84285AB21F00702E002E8708 /* RSOPMLError.h in Headers */ = {isa = PBXBuildFile; fileRef = 84285AB01F00702E002E8708 /* RSOPMLError.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 84285AB31F00702E002E8708 /* RSOPMLError.m in Sources */ = {isa = PBXBuildFile; fileRef = 84285AB11F00702E002E8708 /* RSOPMLError.m */; }; 84469CE21EFA2F3E004A6B28 /* ParserData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84469CE11EFA2F3E004A6B28 /* ParserData.swift */; }; - 84469CEF1EFA3000004A6B28 /* RSOPMLAttributes.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469CE51EFA3000004A6B28 /* RSOPMLAttributes.h */; }; + 84469CEF1EFA3000004A6B28 /* RSOPMLAttributes.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469CE51EFA3000004A6B28 /* RSOPMLAttributes.h */; settings = {ATTRIBUTES = (Public, ); }; }; 84469CF01EFA3000004A6B28 /* RSOPMLAttributes.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469CE61EFA3000004A6B28 /* RSOPMLAttributes.m */; }; - 84469CF11EFA3000004A6B28 /* RSOPMLDocument.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469CE71EFA3000004A6B28 /* RSOPMLDocument.h */; }; + 84469CF11EFA3000004A6B28 /* RSOPMLDocument.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469CE71EFA3000004A6B28 /* RSOPMLDocument.h */; settings = {ATTRIBUTES = (Public, ); }; }; 84469CF21EFA3000004A6B28 /* RSOPMLDocument.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469CE81EFA3000004A6B28 /* RSOPMLDocument.m */; }; - 84469CF31EFA3000004A6B28 /* RSOPMLFeedSpecifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469CE91EFA3000004A6B28 /* RSOPMLFeedSpecifier.h */; }; + 84469CF31EFA3000004A6B28 /* RSOPMLFeedSpecifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469CE91EFA3000004A6B28 /* RSOPMLFeedSpecifier.h */; settings = {ATTRIBUTES = (Public, ); }; }; 84469CF41EFA3000004A6B28 /* RSOPMLFeedSpecifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469CEA1EFA3000004A6B28 /* RSOPMLFeedSpecifier.m */; }; - 84469CF51EFA3000004A6B28 /* RSOPMLItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469CEB1EFA3000004A6B28 /* RSOPMLItem.h */; }; + 84469CF51EFA3000004A6B28 /* RSOPMLItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469CEB1EFA3000004A6B28 /* RSOPMLItem.h */; settings = {ATTRIBUTES = (Public, ); }; }; 84469CF61EFA3000004A6B28 /* RSOPMLItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469CEC1EFA3000004A6B28 /* RSOPMLItem.m */; }; - 84469CF71EFA3000004A6B28 /* RSOPMLParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469CED1EFA3000004A6B28 /* RSOPMLParser.h */; }; + 84469CF71EFA3000004A6B28 /* RSOPMLParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469CED1EFA3000004A6B28 /* RSOPMLParser.h */; settings = {ATTRIBUTES = (Public, ); }; }; 84469CF81EFA3000004A6B28 /* RSOPMLParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469CEE1EFA3000004A6B28 /* RSOPMLParser.m */; }; - 84469CFC1EFA3069004A6B28 /* RSSAXParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469CFA1EFA3069004A6B28 /* RSSAXParser.h */; }; + 84469CFC1EFA3069004A6B28 /* RSSAXParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469CFA1EFA3069004A6B28 /* RSSAXParser.h */; settings = {ATTRIBUTES = (Public, ); }; }; 84469CFD1EFA3069004A6B28 /* RSSAXParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469CFB1EFA3069004A6B28 /* RSSAXParser.m */; }; - 84469D071EFA307E004A6B28 /* RSHTMLLinkParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469CFF1EFA307E004A6B28 /* RSHTMLLinkParser.h */; }; + 84469D071EFA307E004A6B28 /* RSHTMLLinkParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469CFF1EFA307E004A6B28 /* RSHTMLLinkParser.h */; settings = {ATTRIBUTES = (Public, ); }; }; 84469D081EFA307E004A6B28 /* RSHTMLLinkParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D001EFA307E004A6B28 /* RSHTMLLinkParser.m */; }; - 84469D091EFA307E004A6B28 /* RSHTMLMetadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D011EFA307E004A6B28 /* RSHTMLMetadata.h */; }; + 84469D091EFA307E004A6B28 /* RSHTMLMetadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D011EFA307E004A6B28 /* RSHTMLMetadata.h */; settings = {ATTRIBUTES = (Public, ); }; }; 84469D0A1EFA307E004A6B28 /* RSHTMLMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D021EFA307E004A6B28 /* RSHTMLMetadata.m */; }; - 84469D0B1EFA307E004A6B28 /* RSHTMLMetadataParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D031EFA307E004A6B28 /* RSHTMLMetadataParser.h */; }; + 84469D0B1EFA307E004A6B28 /* RSHTMLMetadataParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D031EFA307E004A6B28 /* RSHTMLMetadataParser.h */; settings = {ATTRIBUTES = (Public, ); }; }; 84469D0C1EFA307E004A6B28 /* RSHTMLMetadataParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D041EFA307E004A6B28 /* RSHTMLMetadataParser.m */; }; - 84469D0D1EFA307E004A6B28 /* RSSAXHTMLParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D051EFA307E004A6B28 /* RSSAXHTMLParser.h */; }; + 84469D0D1EFA307E004A6B28 /* RSSAXHTMLParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D051EFA307E004A6B28 /* RSSAXHTMLParser.h */; settings = {ATTRIBUTES = (Public, ); }; }; 84469D0E1EFA307E004A6B28 /* RSSAXHTMLParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D061EFA307E004A6B28 /* RSSAXHTMLParser.m */; }; 84469D161EFA30A2004A6B28 /* NSString+RSParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D101EFA30A2004A6B28 /* NSString+RSParser.h */; settings = {ATTRIBUTES = (Public, ); }; }; 84469D171EFA30A2004A6B28 /* NSString+RSParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D111EFA30A2004A6B28 /* NSString+RSParser.m */; }; @@ -34,15 +40,13 @@ 84469D191EFA30A2004A6B28 /* RSDateParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D131EFA30A2004A6B28 /* RSDateParser.m */; }; 84469D1A1EFA30A2004A6B28 /* RSParserInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D141EFA30A2004A6B28 /* RSParserInternal.h */; }; 84469D1B1EFA30A2004A6B28 /* RSParserInternal.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D151EFA30A2004A6B28 /* RSParserInternal.m */; }; - 84469D271EFA3134004A6B28 /* RSAtomParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D1D1EFA3134004A6B28 /* RSAtomParser.h */; }; + 84469D271EFA3134004A6B28 /* RSAtomParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D1D1EFA3134004A6B28 /* RSAtomParser.h */; settings = {ATTRIBUTES = (Public, ); }; }; 84469D281EFA3134004A6B28 /* RSAtomParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D1E1EFA3134004A6B28 /* RSAtomParser.m */; }; - 84469D291EFA3134004A6B28 /* RSFeedParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D1F1EFA3134004A6B28 /* RSFeedParser.h */; }; - 84469D2A1EFA3134004A6B28 /* RSFeedParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D201EFA3134004A6B28 /* RSFeedParser.m */; }; - 84469D2B1EFA3134004A6B28 /* RSParsedArticle.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D211EFA3134004A6B28 /* RSParsedArticle.h */; }; + 84469D2B1EFA3134004A6B28 /* RSParsedArticle.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D211EFA3134004A6B28 /* RSParsedArticle.h */; settings = {ATTRIBUTES = (Public, ); }; }; 84469D2C1EFA3134004A6B28 /* RSParsedArticle.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D221EFA3134004A6B28 /* RSParsedArticle.m */; }; - 84469D2D1EFA3134004A6B28 /* RSParsedFeed.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D231EFA3134004A6B28 /* RSParsedFeed.h */; }; + 84469D2D1EFA3134004A6B28 /* RSParsedFeed.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D231EFA3134004A6B28 /* RSParsedFeed.h */; settings = {ATTRIBUTES = (Public, ); }; }; 84469D2E1EFA3134004A6B28 /* RSParsedFeed.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D241EFA3134004A6B28 /* RSParsedFeed.m */; }; - 84469D2F1EFA3134004A6B28 /* RSRSSParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D251EFA3134004A6B28 /* RSRSSParser.h */; }; + 84469D2F1EFA3134004A6B28 /* RSRSSParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D251EFA3134004A6B28 /* RSRSSParser.h */; settings = {ATTRIBUTES = (Public, ); }; }; 84469D301EFA3134004A6B28 /* RSRSSParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D261EFA3134004A6B28 /* RSRSSParser.m */; }; 84469D321EFA31CF004A6B28 /* FeedParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84469D311EFA31CF004A6B28 /* FeedParser.swift */; }; 84469D351EFF1190004A6B28 /* NSData+RSParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D331EFF1190004A6B28 /* NSData+RSParser.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -73,6 +77,13 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 84285AA71F005D53002E8708 /* RSSParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RSSParser.swift; sourceTree = ""; }; + 84285AA91F006456002E8708 /* RSParsedFeedTransformer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RSParsedFeedTransformer.swift; sourceTree = ""; }; + 84285AAB1F006754002E8708 /* AtomParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AtomParser.swift; sourceTree = ""; }; + 84285AAE1F006BC0002E8708 /* libxml2.2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libxml2.2.tbd; path = usr/lib/libxml2.2.tbd; sourceTree = SDKROOT; }; + 84285AB01F00702E002E8708 /* RSOPMLError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSOPMLError.h; sourceTree = ""; }; + 84285AB11F00702E002E8708 /* RSOPMLError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSOPMLError.m; sourceTree = ""; }; + 84285AB41F007255002E8708 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 84469CE11EFA2F3E004A6B28 /* ParserData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParserData.swift; sourceTree = ""; }; 84469CE51EFA3000004A6B28 /* RSOPMLAttributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSOPMLAttributes.h; sourceTree = ""; }; 84469CE61EFA3000004A6B28 /* RSOPMLAttributes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSOPMLAttributes.m; sourceTree = ""; }; @@ -102,8 +113,6 @@ 84469D151EFA30A2004A6B28 /* RSParserInternal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSParserInternal.m; sourceTree = ""; }; 84469D1D1EFA3134004A6B28 /* RSAtomParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSAtomParser.h; sourceTree = ""; }; 84469D1E1EFA3134004A6B28 /* RSAtomParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSAtomParser.m; sourceTree = ""; }; - 84469D1F1EFA3134004A6B28 /* RSFeedParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSFeedParser.h; sourceTree = ""; }; - 84469D201EFA3134004A6B28 /* RSFeedParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSFeedParser.m; sourceTree = ""; }; 84469D211EFA3134004A6B28 /* RSParsedArticle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSParsedArticle.h; sourceTree = ""; }; 84469D221EFA3134004A6B28 /* RSParsedArticle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSParsedArticle.m; sourceTree = ""; }; 84469D231EFA3134004A6B28 /* RSParsedFeed.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSParsedFeed.h; sourceTree = ""; }; @@ -136,6 +145,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 84285AAF1F006BC0002E8708 /* libxml2.2.tbd in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -159,6 +169,14 @@ name = Dates; sourceTree = ""; }; + 84285AAD1F006BC0002E8708 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 84285AAE1F006BC0002E8708 /* libxml2.2.tbd */, + ); + name = Frameworks; + sourceTree = ""; + }; 84469CE31EFA2FB0004A6B28 /* Feeds */ = { isa = PBXGroup; children = ( @@ -189,6 +207,8 @@ 84469CEA1EFA3000004A6B28 /* RSOPMLFeedSpecifier.m */, 84469CEB1EFA3000004A6B28 /* RSOPMLItem.h */, 84469CEC1EFA3000004A6B28 /* RSOPMLItem.m */, + 84285AB01F00702E002E8708 /* RSOPMLError.h */, + 84285AB11F00702E002E8708 /* RSOPMLError.m */, ); path = OPML; sourceTree = ""; @@ -233,12 +253,13 @@ 84469D1C1EFA3134004A6B28 /* XML */ = { isa = PBXGroup; children = ( + 84285AA71F005D53002E8708 /* RSSParser.swift */, + 84285AAB1F006754002E8708 /* AtomParser.swift */, + 84285AA91F006456002E8708 /* RSParsedFeedTransformer.swift */, 84469D1D1EFA3134004A6B28 /* RSAtomParser.h */, 84469D1E1EFA3134004A6B28 /* RSAtomParser.m */, 84469D251EFA3134004A6B28 /* RSRSSParser.h */, 84469D261EFA3134004A6B28 /* RSRSSParser.m */, - 84469D1F1EFA3134004A6B28 /* RSFeedParser.h */, - 84469D201EFA3134004A6B28 /* RSFeedParser.m */, 84469D211EFA3134004A6B28 /* RSParsedArticle.h */, 84469D221EFA3134004A6B28 /* RSParsedArticle.m */, 84469D231EFA3134004A6B28 /* RSParsedFeed.h */, @@ -261,6 +282,7 @@ 84FF5F7A1EFA285800C15A01 = { isa = PBXGroup; children = ( + 84285AB41F007255002E8708 /* README.md */, 84D81BDA1EFA28E700652332 /* RSParser.h */, 84469CE11EFA2F3E004A6B28 /* ParserData.swift */, 84469CE31EFA2FB0004A6B28 /* Feeds */, @@ -272,6 +294,7 @@ 84D81BD91EFA28E700652332 /* Info.plist */, 84FF5F911EFA285800C15A01 /* RSParserTests */, 84FF5F851EFA285800C15A01 /* Products */, + 84285AAD1F006BC0002E8708 /* Frameworks */, ); sourceTree = ""; }; @@ -312,13 +335,13 @@ 84469D0B1EFA307E004A6B28 /* RSHTMLMetadataParser.h in Headers */, 84469CFC1EFA3069004A6B28 /* RSSAXParser.h in Headers */, 84469D071EFA307E004A6B28 /* RSHTMLLinkParser.h in Headers */, - 84469D291EFA3134004A6B28 /* RSFeedParser.h in Headers */, 84469D0D1EFA307E004A6B28 /* RSSAXHTMLParser.h in Headers */, 84469D2B1EFA3134004A6B28 /* RSParsedArticle.h in Headers */, 84469D2F1EFA3134004A6B28 /* RSRSSParser.h in Headers */, 84469CF31EFA3000004A6B28 /* RSOPMLFeedSpecifier.h in Headers */, 84469CF11EFA3000004A6B28 /* RSOPMLDocument.h in Headers */, 84469D091EFA307E004A6B28 /* RSHTMLMetadata.h in Headers */, + 84285AB21F00702E002E8708 /* RSOPMLError.h in Headers */, 84469D161EFA30A2004A6B28 /* NSString+RSParser.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -434,13 +457,15 @@ 84469CE21EFA2F3E004A6B28 /* ParserData.swift in Sources */, 84469CF21EFA3000004A6B28 /* RSOPMLDocument.m in Sources */, 84469CF61EFA3000004A6B28 /* RSOPMLItem.m in Sources */, - 84469D2A1EFA3134004A6B28 /* RSFeedParser.m in Sources */, 84D81BE41EFA2D3D00652332 /* ParsedItem.swift in Sources */, + 84285AAC1F006754002E8708 /* AtomParser.swift in Sources */, + 84285AA81F005D53002E8708 /* RSSParser.swift in Sources */, 84469D421EFF2B2D004A6B28 /* JSONTypes.swift in Sources */, 84469D0C1EFA307E004A6B28 /* RSHTMLMetadataParser.m in Sources */, 84469D0A1EFA307E004A6B28 /* RSHTMLMetadata.m in Sources */, 84469D171EFA30A2004A6B28 /* NSString+RSParser.m in Sources */, 84469D2C1EFA3134004A6B28 /* RSParsedArticle.m in Sources */, + 84285AAA1F006456002E8708 /* RSParsedFeedTransformer.swift in Sources */, 84469D2E1EFA3134004A6B28 /* RSParsedFeed.m in Sources */, 84469CF81EFA3000004A6B28 /* RSOPMLParser.m in Sources */, 84469D401EFF29A9004A6B28 /* FeedParserError.swift in Sources */, @@ -448,6 +473,7 @@ 84469D281EFA3134004A6B28 /* RSAtomParser.m in Sources */, 84469D361EFF1190004A6B28 /* NSData+RSParser.m in Sources */, 84D81BE61EFA2DFB00652332 /* ParsedAttachment.swift in Sources */, + 84285AB31F00702E002E8708 /* RSOPMLError.m in Sources */, 84D81BDE1EFA2B7D00652332 /* ParsedFeed.swift in Sources */, 84D81BE81EFA2E6700652332 /* ParsedHub.swift in Sources */, 84469D441F002CEF004A6B28 /* JSONFeedParser.swift in Sources */, @@ -594,6 +620,7 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; + HEADER_SEARCH_PATHS = "${SDKROOT}/usr/include/libxml2"; INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; @@ -617,6 +644,7 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; + HEADER_SEARCH_PATHS = "${SDKROOT}/usr/include/libxml2"; INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; diff --git a/Frameworks/RSParser/SAX/RSSAXParser.m b/Frameworks/RSParser/SAX/RSSAXParser.m index fdfa18624..46916d91b 100755 --- a/Frameworks/RSParser/SAX/RSSAXParser.m +++ b/Frameworks/RSParser/SAX/RSSAXParser.m @@ -9,7 +9,7 @@ #import #import #import "RSSAXParser.h" -#import "RSXMLInternal.h" +#import "RSParserInternal.h" @interface RSSAXParser () diff --git a/Frameworks/RSParser/Utilities/NSData+RSParser.m b/Frameworks/RSParser/Utilities/NSData+RSParser.m index 19d88d474..4974a1718 100644 --- a/Frameworks/RSParser/Utilities/NSData+RSParser.m +++ b/Frameworks/RSParser/Utilities/NSData+RSParser.m @@ -13,6 +13,7 @@ static BOOL bytesAreProbablyHTML(const char *bytes, NSUInteger numberOfBytes); static BOOL bytesAreProbablyXML(const char *bytes, NSUInteger numberOfBytes); static BOOL bytesStartWithStringIgnoringWhitespace(const char *string, const char *bytes, NSUInteger numberOfBytes); +static BOOL didFindString(const char *string, const char *bytes, NSUInteger numberOfBytes); @implementation NSData (RSParser) @@ -55,7 +56,7 @@ static BOOL bytesStartWithStringIgnoringWhitespace(const char *string, const cha return NO; } - return didFindString(" #import "NSString+RSParser.h" diff --git a/Frameworks/RSParser/Utilities/RSParserInternal.h b/Frameworks/RSParser/Utilities/RSParserInternal.h index b198e2076..76209e076 100755 --- a/Frameworks/RSParser/Utilities/RSParserInternal.h +++ b/Frameworks/RSParser/Utilities/RSParserInternal.h @@ -10,7 +10,7 @@ NS_ASSUME_NONNULL_BEGIN -BOOL RSParser_IsEmpty(id _Nullable obj); +BOOL RSParserObjectIsEmpty(id _Nullable obj); BOOL RSParserStringIsEmpty(NSString * _Nullable s); diff --git a/Frameworks/RSParser/Utilities/RSParserInternal.m b/Frameworks/RSParser/Utilities/RSParserInternal.m index cf8661971..1bd66ce40 100755 --- a/Frameworks/RSParser/Utilities/RSParserInternal.m +++ b/Frameworks/RSParser/Utilities/RSParserInternal.m @@ -1,5 +1,5 @@ // -// RSXMLInternal.m +// RSParserInternal.m // RSParser // // Created by Brent Simmons on 12/26/16. @@ -7,7 +7,7 @@ // #import -#import "RSXMLInternal.h" +#import "RSParserInternal.h" static BOOL RSParserIsNil(id obj) {