Make progress on getting RSParser.framework to build.

This commit is contained in:
Brent Simmons 2017-06-25 14:06:01 -07:00
parent 6f0e4a9da6
commit 1ad4474b29
37 changed files with 307 additions and 294 deletions

View File

@ -16,7 +16,7 @@ public struct FeedParser {
static let minNumberOfBytesRequired = 128
public static func feedType(parserData: ParserData) -> FeedType {
public static func feedType(_ parserData: ParserData) -> FeedType {
// Can call with partial data while still downloading, for instance.
// If theres not enough data, return .unknown. Ask again when theres more data.
@ -26,38 +26,40 @@ public struct FeedParser {
return .unknown
}
if parserData.data.isProbablyJSONFeed() {
let nsdata = parserData.data as NSData
if nsdata.isProbablyJSONFeed() {
return .jsonFeed
}
if parserData.data.isProbablyRSSInJSON() {
if nsdata.isProbablyRSSInJSON() {
return .rssInJSON
}
if parserData.data.isProbablyHTML() {
if nsdata.isProbablyHTML() {
return .notAFeed
}
if parserData.data.isProbablyRSS() {
if nsdata.isProbablyRSS() {
return .rss
}
if parserData.data.isProbablyAtom() {
if nsdata.isProbablyAtom() {
return .atom
}
return .notAFeed
}
public static func parseFeed(parserData: ParserData) -> ParsedFeed? {
public static func parseFeed(_ parserData: ParserData) throws -> ParsedFeed? {
do {
let type = feedType(parserData)
switch type {
case .jsonFeed:
return JSONFeedParser.parse(parserData)
return try JSONFeedParser.parse(parserData)
case .rssInJSON:
return RSSInJSONFeedParser.parse(parserData)
return try RSSInJSONParser.parse(parserData)
case .rss:
return RSSParser.parse(parserData)
@ -69,4 +71,6 @@ public struct FeedParser {
return nil
}
}
catch { throw error }
}
}

View File

@ -17,6 +17,7 @@ public struct FeedParserError: Error {
case jsonFeedVersionNotFound
case jsonFeedItemsNotFound
case jsonFeedTitleNotFound
case invalidJSON
}
public let errorType: FeedParserErrorType

View File

@ -12,10 +12,12 @@ import Foundation
public struct JSONFeedParser {
public static func parse(parserData: ParserData) throws -> ParsedFeed? {
public static func parse(_ parserData: ParserData) throws -> ParsedFeed? {
do {
let parsedObject = try JSONSerialization.jsonObject(with: parserData.data)
guard let parsedObject = try JSONSerialization.jsonObject(with: parserData.data) as? JSONDictionary else {
throw FeedParserError(.invalidJSON)
}
guard let version = parsedObject["version"] as? String, version.hasPrefix("https://jsonfeed.org/version/") else {
throw FeedParserError(.jsonFeedVersionNotFound)
@ -27,13 +29,13 @@ public struct JSONFeedParser {
throw FeedParserError(.jsonFeedTitleNotFound)
}
let authors = parseAuthors(parsedObject)
let homePageURL = parsedObject["home_page_url"] as? String
let feedURL = parsedObject["feed_url"] ?? parserData.url
let feedURL = parsedObject["feed_url"] as? String ?? parserData.url
let feedDescription = parsedObject["description"] as? String
let nextURL = parsedObject["next_url"] as? String
let iconURL = parsedObject["icon_url"] as? String
let faviconURL = parsedObject["favicon_url"] as? String
let authors = parseAuthors(parsedObject)
let expired = parsedObject["expired"] as? Bool ?? false
let hubs = parseHubs(parsedObject)
@ -48,15 +50,15 @@ public struct JSONFeedParser {
private extension JSONFeedParser {
func parseAuthors(_ dictionary: JSONDictionary) -> [ParsedAuthor]? {
static func parseAuthors(_ dictionary: JSONDictionary) -> [ParsedAuthor]? {
guard let authorDictionary = dictionary["author"] as? JSONDictionary else {
return nil
}
let name = authorDictionary["name"]
let url = authorDictionary["url"]
let avatar = authorDictionary["avatar"]
let name = authorDictionary["name"] as? String
let url = authorDictionary["url"] as? String
let avatar = authorDictionary["avatar"] as? String
if name == nil && url == nil && avatar == nil {
return nil
}
@ -64,14 +66,14 @@ private extension JSONFeedParser {
return [parsedAuthor]
}
func parseHubs(_ dictionary: JSONDictionary) -> [ParsedHub]? {
static func parseHubs(_ dictionary: JSONDictionary) -> [ParsedHub]? {
guard let hubsArray = dictionary["hubs"] as? JSONArray else {
return nil
}
let hubs = hubsArray.flatMap { (oneHubDictionary) -> ParsedHub? in
guard let oneHubURL = oneHubDictionary["url"], let oneHubType = oneHubDictionary["type"] else {
guard let oneHubURL = oneHubDictionary["url"] as? String, let oneHubType = oneHubDictionary["type"] as? String else {
return nil
}
return ParsedHub(type: oneHubType, url: oneHubURL)
@ -79,14 +81,14 @@ private extension JSONFeedParser {
return hubs.isEmpty ? nil : hubs
}
func parseItems(_ itemsArray: JSONArray) -> [ParsedItem] {
static func parseItems(_ itemsArray: JSONArray) -> [ParsedItem] {
return itemsArray.flatMap { (oneItemDictionary) -> ParsedItem? in
return parseItem(oneItemDictionary)
}
}
func parseItem(_ itemDictionary: JSONDictionary) -> ParsedItem? {
static func parseItem(_ itemDictionary: JSONDictionary) -> ParsedItem? {
guard let uniqueID = parseUniqueID(itemDictionary) else {
return nil
@ -105,8 +107,8 @@ private extension JSONFeedParser {
let imageURL = itemDictionary["image"] as? String
let bannerImageURL = itemDictionary["banner_image"] as? String
let datePublished = parseDate(itemDictionary["date_published"])
let dateModified = parseDate(itemDictionary["date_modified"])
let datePublished = parseDate(itemDictionary["date_published"] as? String)
let dateModified = parseDate(itemDictionary["date_modified"] as? String)
let authors = parseAuthors(itemDictionary)
let tags = itemDictionary["tags"] as? [String]
@ -115,7 +117,7 @@ private extension JSONFeedParser {
return ParsedItem(uniqueID: uniqueID, url: url, externalURL: externalURL, title: title, contentHTML: contentHTML, contentText: contentText, summary: summary, imageURL: imageURL, bannerImageURL: bannerImageURL, datePublished: datePublished, dateModified: dateModified, authors: authors, tags: tags, attachments: attachments)
}
func parseUniqueID(_ itemDictionary: JSONDictionary) -> String? {
static func parseUniqueID(_ itemDictionary: JSONDictionary) -> String? {
if let uniqueID = itemDictionary["id"] as? String {
return uniqueID // Spec says it must be a string
@ -130,7 +132,7 @@ private extension JSONFeedParser {
return nil
}
func parseDate(_ dateString: String?) -> Date? {
static func parseDate(_ dateString: String?) -> Date? {
guard let dateString = dateString, !dateString.isEmpty else {
return nil
@ -138,7 +140,7 @@ private extension JSONFeedParser {
return RSDateWithString(dateString)
}
func parseAttachments(_ itemDictionary: JSONDictionary) -> [ParsedAttachment]? {
static func parseAttachments(_ itemDictionary: JSONDictionary) -> [ParsedAttachment]? {
guard let attachmentsArray = itemDictionary["attachments"] as? JSONArray else {
return nil
@ -148,7 +150,7 @@ private extension JSONFeedParser {
}
}
func parseAttachment(_ attachmentObject: JSONDictionary) -> ParsedAttachment? {
static func parseAttachment(_ attachmentObject: JSONDictionary) -> ParsedAttachment? {
guard let url = attachmentObject["url"] as? String else {
return nil

View File

@ -13,10 +13,12 @@ import Foundation
public struct RSSInJSONParser {
public static func parse(parserData: ParserData) throws -> ParsedFeed? {
public static func parse(_ parserData: ParserData) throws -> ParsedFeed? {
do {
let parsedObject = try JSONSerialization.jsonObject(with: parserData.data)
guard let parsedObject = try JSONSerialization.jsonObject(with: parserData.data) as? JSONDictionary else {
throw FeedParserError(.invalidJSON)
}
guard let channelObject = parsedObject["channel"] as? JSONDictionary else {
throw FeedParserError(.rssChannelNotFound)
@ -32,7 +34,7 @@ public struct RSSInJSONParser {
itemsObject = channelObject["items"] as? JSONArray
}
if itemsObject == nil {
itemsObject == parsedObject["items"] as? JSONArray
itemsObject = parsedObject["items"] as? JSONArray
}
if itemsObject == nil {
throw FeedParserError(.rssItemsNotFound)
@ -43,7 +45,7 @@ public struct RSSInJSONParser {
let feedURL = parserData.url
let feedDescription = channelObject["description"] as? String
let items = parseItems(itemsObject)
let items = parseItems(itemsObject!)
return ParsedFeed(type: .rssInJSON, title: title, homePageURL: homePageURL, feedURL: feedURL, feedDescription: feedDescription, nextURL: nil, iconURL: nil, faviconURL: nil, authors: nil, expired: false, hubs: nil, items: items)
@ -56,19 +58,19 @@ private extension RSSInJSONParser {
static func parseItems(_ itemsObject: JSONArray) -> [ParsedItem] {
return itemsObject.flatMap{ (oneItemDictionary) -> ParsedItem in
return itemsObject.flatMap{ (oneItemDictionary) -> ParsedItem? in
return parsedItemWithDictionary(oneItemDictionary)
}
}
static func parsedItemWithDictionary(_ JSONDictionary: itemDictionary) -> ParsedItem? {
static func parsedItemWithDictionary(_ itemDictionary: JSONDictionary) -> ParsedItem? {
let externalURL = itemDictionary["link"] as? String
let title = itemDictionary["title"] as? String
var contentHTML = itemDictionary["description"] as? String
var contentText = nil
var contentText: String? = nil
if contentHTML != nil && !(contentHTML!.contains("<")) {
contentText = contentHTML
contentHTML = nil
@ -77,9 +79,9 @@ private extension RSSInJSONParser {
return nil
}
var datePublished: Date = nil
var datePublished: Date? = nil
if let datePublishedString = itemDictionary["pubDate"] as? String {
datePublished = RSDateWithString(datePublishedString as NSString)
datePublished = RSDateWithString(datePublishedString)
}
let authors = parseAuthors(itemDictionary)
@ -112,14 +114,14 @@ private extension RSSInJSONParser {
}
if s.isEmpty {
// Sheesh. Tough case.
if contentHTML != nil {
s = contentHTML
if let _ = contentHTML {
s = contentHTML!
}
if contentText != nil {
s = contentText
if let _ = contentText {
s = contentText!
}
}
uniqueID = (s as NSString).rsxml_md5HashString()
uniqueID = (s as NSString).rsparser_md5Hash()
}
return ParsedItem(uniqueID: uniqueID, url: nil, externalURL: externalURL, title: title, contentHTML: contentHTML, contentText: contentText, summary: nil, imageURL: nil, bannerImageURL: nil, datePublished: datePublished, dateModified: nil, authors: authors, tags: tags, attachments: attachments)
@ -137,11 +139,14 @@ private extension RSSInJSONParser {
static func parseTags(_ itemDictionary: JSONDictionary) -> [String]? {
if let categoryObject = itemDictionary["category"] as? JSONDictionary {
return categoryObject["#value"]
if let oneTag = categoryObject["#value"] as? String {
return [oneTag]
}
return nil
}
else if let categoryArray = itemDictionary["category"] as? JSONArray {
return categoryArray.flatMap{ (categoryObject) in
return categoryObject["#value"]
return categoryObject["#value"] as? String
}
}
return nil

View File

@ -1,6 +1,6 @@
//
// RSAtomParser.h
// RSXML
// RSParser
//
// Created by Brent Simmons on 1/15/15.
// Copyright (c) 2015 Ranchero Software LLC. All rights reserved.

View File

@ -1,6 +1,6 @@
//
// RSAtomParser.m
// RSXML
// RSParser
//
// Created by Brent Simmons on 1/15/15.
// Copyright (c) 2015 Ranchero Software LLC. All rights reserved.

View File

@ -1,6 +1,6 @@
//
// RSFeedParser.h
// RSXML
// RSParser
//
// Created by Brent Simmons on 1/4/15.
// Copyright (c) 2015 Ranchero Software LLC. All rights reserved.

View File

@ -1,6 +1,6 @@
//
// FeedParser.m
// RSXML
// RSParser
//
// Created by Brent Simmons on 1/4/15.
// Copyright (c) 2015 Ranchero Software LLC. All rights reserved.

View File

@ -56,16 +56,16 @@
datePublishedTimeStampString = [NSString stringWithFormat:@"%.0f", self.datePublished.timeIntervalSince1970];
}
if (!RSXMLStringIsEmpty(self.guid)) {
if (!RSParserStringIsEmpty(self.guid)) {
[s appendString:self.guid];
}
else if (!RSXMLStringIsEmpty(self.link) && self.datePublished != nil) {
else if (!RSParserStringIsEmpty(self.link) && self.datePublished != nil) {
[s appendString:self.link];
[s appendString:datePublishedTimeStampString];
}
else if (!RSXMLStringIsEmpty(self.title) && self.datePublished != nil) {
else if (!RSParserStringIsEmpty(self.title) && self.datePublished != nil) {
[s appendString:self.title];
[s appendString:datePublishedTimeStampString];
}
@ -74,19 +74,19 @@
[s appendString:datePublishedTimeStampString];
}
else if (!RSXMLStringIsEmpty(self.link)) {
else if (!RSParserStringIsEmpty(self.link)) {
[s appendString:self.link];
}
else if (!RSXMLStringIsEmpty(self.title)) {
else if (!RSParserStringIsEmpty(self.title)) {
[s appendString:self.title];
}
else if (!RSXMLStringIsEmpty(self.body)) {
else if (!RSParserStringIsEmpty(self.body)) {
[s appendString:self.body];
}
NSAssert(!RSXMLStringIsEmpty(self.feedURL), nil);
NSAssert(!RSParserStringIsEmpty(self.feedURL), nil);
[s appendString:self.feedURL];
return [s rsxml_md5HashString];

View File

@ -1,6 +1,6 @@
//
// RSRSSParser.h
// RSXML
// RSParser
//
// Created by Brent Simmons on 1/6/15.
// Copyright (c) 2015 Ranchero Software LLC. All rights reserved.

View File

@ -1,6 +1,6 @@
//
// RSRSSParser.m
// RSXML
// RSParser
//
// Created by Brent Simmons on 1/6/15.
// Copyright (c) 2015 Ranchero Software LLC. All rights reserved.
@ -256,7 +256,7 @@ static const NSInteger kTrueLength = 5;
self.currentArticle.guid = self.parser.currentStringWithTrimmedWhitespace;
NSString *isPermaLinkValue = [self.currentAttributes rsxml_objectForCaseInsensitiveKey:@"ispermalink"];
NSString *isPermaLinkValue = [self.currentAttributes rsparser_objectForCaseInsensitiveKey:@"ispermalink"];
if (!isPermaLinkValue || ![isPermaLinkValue isEqualToString:@"false"]) {
self.currentArticle.permalink = [self urlString:self.currentArticle.guid];
}

View File

@ -1,6 +1,6 @@
//
// RSHTMLLinkParser.h
// RSXML
// RSParser
//
// Created by Brent Simmons on 8/7/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.

View File

@ -1,6 +1,6 @@
//
// RSHTMLLinkParser.m
// RSXML
// RSParser
//
// Created by Brent Simmons on 8/7/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
@ -88,7 +88,7 @@ static NSString *kHrefKey = @"href";
- (NSString *)urlStringFromDictionary:(NSDictionary *)d {
NSString *href = [d rsxml_objectForCaseInsensitiveKey:kHrefKey];
NSString *href = [d rsparser_objectForCaseInsensitiveKey:kHrefKey];
if (!href) {
return nil;
}
@ -102,7 +102,7 @@ static NSString *kTitleKey = @"title";
- (NSString *)titleFromDictionary:(NSDictionary *)d {
return [d rsxml_objectForCaseInsensitiveKey:kTitleKey];
return [d rsparser_objectForCaseInsensitiveKey:kTitleKey];
}
@ -127,7 +127,7 @@ static const NSInteger kAnchorLength = 2;
[self.links addObject:link];
NSDictionary *d = [SAXParser attributesDictionary:attributes];
if (!RSXMLIsEmpty(d)) {
if (!RSParser_IsEmpty(d)) {
[self handleLinkAttributes:d];
}

View File

@ -1,6 +1,6 @@
//
// RSHTMLMetadata.h
// RSXML
// RSParser
//
// Created by Brent Simmons on 3/6/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.

View File

@ -1,6 +1,6 @@
//
// RSHTMLMetadata.m
// RSXML
// RSParser
//
// Created by Brent Simmons on 3/6/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
@ -114,12 +114,12 @@ static NSString *kTypeKey = @"type";
continue;
}
NSString *oneType = [oneDictionary rsxml_objectForCaseInsensitiveKey:kTypeKey];
NSString *oneType = [oneDictionary rsparser_objectForCaseInsensitiveKey:kTypeKey];
if (!typeIsFeedType(oneType)) {
continue;
}
if (RSXMLStringIsEmpty(urlStringFromDictionary(oneDictionary))) {
if (RSParserStringIsEmpty(urlStringFromDictionary(oneDictionary))) {
continue;
}
@ -142,18 +142,18 @@ static NSString *kTypeKey = @"type";
static NSString *relValue(NSDictionary *d) {
return [d rsxml_objectForCaseInsensitiveKey:kRelKey];
return [d rsparser_objectForCaseInsensitiveKey:kRelKey];
}
static NSString *urlStringFromDictionary(NSDictionary *d) {
NSString *urlString = [d rsxml_objectForCaseInsensitiveKey:kHrefKey];
NSString *urlString = [d rsparser_objectForCaseInsensitiveKey:kHrefKey];
if (urlString) {
return urlString;
}
return [d rsxml_objectForCaseInsensitiveKey:kSrcKey];
return [d rsparser_objectForCaseInsensitiveKey:kSrcKey];
}
@ -172,7 +172,7 @@ static NSString *absoluteURLStringWithRelativeURLString(NSString *relativeURLStr
static NSString *absoluteURLStringWithDictionary(NSDictionary *d, NSString *baseURLString) {
NSString *urlString = urlStringFromDictionary(d);
if (RSXMLStringIsEmpty(urlString)) {
if (RSParserStringIsEmpty(urlString)) {
return nil;
}
return absoluteURLStringWithRelativeURLString(urlString, baseURLString);
@ -213,8 +213,8 @@ static BOOL typeIsFeedType(NSString *type) {
}
_urlString = absoluteURLStringWithDictionary(d, baseURLString);
_sizes = [d rsxml_objectForCaseInsensitiveKey:kSizesKey];
_rel = [d rsxml_objectForCaseInsensitiveKey:kRelKey];
_sizes = [d rsparser_objectForCaseInsensitiveKey:kSizesKey];
_rel = [d rsparser_objectForCaseInsensitiveKey:kRelKey];
return self;
}
@ -234,8 +234,8 @@ static BOOL typeIsFeedType(NSString *type) {
}
_urlString = absoluteURLStringWithDictionary(d, baseURLString);
_title = [d rsxml_objectForCaseInsensitiveKey:kTitleKey];
_type = [d rsxml_objectForCaseInsensitiveKey:kTypeKey];
_title = [d rsparser_objectForCaseInsensitiveKey:kTitleKey];
_type = [d rsparser_objectForCaseInsensitiveKey:kTypeKey];
return self;
}

View File

@ -1,6 +1,6 @@
//
// RSHTMLMetadataParser.h
// RSXML
// RSParser
//
// Created by Brent Simmons on 3/6/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.

View File

@ -76,21 +76,21 @@ static NSString *kRelKey = @"rel";
- (NSString *)linkForDictionary:(NSDictionary *)d {
NSString *link = [d rsxml_objectForCaseInsensitiveKey:kHrefKey];
NSString *link = [d rsparser_objectForCaseInsensitiveKey:kHrefKey];
if (link) {
return link;
}
return [d rsxml_objectForCaseInsensitiveKey:kSrcKey];
return [d rsparser_objectForCaseInsensitiveKey:kSrcKey];
}
- (void)handleLinkAttributes:(NSDictionary *)d {
if (RSXMLStringIsEmpty([d rsxml_objectForCaseInsensitiveKey:kRelKey])) {
if (RSParserStringIsEmpty([d rsparser_objectForCaseInsensitiveKey:kRelKey])) {
return;
}
if (RSXMLStringIsEmpty([self linkForDictionary:d])) {
if (RSParserStringIsEmpty([self linkForDictionary:d])) {
return;
}
@ -121,7 +121,7 @@ static const NSInteger kLinkLength = 5;
}
NSDictionary *d = [SAXParser attributesDictionary:attributes];
if (!RSXMLIsEmpty(d)) {
if (!RSParser_IsEmpty(d)) {
[self handleLinkAttributes:d];
}
}

View File

@ -1,6 +1,6 @@
//
// RSSAXHTMLParser.h
// RSXML
// RSParser
//
// Created by Brent Simmons on 3/6/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.

View File

@ -1,6 +1,6 @@
//
// RSSAXHTMLParser.m
// RSXML
// RSParser
//
// Created by Brent Simmons on 3/6/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
@ -150,7 +150,7 @@ static xmlSAXHandler saxHandlerStruct;
- (NSString *)currentString {
NSData *d = self.currentCharacters;
if (RSXMLIsEmpty(d)) {
if (RSParserObjectIsEmpty(d)) {
return nil;
}

View File

@ -23,43 +23,43 @@ NSString *OPMLXMLURLKey = @"xmlUrl";
- (NSString *)opml_text {
return [self rsxml_objectForCaseInsensitiveKey:OPMLTextKey];
return [self rsparser_objectForCaseInsensitiveKey:OPMLTextKey];
}
- (NSString *)opml_title {
return [self rsxml_objectForCaseInsensitiveKey:OPMLTitleKey];
return [self rsparser_objectForCaseInsensitiveKey:OPMLTitleKey];
}
- (NSString *)opml_description {
return [self rsxml_objectForCaseInsensitiveKey:OPMLDescriptionKey];
return [self rsparser_objectForCaseInsensitiveKey:OPMLDescriptionKey];
}
- (NSString *)opml_type {
return [self rsxml_objectForCaseInsensitiveKey:OPMLTypeKey];
return [self rsparser_objectForCaseInsensitiveKey:OPMLTypeKey];
}
- (NSString *)opml_version {
return [self rsxml_objectForCaseInsensitiveKey:OPMLVersionKey];
return [self rsparser_objectForCaseInsensitiveKey:OPMLVersionKey];
}
- (NSString *)opml_htmlUrl {
return [self rsxml_objectForCaseInsensitiveKey:OPMLHMTLURLKey];
return [self rsparser_objectForCaseInsensitiveKey:OPMLHMTLURLKey];
}
- (NSString *)opml_xmlUrl {
return [self rsxml_objectForCaseInsensitiveKey:OPMLXMLURLKey];
return [self rsparser_objectForCaseInsensitiveKey:OPMLXMLURLKey];
}

View File

@ -14,28 +14,28 @@
- (instancetype)initWithTitle:(NSString *)title feedDescription:(NSString *)feedDescription homePageURL:(NSString *)homePageURL feedURL:(NSString *)feedURL {
NSParameterAssert(!RSXMLIsEmpty(feedURL));
NSParameterAssert(!RSParserStringIsEmpty(feedURL));
self = [super init];
if (!self) {
return nil;
}
if (RSXMLIsEmpty(title)) {
if (RSParserStringIsEmpty(title)) {
_title = nil;
}
else {
_title = title;
}
if (RSXMLIsEmpty(feedDescription)) {
if (RSParserStringIsEmpty(feedDescription)) {
_feedDescription = nil;
}
else {
_feedDescription = feedDescription;
}
if (RSXMLIsEmpty(homePageURL)) {
if (RSParserStringIsEmpty(homePageURL)) {
_homePageURL = nil;
}
else {

View File

@ -55,7 +55,7 @@
}
NSString *feedURL = self.attributes.opml_xmlUrl;
if (RSXMLIsEmpty(feedURL)) {
if (RSParserObjectIsEmpty(feedURL)) {
return nil;
}

View File

@ -9,7 +9,8 @@
@import Foundation;
#import <RSParser/NSData+RSParser.h>
#import <RSParser/RSParser.h>
#import <RSParser/RSDateParser.h>
#import <RSParser/NSString+RSParser.h>
//#import <RSXML/RSSAXParser.h>
//#import <RSXML/RSXMLData.h>

View File

@ -28,12 +28,12 @@
84469D0C1EFA307E004A6B28 /* RSHTMLMetadataParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D041EFA307E004A6B28 /* RSHTMLMetadataParser.m */; };
84469D0D1EFA307E004A6B28 /* RSSAXHTMLParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D051EFA307E004A6B28 /* RSSAXHTMLParser.h */; };
84469D0E1EFA307E004A6B28 /* RSSAXHTMLParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D061EFA307E004A6B28 /* RSSAXHTMLParser.m */; };
84469D161EFA30A2004A6B28 /* NSString+RSXML.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D101EFA30A2004A6B28 /* NSString+RSXML.h */; };
84469D171EFA30A2004A6B28 /* NSString+RSXML.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D111EFA30A2004A6B28 /* NSString+RSXML.m */; };
84469D181EFA30A2004A6B28 /* RSDateParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D121EFA30A2004A6B28 /* RSDateParser.h */; };
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 */; };
84469D181EFA30A2004A6B28 /* RSDateParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D121EFA30A2004A6B28 /* RSDateParser.h */; settings = {ATTRIBUTES = (Public, ); }; };
84469D191EFA30A2004A6B28 /* RSDateParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D131EFA30A2004A6B28 /* RSDateParser.m */; };
84469D1A1EFA30A2004A6B28 /* RSXMLInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D141EFA30A2004A6B28 /* RSXMLInternal.h */; };
84469D1B1EFA30A2004A6B28 /* RSXMLInternal.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D151EFA30A2004A6B28 /* RSXMLInternal.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 */; };
84469D281EFA3134004A6B28 /* RSAtomParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D1E1EFA3134004A6B28 /* RSAtomParser.m */; };
84469D291EFA3134004A6B28 /* RSFeedParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D1F1EFA3134004A6B28 /* RSFeedParser.h */; };
@ -45,7 +45,7 @@
84469D2F1EFA3134004A6B28 /* RSRSSParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D251EFA3134004A6B28 /* RSRSSParser.h */; };
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 */; };
84469D351EFF1190004A6B28 /* NSData+RSParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 84469D331EFF1190004A6B28 /* NSData+RSParser.h */; settings = {ATTRIBUTES = (Public, ); }; };
84469D361EFF1190004A6B28 /* NSData+RSParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 84469D341EFF1190004A6B28 /* NSData+RSParser.m */; };
84469D381EFF2645004A6B28 /* RSSInJSONParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84469D371EFF2645004A6B28 /* RSSInJSONParser.swift */; };
84469D401EFF29A9004A6B28 /* FeedParserError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84469D3F1EFF29A9004A6B28 /* FeedParserError.swift */; };
@ -94,12 +94,12 @@
84469D041EFA307E004A6B28 /* RSHTMLMetadataParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSHTMLMetadataParser.m; sourceTree = "<group>"; };
84469D051EFA307E004A6B28 /* RSSAXHTMLParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSSAXHTMLParser.h; sourceTree = "<group>"; };
84469D061EFA307E004A6B28 /* RSSAXHTMLParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSSAXHTMLParser.m; sourceTree = "<group>"; };
84469D101EFA30A2004A6B28 /* NSString+RSXML.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+RSXML.h"; sourceTree = "<group>"; };
84469D111EFA30A2004A6B28 /* NSString+RSXML.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+RSXML.m"; sourceTree = "<group>"; };
84469D121EFA30A2004A6B28 /* RSDateParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSDateParser.h; sourceTree = "<group>"; };
84469D131EFA30A2004A6B28 /* RSDateParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSDateParser.m; sourceTree = "<group>"; };
84469D141EFA30A2004A6B28 /* RSXMLInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSXMLInternal.h; sourceTree = "<group>"; };
84469D151EFA30A2004A6B28 /* RSXMLInternal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSXMLInternal.m; sourceTree = "<group>"; };
84469D101EFA30A2004A6B28 /* NSString+RSParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+RSParser.h"; sourceTree = "<group>"; };
84469D111EFA30A2004A6B28 /* NSString+RSParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+RSParser.m"; sourceTree = "<group>"; };
84469D121EFA30A2004A6B28 /* RSDateParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RSDateParser.h; path = Utilities/RSDateParser.h; sourceTree = "<group>"; };
84469D131EFA30A2004A6B28 /* RSDateParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RSDateParser.m; path = Utilities/RSDateParser.m; sourceTree = "<group>"; };
84469D141EFA30A2004A6B28 /* RSParserInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSParserInternal.h; sourceTree = "<group>"; };
84469D151EFA30A2004A6B28 /* RSParserInternal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSParserInternal.m; sourceTree = "<group>"; };
84469D1D1EFA3134004A6B28 /* RSAtomParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSAtomParser.h; sourceTree = "<group>"; };
84469D1E1EFA3134004A6B28 /* RSAtomParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSAtomParser.m; sourceTree = "<group>"; };
84469D1F1EFA3134004A6B28 /* RSFeedParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RSFeedParser.h; sourceTree = "<group>"; };
@ -150,6 +150,15 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
84285AA61F004879002E8708 /* Dates */ = {
isa = PBXGroup;
children = (
84469D121EFA30A2004A6B28 /* RSDateParser.h */,
84469D131EFA30A2004A6B28 /* RSDateParser.m */,
);
name = Dates;
sourceTree = "<group>";
};
84469CE31EFA2FB0004A6B28 /* Feeds */ = {
isa = PBXGroup;
children = (
@ -213,12 +222,10 @@
children = (
84469D331EFF1190004A6B28 /* NSData+RSParser.h */,
84469D341EFF1190004A6B28 /* NSData+RSParser.m */,
84469D101EFA30A2004A6B28 /* NSString+RSXML.h */,
84469D111EFA30A2004A6B28 /* NSString+RSXML.m */,
84469D121EFA30A2004A6B28 /* RSDateParser.h */,
84469D131EFA30A2004A6B28 /* RSDateParser.m */,
84469D141EFA30A2004A6B28 /* RSXMLInternal.h */,
84469D151EFA30A2004A6B28 /* RSXMLInternal.m */,
84469D101EFA30A2004A6B28 /* NSString+RSParser.h */,
84469D111EFA30A2004A6B28 /* NSString+RSParser.m */,
84469D141EFA30A2004A6B28 /* RSParserInternal.h */,
84469D151EFA30A2004A6B28 /* RSParserInternal.m */,
);
path = Utilities;
sourceTree = "<group>";
@ -257,6 +264,7 @@
84D81BDA1EFA28E700652332 /* RSParser.h */,
84469CE11EFA2F3E004A6B28 /* ParserData.swift */,
84469CE31EFA2FB0004A6B28 /* Feeds */,
84285AA61F004879002E8708 /* Dates */,
84469CE41EFA3000004A6B28 /* OPML */,
84469CFE1EFA307E004A6B28 /* HTML */,
84469CF91EFA3069004A6B28 /* SAX */,
@ -298,7 +306,7 @@
84469CF51EFA3000004A6B28 /* RSOPMLItem.h in Headers */,
84469D2D1EFA3134004A6B28 /* RSParsedFeed.h in Headers */,
84469D181EFA30A2004A6B28 /* RSDateParser.h in Headers */,
84469D1A1EFA30A2004A6B28 /* RSXMLInternal.h in Headers */,
84469D1A1EFA30A2004A6B28 /* RSParserInternal.h in Headers */,
84469D351EFF1190004A6B28 /* NSData+RSParser.h in Headers */,
84D81BDC1EFA28E700652332 /* RSParser.h in Headers */,
84469D0B1EFA307E004A6B28 /* RSHTMLMetadataParser.h in Headers */,
@ -311,7 +319,7 @@
84469CF31EFA3000004A6B28 /* RSOPMLFeedSpecifier.h in Headers */,
84469CF11EFA3000004A6B28 /* RSOPMLDocument.h in Headers */,
84469D091EFA307E004A6B28 /* RSHTMLMetadata.h in Headers */,
84469D161EFA30A2004A6B28 /* NSString+RSXML.h in Headers */,
84469D161EFA30A2004A6B28 /* NSString+RSParser.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -414,7 +422,7 @@
buildActionMask = 2147483647;
files = (
84469D081EFA307E004A6B28 /* RSHTMLLinkParser.m in Sources */,
84469D1B1EFA30A2004A6B28 /* RSXMLInternal.m in Sources */,
84469D1B1EFA30A2004A6B28 /* RSParserInternal.m in Sources */,
84D81BE21EFA2D0900652332 /* ParsedAuthor.swift in Sources */,
84469D0E1EFA307E004A6B28 /* RSSAXHTMLParser.m in Sources */,
84469CF41EFA3000004A6B28 /* RSOPMLFeedSpecifier.m in Sources */,
@ -431,7 +439,7 @@
84469D421EFF2B2D004A6B28 /* JSONTypes.swift in Sources */,
84469D0C1EFA307E004A6B28 /* RSHTMLMetadataParser.m in Sources */,
84469D0A1EFA307E004A6B28 /* RSHTMLMetadata.m in Sources */,
84469D171EFA30A2004A6B28 /* NSString+RSXML.m in Sources */,
84469D171EFA30A2004A6B28 /* NSString+RSParser.m in Sources */,
84469D2C1EFA3134004A6B28 /* RSParsedArticle.m in Sources */,
84469D2E1EFA3134004A6B28 /* RSParsedFeed.m in Sources */,
84469CF81EFA3000004A6B28 /* RSOPMLParser.m in Sources */,

View File

@ -1,6 +1,6 @@
//
// RSSAXParser.h
// RSXML
// RSParser
//
// Created by Brent Simmons on 3/25/15.
// Copyright (c) 2015 Ranchero Software, LLC. All rights reserved.

View File

@ -1,6 +1,6 @@
//
// RSSAXParser.m
// RSXML
// RSParser
//
// Created by Brent Simmons on 3/25/15.
// Copyright (c) 2015 Ranchero Software, LLC. All rights reserved.
@ -152,7 +152,7 @@ static xmlSAXHandler saxHandlerStruct;
- (NSString *)currentString {
NSData *d = self.currentCharacters;
if (RSXMLIsEmpty(d)) {
if (RSParserObjectIsEmpty(d)) {
return nil;
}

View File

@ -15,6 +15,11 @@
- (BOOL)isProbablyXML;
- (BOOL)isProbablyJSON;
- (BOOL)isProbablyJSONFeed;
- (BOOL)isProbablyRSSInJSON;
- (BOOL)isProbablyRSS;
- (BOOL)isProbablyAtom;
@end

View File

@ -39,7 +39,7 @@ static BOOL bytesStartWithStringIgnoringWhitespace(const char *string, const cha
return didFindString("https://jsonfeed.org/version/", self.bytes, self.length);
}
- (BOOL)isProbablyRSSInJSONFeed {
- (BOOL)isProbablyRSSInJSON {
if (![self isProbablyJSON]) {
return NO;

View File

@ -0,0 +1,18 @@
//
// NSString+RSParser.h
// RSParser
//
// Created by Brent Simmons on 9/25/15.
// Copyright © 2015 Ranchero Software, LLC. All rights reserved.
//
@import Foundation;
@interface NSString (RSParser)
- (NSString *)rsparser_stringByDecodingHTMLEntities;
- (NSString *)rsparser_md5Hash;
@end

View File

@ -1,24 +1,24 @@
//
// NSString+RSXML.m
// RSXML
// NSString+RSParser.m
// RSParser
//
// Created by Brent Simmons on 9/25/15.
// Copyright © 2015 Ranchero Software, LLC. All rights reserved.
//
#import "NSString+RSXML.h"
#import "NSString+RSParser.h"
@interface NSScanner (RSXML)
@interface NSScanner (RSParser)
- (BOOL)rs_scanEntityValue:(NSString * _Nullable * _Nullable)decodedEntity;
@end
@implementation NSString (RSXML)
@implementation NSString (RSParser)
- (NSString *)rs_stringByDecodingHTMLEntities {
- (NSString *)rsparser_stringByDecodingHTMLEntities {
@autoreleasepool {
@ -60,7 +60,7 @@
static NSDictionary *RSEntitiesDictionary(void);
static NSString *RSXMLStringWithValue(unichar value);
static NSString *RSParserStringWithValue(unichar value);
- (NSString * _Nullable)rs_stringByDecodingEntity {
@ -87,7 +87,7 @@ static NSString *RSXMLStringWithValue(unichar value);
scanner.charactersToBeSkipped = [NSCharacterSet characterSetWithCharactersInString:@"#x"];
unsigned int hexValue = 0;
if ([scanner scanHexInt:&hexValue]) {
return RSXMLStringWithValue((unichar)hexValue);
return RSParserStringWithValue((unichar)hexValue);
}
return nil;
}
@ -98,15 +98,33 @@ static NSString *RSXMLStringWithValue(unichar value);
if (value < 1) {
return nil;
}
return RSXMLStringWithValue((unichar)value);
return RSParserStringWithValue((unichar)value);
}
return nil;
}
- (NSData *)_rsparser_md5HashData {
NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
unsigned char hash[CC_MD5_DIGEST_LENGTH];
CC_MD5(data.bytes, (CC_LONG)data.length, hash);
return [NSData dataWithBytes:(const void *)hash length:CC_MD5_DIGEST_LENGTH];
}
- (NSString *)rsparser_md5Hash {
NSData *md5Data = [self _rsparser_md5HashData];
const Byte *bytes = md5Data.bytes;
return [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]];
}
@end
@implementation NSScanner (RSXML)
@implementation NSScanner (RSParser)
- (BOOL)rs_scanEntityValue:(NSString * _Nullable * _Nullable)decodedEntity {
@ -144,7 +162,7 @@ static NSString *RSXMLStringWithValue(unichar value);
@end
static NSString *RSXMLStringWithValue(unichar value) {
static NSString *RSParserStringWithValue(unichar value) {
return [[NSString alloc] initWithFormat:@"%C", value];
}
@ -169,7 +187,7 @@ static NSDictionary *RSEntitiesDictionary(void) {
@"#150": @"-",
@"#151": @"—",
@"#153": @"™",
@"#160": RSXMLStringWithValue(160),
@"#160": RSParserStringWithValue(160),
@"#161": @"¡",
@"#162": @"¢",
@"#163": @"£",
@ -277,7 +295,7 @@ static NSDictionary *RSEntitiesDictionary(void) {
@"#8220": @"“",
@"#8221": @"”",
@"#8230": @"…",
@"#8617": RSXMLStringWithValue(8617),
@"#8617": RSParserStringWithValue(8617),
@"AElig": @"Æ",
@"Aacute": @"Á",
@"Acirc": @"Â",
@ -394,14 +412,14 @@ static NSDictionary *RSEntitiesDictionary(void) {
@"yen": @"¥",
@"yuml": @"ÿ",
@"infin": @"∞",
@"nbsp": RSXMLStringWithValue(160),
@"#x21A9": RSXMLStringWithValue(8617),
@"#xFE0E": RSXMLStringWithValue(65038),
@"#x2019": RSXMLStringWithValue(8217),
@"#x2026": RSXMLStringWithValue(8230),
@"#x201C": RSXMLStringWithValue(8220),
@"#x201D": RSXMLStringWithValue(8221),
@"#x2014": RSXMLStringWithValue(8212)};
@"nbsp": RSParserStringWithValue(160),
@"#x21A9": RSParserStringWithValue(8617),
@"#xFE0E": RSParserStringWithValue(65038),
@"#x2019": RSParserStringWithValue(8217),
@"#x2026": RSParserStringWithValue(8230),
@"#x201C": RSParserStringWithValue(8220),
@"#x201D": RSParserStringWithValue(8221),
@"#x2014": RSParserStringWithValue(8212)};
});
return entitiesDictionary;

View File

@ -1,16 +0,0 @@
//
// NSString+RSXML.h
// RSXML
//
// Created by Brent Simmons on 9/25/15.
// Copyright © 2015 Ranchero Software, LLC. All rights reserved.
//
@import Foundation;
@interface NSString (RSXML)
- (NSString *)rs_stringByDecodingHTMLEntities;
@end

View File

@ -1,6 +1,6 @@
//
// RSDateParser.h
// RSXML
// RSParser
//
// Created by Brent Simmons on 3/25/15.
// Copyright (c) 2015 Ranchero Software, LLC. All rights reserved.
@ -9,17 +9,14 @@
@import Foundation;
/*Common web dates -- RFC 822 and 8601 -- are handled here:
the formats you find in JSON and XML feeds.
Any of these may return nil. They may also return garbage, given bad input.*/
// Common web dates -- RFC 822 and 8601 -- are handled here: the formats you find in JSON and XML feeds.
// These may return nil. They may also return garbage, given bad input.
NSDate *RSDateWithString(NSString *dateString);
/*If you're using a SAX parser, you have the bytes and don't need to convert to a string first.
It's faster and uses less memory.
(Assumes bytes are UTF-8 or ASCII. If you're using the libxml SAX parser, this will work.)*/
// If you're using a SAX parser, you have the bytes and don't need to convert to a string first.
// It's faster and uses less memory.
// (Assumes bytes are UTF-8 or ASCII. If you're using the libxml SAX parser, this will work.)
NSDate *RSDateWithBytes(const char *bytes, NSUInteger numberOfBytes);

View File

@ -1,6 +1,6 @@
//
// RSDateParser.m
// RSXML
// RSParser
//
// Created by Brent Simmons on 3/25/15.
// Copyright (c) 2015 Ranchero Software, LLC. All rights reserved.

View File

@ -0,0 +1,24 @@
//
// RSParserInternal.h
// RSParser
//
// Created by Brent Simmons on 12/26/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
//
@import Foundation;
NS_ASSUME_NONNULL_BEGIN
BOOL RSParser_IsEmpty(id _Nullable obj);
BOOL RSParserStringIsEmpty(NSString * _Nullable s);
@interface NSDictionary (RSParserInternal)
- (nullable id)rsparser_objectForCaseInsensitiveKey:(NSString *)key;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,60 @@
//
// RSXMLInternal.m
// RSParser
//
// Created by Brent Simmons on 12/26/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
//
#import <CommonCrypto/CommonDigest.h>
#import "RSXMLInternal.h"
static BOOL RSParserIsNil(id obj) {
return obj == nil || obj == [NSNull null];
}
BOOL RSParserObjectIsEmpty(id obj) {
if (RSParserIsNil(obj)) {
return YES;
}
if ([obj respondsToSelector:@selector(count)]) {
return [obj count] < 1;
}
if ([obj respondsToSelector:@selector(length)]) {
return [obj length] < 1;
}
return NO; /*Shouldn't get here very often.*/
}
BOOL RSParserStringIsEmpty(NSString *s) {
return RSParserIsNil(s) || s.length < 1;
}
@implementation NSDictionary (RSParserInternal)
- (nullable id)rsparser_objectForCaseInsensitiveKey:(NSString *)key {
id obj = self[key];
if (obj) {
return obj;
}
for (NSString *oneKey in self.allKeys) {
if ([oneKey isKindOfClass:[NSString class]] && [key caseInsensitiveCompare:oneKey] == NSOrderedSame) {
return self[oneKey];
}
}
return nil;
}
@end

View File

@ -1,31 +0,0 @@
//
// RSXMLInternal.h
// RSXML
//
// Created by Brent Simmons on 12/26/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
//
@import Foundation;
NS_ASSUME_NONNULL_BEGIN
BOOL RSXMLIsEmpty(id _Nullable obj);
BOOL RSXMLStringIsEmpty(NSString * _Nullable s);
@interface NSString (RSXMLInternal)
- (NSString *)rsxml_md5HashString;
@end
@interface NSDictionary (RSXMLInternal)
- (nullable id)rsxml_objectForCaseInsensitiveKey:(NSString *)key;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,83 +0,0 @@
//
// RSXMLInternal.m
// RSXML
//
// Created by Brent Simmons on 12/26/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
//
#import <CommonCrypto/CommonDigest.h>
#import "RSXMLInternal.h"
static BOOL RSXMLIsNil(id obj) {
return obj == nil || obj == [NSNull null];
}
BOOL RSXMLIsEmpty(id obj) {
if (RSXMLIsNil(obj)) {
return YES;
}
if ([obj respondsToSelector:@selector(count)]) {
return [obj count] < 1;
}
if ([obj respondsToSelector:@selector(length)]) {
return [obj length] < 1;
}
return NO; /*Shouldn't get here very often.*/
}
BOOL RSXMLStringIsEmpty(NSString *s) {
return RSXMLIsNil(s) || s.length < 1;
}
@implementation NSString (RSXMLInternal)
- (NSData *)rsxml_md5Hash {
NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
unsigned char hash[CC_MD5_DIGEST_LENGTH];
CC_MD5(data.bytes, (CC_LONG)data.length, hash);
return [NSData dataWithBytes:(const void *)hash length:CC_MD5_DIGEST_LENGTH];
}
- (NSString *)rsxml_md5HashString {
NSData *md5Data = [self rsxml_md5Hash];
const Byte *bytes = md5Data.bytes;
return [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]];
}
@end
@implementation NSDictionary (RSXMLInternal)
- (nullable id)rsxml_objectForCaseInsensitiveKey:(NSString *)key {
id obj = self[key];
if (obj) {
return obj;
}
for (NSString *oneKey in self.allKeys) {
if ([oneKey isKindOfClass:[NSString class]] && [key caseInsensitiveCompare:oneKey] == NSOrderedSame) {
return self[oneKey];
}
}
return nil;
}
@end