// // FeedManager.m // FeedAnimal // // Created by Andrew Pennebaker on 10 Mar 2008. // Copyright 2008 YelloSoft. All rights reserved. // #import "FeedManager.h" @implementation FeedManager // From ThinkMac Software // http://www.thinkmac.co.uk/blog/2005/05/removing-entities-from-html-in-cocoa.html +(NSString*) decodeCharacterEntities: (NSString*) source { if (!source) { return nil; } else if ([source rangeOfString: @"&"].location==NSNotFound) { return source; } else { NSMutableString *escaped=[NSMutableString stringWithString:source]; NSArray *codes=[NSArray arrayWithObjects: @" ", @"¡", @"¢", @"£", @"¤", @"¥", @"¦", @"§", @"¨", @"©", @"ª", @"«", @"¬", @"­", @"®", @"¯", @"°", @"±", @"²", @"³", @"´", @"µ", @"¶", @"·", @"¸", @"¹", @"º", @"»", @"¼", @"½", @"¾", @"¿", @"À", @"Á", @"Â", @"Ã", @"Ä", @"Å", @"Æ", @"Ç", @"È", @"É", @"Ê", @"Ë", @"Ì", @"Í", @"Î", @"Ï", @"Ð", @"Ñ", @"Ò", @"Ó", @"Ô", @"Õ", @"Ö", @"×", @"Ø", @"Ù", @"Ú", @"Û", @"Ü", @"Ý", @"Þ", @"ß", @"à", @"á", @"â", @"ã", @"ä", @"å", @"æ", @"ç", @"è", @"é", @"ê", @"ë", @"ì", @"í", @"î", @"ï", @"ð", @"ñ", @"ò", @"ó", @"ô", @"õ", @"ö", @"÷", @"ø", @"ù", @"ú", @"û", @"ü", @"ý", @"þ", @"ÿ", nil ]; int count=[codes count]; // Html int i; for (i=0; istart.location) { NSRange entityRange=NSMakeRange(start.location, (finish.location-start.location)+1); NSString *entity=[escaped substringWithRange:entityRange]; NSString *value=[entity substringWithRange:NSMakeRange(2, [entity length]-2)]; [escaped deleteCharactersInRange:entityRange]; if ([value hasPrefix:@"x"]) { int tempInt=0; NSScanner *scanner=[NSScanner scannerWithString:[value substringFromIndex:1]]; [scanner scanHexInt:&tempInt]; [escaped insertString:[NSString stringWithFormat:@"%C", tempInt] atIndex:entityRange.location]; } else { [escaped insertString:[NSString stringWithFormat: @"%C", [value intValue]] atIndex: entityRange.location]; } i=start.location; } else { i++; } searchRange=NSMakeRange(i, [escaped length]-i); } return [escaped retain]; // Note this was autoreleased before. } } // From Karelia Software // http://cocoa.karelia.com/Foundation_Categories/NSString/_Flatten__a_string_.m +(NSString*) flattenHTML: (NSString*) text { NSString *result=@""; if (![text isEqualToString:@""]) { // if empty string, don't do this! You get junk. // HACK -- IF SHORT LENGTH, USE MACROMAN -- FOR SOME REASON UNICODE FAILS FOR "" AND "-" AND "CNN" ... int encoding=([text length]>3) ? NSUnicodeStringEncoding:NSMacOSRomanStringEncoding; NSAttributedString *attrString; NSData *theData=[text dataUsingEncoding:encoding]; if (nil!=theData) { // this returned nil once; not sure why; so handle this case. NSDictionary *encodingDict=[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:encoding] forKey:@"CharacterEncoding"]; attrString=[[NSAttributedString alloc] initWithHTML:theData documentAttributes:&encodingDict]; result=[[[attrString string] retain] autorelease]; // keep only this [attrString release]; // don't do autorelease since this is so deep down. } } return result; } +(NSString*) clean: (NSString*) text { return [FeedManager flattenHTML:[FeedManager decodeCharacterEntities:text]]; } -(void) setStories: (NSMutableArray*) a { stories=[a retain]; } -(FeedManager*) init { self=[super init]; [self setMaxItems:10]; [self setStories: [[NSMutableArray arrayWithCapacity:10] retain] ]; return self; } -(void) setMaxItems: (int) max { maxItems=max; } -(int) getMaxItems { return maxItems; } +(BOOL) isRSS: (NSXMLDocument*) xmlDoc { return [[[xmlDoc rootElement] name] isEqualToString:@"rss"]; } +(BOOL) isAtom: (NSXMLDocument*) xmlDoc { return [[[xmlDoc rootElement] name] isEqualToString:@"feed"]; } // From DiggUpdate Controller.m -(NSMutableArray*) loadFeed: (NSString*) url { NSMutableArray *items=[[NSMutableArray alloc] initWithCapacity:10]; NSXMLDocument *xmlDoc=[[NSXMLDocument alloc] initWithContentsOfURL:[NSURL URLWithString:url] options:nil error:nil]; if(xmlDoc!=nil) { if ([FeedManager isRSS:xmlDoc]) { NSArray *xmlItems=[[[[xmlDoc rootElement] elementsForName:@"channel"] objectAtIndex:0] elementsForName:@"item"]; int count=[xmlItems count]; int i; for (i=0; imaxItems) { [stories removeObjectAtIndex:[stories count]-1]; } } -(NSMutableArray*) getStories { return stories; } +(void) visitURL: (NSString*) url { NSString *command=[NSString stringWithFormat:@"open \"%s\"", [url UTF8String]]; system([command UTF8String]); } -(void) markAsRead: (NSString*) link open: (BOOL) shouldOpen { int index=[self getStoryIndexForLink:link]; NSDictionary *story=[stories objectAtIndex:index]; NSString *title=[story objectForKey:@"title"]; NSDictionary *newStory=[[NSDictionary alloc] initWithObjectsAndKeys: [NSNumber numberWithInt:1], @"read", title, @"title", link, @"link", nil ]; [stories replaceObjectAtIndex:index withObject:newStory]; if (shouldOpen) { [FeedManager visitURL:link]; } } @end