Adding String HTML decoding class to iphone app. Also working on paging, but it needs scroll love.

This commit is contained in:
Samuel Clay 2011-07-21 09:56:33 -07:00
parent 27f0cb8ee3
commit 86741fbed4
8 changed files with 3966 additions and 1971 deletions

View file

@ -111,7 +111,9 @@
[appDelegate addActiveFeedStories:[results objectForKey:@"stories"]];
}
NSLog(@"Stories: %d on page %d", [appDelegate.activeFeedStories count], self.feedPage);
[[self storyTitlesTable] reloadData];
// NSArray *indexPaths = [NSArray alloc]
// [self.storyTitlesTable insertRowsAtIndexPaths:indexPaths withRowAnimation:NO];
self.pageFetching = NO;
[results release];
[jsonS release];

351
media/iphone/GTMDefines.h Normal file
View file

@ -0,0 +1,351 @@
//
// GTMDefines.h
//
// Copyright 2008 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
// of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
//
// ============================================================================
#include <AvailabilityMacros.h>
#include <TargetConditionals.h>
#if TARGET_OS_IPHONE
#include <Availability.h>
#endif // TARGET_OS_IPHONE
// Not all MAC_OS_X_VERSION_10_X macros defined in past SDKs
#ifndef MAC_OS_X_VERSION_10_5
#define MAC_OS_X_VERSION_10_5 1050
#endif
#ifndef MAC_OS_X_VERSION_10_6
#define MAC_OS_X_VERSION_10_6 1060
#endif
// Not all __IPHONE_X macros defined in past SDKs
#ifndef __IPHONE_2_1
#define __IPHONE_2_1 20100
#endif
#ifndef __IPHONE_2_2
#define __IPHONE_2_2 20200
#endif
#ifndef __IPHONE_3_0
#define __IPHONE_3_0 30000
#endif
#ifndef __IPHONE_3_1
#define __IPHONE_3_1 30100
#endif
#ifndef __IPHONE_3_2
#define __IPHONE_3_2 30200
#endif
#ifndef __IPHONE_4_0
#define __IPHONE_4_0 40000
#endif
// ----------------------------------------------------------------------------
// CPP symbols that can be overridden in a prefix to control how the toolbox
// is compiled.
// ----------------------------------------------------------------------------
// By setting the GTM_CONTAINERS_VALIDATION_FAILED_LOG and
// GTM_CONTAINERS_VALIDATION_FAILED_ASSERT macros you can control what happens
// when a validation fails. If you implement your own validators, you may want
// to control their internals using the same macros for consistency.
#ifndef GTM_CONTAINERS_VALIDATION_FAILED_ASSERT
#define GTM_CONTAINERS_VALIDATION_FAILED_ASSERT 0
#endif
// Give ourselves a consistent way to do inlines. Apple's macros even use
// a few different actual definitions, so we're based off of the foundation
// one.
#if !defined(GTM_INLINE)
#if defined (__GNUC__) && (__GNUC__ == 4)
#define GTM_INLINE static __inline__ __attribute__((always_inline))
#else
#define GTM_INLINE static __inline__
#endif
#endif
// Give ourselves a consistent way of doing externs that links up nicely
// when mixing objc and objc++
#if !defined (GTM_EXTERN)
#if defined __cplusplus
#define GTM_EXTERN extern "C"
#else
#define GTM_EXTERN extern
#endif
#endif
// Give ourselves a consistent way of exporting things if we have visibility
// set to hidden.
#if !defined (GTM_EXPORT)
#define GTM_EXPORT __attribute__((visibility("default")))
#endif
// _GTMDevLog & _GTMDevAssert
//
// _GTMDevLog & _GTMDevAssert are meant to be a very lightweight shell for
// developer level errors. This implementation simply macros to NSLog/NSAssert.
// It is not intended to be a general logging/reporting system.
//
// Please see http://code.google.com/p/google-toolbox-for-mac/wiki/DevLogNAssert
// for a little more background on the usage of these macros.
//
// _GTMDevLog log some error/problem in debug builds
// _GTMDevAssert assert if conditon isn't met w/in a method/function
// in all builds.
//
// To replace this system, just provide different macro definitions in your
// prefix header. Remember, any implementation you provide *must* be thread
// safe since this could be called by anything in what ever situtation it has
// been placed in.
//
// We only define the simple macros if nothing else has defined this.
#ifndef _GTMDevLog
#ifdef DEBUG
#define _GTMDevLog(...) NSLog(__VA_ARGS__)
#else
#define _GTMDevLog(...) do { } while (0)
#endif
#endif // _GTMDevLog
// Declared here so that it can easily be used for logging tracking if
// necessary. See GTMUnitTestDevLog.h for details.
@class NSString;
GTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...);
#ifndef _GTMDevAssert
// we directly invoke the NSAssert handler so we can pass on the varargs
// (NSAssert doesn't have a macro we can use that takes varargs)
#if !defined(NS_BLOCK_ASSERTIONS)
#define _GTMDevAssert(condition, ...) \
do { \
if (!(condition)) { \
[[NSAssertionHandler currentHandler] \
handleFailureInFunction:[NSString stringWithUTF8String:__PRETTY_FUNCTION__] \
file:[NSString stringWithUTF8String:__FILE__] \
lineNumber:__LINE__ \
description:__VA_ARGS__]; \
} \
} while(0)
#else // !defined(NS_BLOCK_ASSERTIONS)
#define _GTMDevAssert(condition, ...) do { } while (0)
#endif // !defined(NS_BLOCK_ASSERTIONS)
#endif // _GTMDevAssert
// _GTMCompileAssert
// _GTMCompileAssert is an assert that is meant to fire at compile time if you
// want to check things at compile instead of runtime. For example if you
// want to check that a wchar is 4 bytes instead of 2 you would use
// _GTMCompileAssert(sizeof(wchar_t) == 4, wchar_t_is_4_bytes_on_OS_X)
// Note that the second "arg" is not in quotes, and must be a valid processor
// symbol in it's own right (no spaces, punctuation etc).
// Wrapping this in an #ifndef allows external groups to define their own
// compile time assert scheme.
#ifndef _GTMCompileAssert
// We got this technique from here:
// http://unixjunkie.blogspot.com/2007/10/better-compile-time-asserts_29.html
#define _GTMCompileAssertSymbolInner(line, msg) _GTMCOMPILEASSERT ## line ## __ ## msg
#define _GTMCompileAssertSymbol(line, msg) _GTMCompileAssertSymbolInner(line, msg)
#define _GTMCompileAssert(test, msg) \
typedef char _GTMCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ]
#endif // _GTMCompileAssert
// Macro to allow you to create NSStrings out of other macros.
// #define FOO foo
// NSString *fooString = GTM_NSSTRINGIFY(FOO);
#if !defined (GTM_NSSTRINGIFY)
#define GTM_NSSTRINGIFY_INNER(x) @#x
#define GTM_NSSTRINGIFY(x) GTM_NSSTRINGIFY_INNER(x)
#endif
// Macro to allow fast enumeration when building for 10.5 or later, and
// reliance on NSEnumerator for 10.4. Remember, NSDictionary w/ FastEnumeration
// does keys, so pick the right thing, nothing is done on the FastEnumeration
// side to be sure you're getting what you wanted.
#ifndef GTM_FOREACH_OBJECT
#if TARGET_OS_IPHONE || !(MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5)
#define GTM_FOREACH_ENUMEREE(element, enumeration) \
for (element in enumeration)
#define GTM_FOREACH_OBJECT(element, collection) \
for (element in collection)
#define GTM_FOREACH_KEY(element, collection) \
for (element in collection)
#else
#define GTM_FOREACH_ENUMEREE(element, enumeration) \
for (NSEnumerator *_ ## element ## _enum = enumeration; \
(element = [_ ## element ## _enum nextObject]) != nil; )
#define GTM_FOREACH_OBJECT(element, collection) \
GTM_FOREACH_ENUMEREE(element, [collection objectEnumerator])
#define GTM_FOREACH_KEY(element, collection) \
GTM_FOREACH_ENUMEREE(element, [collection keyEnumerator])
#endif
#endif
// ============================================================================
// ----------------------------------------------------------------------------
// CPP symbols defined based on the project settings so the GTM code has
// simple things to test against w/o scattering the knowledge of project
// setting through all the code.
// ----------------------------------------------------------------------------
// Provide a single constant CPP symbol that all of GTM uses for ifdefing
// iPhone code.
#if TARGET_OS_IPHONE // iPhone SDK
// For iPhone specific stuff
#define GTM_IPHONE_SDK 1
#if TARGET_IPHONE_SIMULATOR
#define GTM_IPHONE_SIMULATOR 1
#else
#define GTM_IPHONE_DEVICE 1
#endif // TARGET_IPHONE_SIMULATOR
#else
// For MacOS specific stuff
#define GTM_MACOS_SDK 1
#endif
// Some of our own availability macros
#if GTM_MACOS_SDK
#define GTM_AVAILABLE_ONLY_ON_IPHONE UNAVAILABLE_ATTRIBUTE
#define GTM_AVAILABLE_ONLY_ON_MACOS
#else
#define GTM_AVAILABLE_ONLY_ON_IPHONE
#define GTM_AVAILABLE_ONLY_ON_MACOS UNAVAILABLE_ATTRIBUTE
#endif
// Provide a symbol to include/exclude extra code for GC support. (This mainly
// just controls the inclusion of finalize methods).
#ifndef GTM_SUPPORT_GC
#if GTM_IPHONE_SDK
// iPhone never needs GC
#define GTM_SUPPORT_GC 0
#else
// We can't find a symbol to tell if GC is supported/required, so best we
// do on Mac targets is include it if we're on 10.5 or later.
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
#define GTM_SUPPORT_GC 0
#else
#define GTM_SUPPORT_GC 1
#endif
#endif
#endif
// To simplify support for 64bit (and Leopard in general), we provide the type
// defines for non Leopard SDKs
#if !(MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
// NSInteger/NSUInteger and Max/Mins
#ifndef NSINTEGER_DEFINED
#if __LP64__ || NS_BUILD_32_LIKE_64
typedef long NSInteger;
typedef unsigned long NSUInteger;
#else
typedef int NSInteger;
typedef unsigned int NSUInteger;
#endif
#define NSIntegerMax LONG_MAX
#define NSIntegerMin LONG_MIN
#define NSUIntegerMax ULONG_MAX
#define NSINTEGER_DEFINED 1
#endif // NSINTEGER_DEFINED
// CGFloat
#ifndef CGFLOAT_DEFINED
#if defined(__LP64__) && __LP64__
// This really is an untested path (64bit on Tiger?)
typedef double CGFloat;
#define CGFLOAT_MIN DBL_MIN
#define CGFLOAT_MAX DBL_MAX
#define CGFLOAT_IS_DOUBLE 1
#else /* !defined(__LP64__) || !__LP64__ */
typedef float CGFloat;
#define CGFLOAT_MIN FLT_MIN
#define CGFLOAT_MAX FLT_MAX
#define CGFLOAT_IS_DOUBLE 0
#endif /* !defined(__LP64__) || !__LP64__ */
#define CGFLOAT_DEFINED 1
#endif // CGFLOAT_DEFINED
#endif // MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
// Some support for advanced clang static analysis functionality
// See http://clang-analyzer.llvm.org/annotations.html
#ifndef __has_feature // Optional.
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
#ifndef NS_RETURNS_RETAINED
#if __has_feature(attribute_ns_returns_retained)
#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
#else
#define NS_RETURNS_RETAINED
#endif
#endif
#ifndef NS_RETURNS_NOT_RETAINED
#if __has_feature(attribute_ns_returns_not_retained)
#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
#else
#define NS_RETURNS_NOT_RETAINED
#endif
#endif
#ifndef CF_RETURNS_RETAINED
#if __has_feature(attribute_cf_returns_retained)
#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
#else
#define CF_RETURNS_RETAINED
#endif
#endif
#ifndef CF_RETURNS_NOT_RETAINED
#if __has_feature(attribute_cf_returns_not_retained)
#define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained))
#else
#define CF_RETURNS_NOT_RETAINED
#endif
#endif
// Defined on 10.6 and above.
#ifndef NS_FORMAT_ARGUMENT
#define NS_FORMAT_ARGUMENT(A)
#endif
// Defined on 10.6 and above.
#ifndef NS_FORMAT_FUNCTION
#define NS_FORMAT_FUNCTION(F,A)
#endif
#ifndef GTM_NONNULL
#define GTM_NONNULL(x) __attribute__((nonnull(x)))
#endif
// To simplify support for both Leopard and Snow Leopard we declare
// the Snow Leopard protocols that we need here.
#if !defined(GTM_10_6_PROTOCOLS_DEFINED) && !(MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
#define GTM_10_6_PROTOCOLS_DEFINED 1
@protocol NSConnectionDelegate
@end
@protocol NSAnimationDelegate
@end
@protocol NSImageDelegate
@end
@protocol NSTabViewDelegate
@end
#endif // !defined(GTM_10_6_PROTOCOLS_DEFINED) && !(MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)

View file

@ -0,0 +1,66 @@
//
// GTMNSString+HTML.h
// Dealing with NSStrings that contain HTML
//
// Copyright 2006-2008 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
// of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
//
#import <Foundation/Foundation.h>
/// Utilities for NSStrings containing HTML
@interface NSString (GTMNSStringHTMLAdditions)
/// Get a string where internal characters that need escaping for HTML are escaped
//
/// For example, '&' become '&amp;'. This will only cover characters from table
/// A.2.2 of http://www.w3.org/TR/xhtml1/dtds.html#a_dtd_Special_characters
/// which is what you want for a unicode encoded webpage. If you have a ascii
/// or non-encoded webpage, please use stringByEscapingAsciiHTML which will
/// encode all characters.
///
/// For obvious reasons this call is only safe once.
//
// Returns:
// Autoreleased NSString
//
- (NSString *)gtm_stringByEscapingForHTML;
/// Get a string where internal characters that need escaping for HTML are escaped
//
/// For example, '&' become '&amp;'
/// All non-mapped characters (unicode that don't have a &keyword; mapping)
/// will be converted to the appropriate &#xxx; value. If your webpage is
/// unicode encoded (UTF16 or UTF8) use stringByEscapingHTML instead as it is
/// faster, and produces less bloated and more readable HTML (as long as you
/// are using a unicode compliant HTML reader).
///
/// For obvious reasons this call is only safe once.
//
// Returns:
// Autoreleased NSString
//
- (NSString *)gtm_stringByEscapingForAsciiHTML;
/// Get a string where internal characters that are escaped for HTML are unescaped
//
/// For example, '&amp;' becomes '&'
/// Handles &#32; and &#x32; cases as well
///
// Returns:
// Autoreleased NSString
//
- (NSString *)gtm_stringByUnescapingFromHTML;
@end

View file

@ -0,0 +1,522 @@
//
// GTMNSString+HTML.m
// Dealing with NSStrings that contain HTML
//
// Copyright 2006-2008 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
// of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
//
#import "GTMDefines.h"
#import "GTMNString+HTML.h"
typedef struct {
NSString *escapeSequence;
unichar uchar;
} HTMLEscapeMap;
// Taken from http://www.w3.org/TR/xhtml1/dtds.html#a_dtd_Special_characters
// Ordered by uchar lowest to highest for bsearching
static HTMLEscapeMap gAsciiHTMLEscapeMap[] = {
// A.2.2. Special characters
{ @"&quot;", 34 },
{ @"&amp;", 38 },
{ @"&apos;", 39 },
{ @"&lt;", 60 },
{ @"&gt;", 62 },
// A.2.1. Latin-1 characters
{ @"&nbsp;", 160 },
{ @"&iexcl;", 161 },
{ @"&cent;", 162 },
{ @"&pound;", 163 },
{ @"&curren;", 164 },
{ @"&yen;", 165 },
{ @"&brvbar;", 166 },
{ @"&sect;", 167 },
{ @"&uml;", 168 },
{ @"&copy;", 169 },
{ @"&ordf;", 170 },
{ @"&laquo;", 171 },
{ @"&not;", 172 },
{ @"&shy;", 173 },
{ @"&reg;", 174 },
{ @"&macr;", 175 },
{ @"&deg;", 176 },
{ @"&plusmn;", 177 },
{ @"&sup2;", 178 },
{ @"&sup3;", 179 },
{ @"&acute;", 180 },
{ @"&micro;", 181 },
{ @"&para;", 182 },
{ @"&middot;", 183 },
{ @"&cedil;", 184 },
{ @"&sup1;", 185 },
{ @"&ordm;", 186 },
{ @"&raquo;", 187 },
{ @"&frac14;", 188 },
{ @"&frac12;", 189 },
{ @"&frac34;", 190 },
{ @"&iquest;", 191 },
{ @"&Agrave;", 192 },
{ @"&Aacute;", 193 },
{ @"&Acirc;", 194 },
{ @"&Atilde;", 195 },
{ @"&Auml;", 196 },
{ @"&Aring;", 197 },
{ @"&AElig;", 198 },
{ @"&Ccedil;", 199 },
{ @"&Egrave;", 200 },
{ @"&Eacute;", 201 },
{ @"&Ecirc;", 202 },
{ @"&Euml;", 203 },
{ @"&Igrave;", 204 },
{ @"&Iacute;", 205 },
{ @"&Icirc;", 206 },
{ @"&Iuml;", 207 },
{ @"&ETH;", 208 },
{ @"&Ntilde;", 209 },
{ @"&Ograve;", 210 },
{ @"&Oacute;", 211 },
{ @"&Ocirc;", 212 },
{ @"&Otilde;", 213 },
{ @"&Ouml;", 214 },
{ @"&times;", 215 },
{ @"&Oslash;", 216 },
{ @"&Ugrave;", 217 },
{ @"&Uacute;", 218 },
{ @"&Ucirc;", 219 },
{ @"&Uuml;", 220 },
{ @"&Yacute;", 221 },
{ @"&THORN;", 222 },
{ @"&szlig;", 223 },
{ @"&agrave;", 224 },
{ @"&aacute;", 225 },
{ @"&acirc;", 226 },
{ @"&atilde;", 227 },
{ @"&auml;", 228 },
{ @"&aring;", 229 },
{ @"&aelig;", 230 },
{ @"&ccedil;", 231 },
{ @"&egrave;", 232 },
{ @"&eacute;", 233 },
{ @"&ecirc;", 234 },
{ @"&euml;", 235 },
{ @"&igrave;", 236 },
{ @"&iacute;", 237 },
{ @"&icirc;", 238 },
{ @"&iuml;", 239 },
{ @"&eth;", 240 },
{ @"&ntilde;", 241 },
{ @"&ograve;", 242 },
{ @"&oacute;", 243 },
{ @"&ocirc;", 244 },
{ @"&otilde;", 245 },
{ @"&ouml;", 246 },
{ @"&divide;", 247 },
{ @"&oslash;", 248 },
{ @"&ugrave;", 249 },
{ @"&uacute;", 250 },
{ @"&ucirc;", 251 },
{ @"&uuml;", 252 },
{ @"&yacute;", 253 },
{ @"&thorn;", 254 },
{ @"&yuml;", 255 },
// A.2.2. Special characters cont'd
{ @"&OElig;", 338 },
{ @"&oelig;", 339 },
{ @"&Scaron;", 352 },
{ @"&scaron;", 353 },
{ @"&Yuml;", 376 },
// A.2.3. Symbols
{ @"&fnof;", 402 },
// A.2.2. Special characters cont'd
{ @"&circ;", 710 },
{ @"&tilde;", 732 },
// A.2.3. Symbols cont'd
{ @"&Alpha;", 913 },
{ @"&Beta;", 914 },
{ @"&Gamma;", 915 },
{ @"&Delta;", 916 },
{ @"&Epsilon;", 917 },
{ @"&Zeta;", 918 },
{ @"&Eta;", 919 },
{ @"&Theta;", 920 },
{ @"&Iota;", 921 },
{ @"&Kappa;", 922 },
{ @"&Lambda;", 923 },
{ @"&Mu;", 924 },
{ @"&Nu;", 925 },
{ @"&Xi;", 926 },
{ @"&Omicron;", 927 },
{ @"&Pi;", 928 },
{ @"&Rho;", 929 },
{ @"&Sigma;", 931 },
{ @"&Tau;", 932 },
{ @"&Upsilon;", 933 },
{ @"&Phi;", 934 },
{ @"&Chi;", 935 },
{ @"&Psi;", 936 },
{ @"&Omega;", 937 },
{ @"&alpha;", 945 },
{ @"&beta;", 946 },
{ @"&gamma;", 947 },
{ @"&delta;", 948 },
{ @"&epsilon;", 949 },
{ @"&zeta;", 950 },
{ @"&eta;", 951 },
{ @"&theta;", 952 },
{ @"&iota;", 953 },
{ @"&kappa;", 954 },
{ @"&lambda;", 955 },
{ @"&mu;", 956 },
{ @"&nu;", 957 },
{ @"&xi;", 958 },
{ @"&omicron;", 959 },
{ @"&pi;", 960 },
{ @"&rho;", 961 },
{ @"&sigmaf;", 962 },
{ @"&sigma;", 963 },
{ @"&tau;", 964 },
{ @"&upsilon;", 965 },
{ @"&phi;", 966 },
{ @"&chi;", 967 },
{ @"&psi;", 968 },
{ @"&omega;", 969 },
{ @"&thetasym;", 977 },
{ @"&upsih;", 978 },
{ @"&piv;", 982 },
// A.2.2. Special characters cont'd
{ @"&ensp;", 8194 },
{ @"&emsp;", 8195 },
{ @"&thinsp;", 8201 },
{ @"&zwnj;", 8204 },
{ @"&zwj;", 8205 },
{ @"&lrm;", 8206 },
{ @"&rlm;", 8207 },
{ @"&ndash;", 8211 },
{ @"&mdash;", 8212 },
{ @"&lsquo;", 8216 },
{ @"&rsquo;", 8217 },
{ @"&sbquo;", 8218 },
{ @"&ldquo;", 8220 },
{ @"&rdquo;", 8221 },
{ @"&bdquo;", 8222 },
{ @"&dagger;", 8224 },
{ @"&Dagger;", 8225 },
// A.2.3. Symbols cont'd
{ @"&bull;", 8226 },
{ @"&hellip;", 8230 },
// A.2.2. Special characters cont'd
{ @"&permil;", 8240 },
// A.2.3. Symbols cont'd
{ @"&prime;", 8242 },
{ @"&Prime;", 8243 },
// A.2.2. Special characters cont'd
{ @"&lsaquo;", 8249 },
{ @"&rsaquo;", 8250 },
// A.2.3. Symbols cont'd
{ @"&oline;", 8254 },
{ @"&frasl;", 8260 },
// A.2.2. Special characters cont'd
{ @"&euro;", 8364 },
// A.2.3. Symbols cont'd
{ @"&image;", 8465 },
{ @"&weierp;", 8472 },
{ @"&real;", 8476 },
{ @"&trade;", 8482 },
{ @"&alefsym;", 8501 },
{ @"&larr;", 8592 },
{ @"&uarr;", 8593 },
{ @"&rarr;", 8594 },
{ @"&darr;", 8595 },
{ @"&harr;", 8596 },
{ @"&crarr;", 8629 },
{ @"&lArr;", 8656 },
{ @"&uArr;", 8657 },
{ @"&rArr;", 8658 },
{ @"&dArr;", 8659 },
{ @"&hArr;", 8660 },
{ @"&forall;", 8704 },
{ @"&part;", 8706 },
{ @"&exist;", 8707 },
{ @"&empty;", 8709 },
{ @"&nabla;", 8711 },
{ @"&isin;", 8712 },
{ @"&notin;", 8713 },
{ @"&ni;", 8715 },
{ @"&prod;", 8719 },
{ @"&sum;", 8721 },
{ @"&minus;", 8722 },
{ @"&lowast;", 8727 },
{ @"&radic;", 8730 },
{ @"&prop;", 8733 },
{ @"&infin;", 8734 },
{ @"&ang;", 8736 },
{ @"&and;", 8743 },
{ @"&or;", 8744 },
{ @"&cap;", 8745 },
{ @"&cup;", 8746 },
{ @"&int;", 8747 },
{ @"&there4;", 8756 },
{ @"&sim;", 8764 },
{ @"&cong;", 8773 },
{ @"&asymp;", 8776 },
{ @"&ne;", 8800 },
{ @"&equiv;", 8801 },
{ @"&le;", 8804 },
{ @"&ge;", 8805 },
{ @"&sub;", 8834 },
{ @"&sup;", 8835 },
{ @"&nsub;", 8836 },
{ @"&sube;", 8838 },
{ @"&supe;", 8839 },
{ @"&oplus;", 8853 },
{ @"&otimes;", 8855 },
{ @"&perp;", 8869 },
{ @"&sdot;", 8901 },
{ @"&lceil;", 8968 },
{ @"&rceil;", 8969 },
{ @"&lfloor;", 8970 },
{ @"&rfloor;", 8971 },
{ @"&lang;", 9001 },
{ @"&rang;", 9002 },
{ @"&loz;", 9674 },
{ @"&spades;", 9824 },
{ @"&clubs;", 9827 },
{ @"&hearts;", 9829 },
{ @"&diams;", 9830 }
};
// Taken from http://www.w3.org/TR/xhtml1/dtds.html#a_dtd_Special_characters
// This is table A.2.2 Special Characters
static HTMLEscapeMap gUnicodeHTMLEscapeMap[] = {
// C0 Controls and Basic Latin
{ @"&quot;", 34 },
{ @"&amp;", 38 },
{ @"&apos;", 39 },
{ @"&lt;", 60 },
{ @"&gt;", 62 },
// Latin Extended-A
{ @"&OElig;", 338 },
{ @"&oelig;", 339 },
{ @"&Scaron;", 352 },
{ @"&scaron;", 353 },
{ @"&Yuml;", 376 },
// Spacing Modifier Letters
{ @"&circ;", 710 },
{ @"&tilde;", 732 },
// General Punctuation
{ @"&ensp;", 8194 },
{ @"&emsp;", 8195 },
{ @"&thinsp;", 8201 },
{ @"&zwnj;", 8204 },
{ @"&zwj;", 8205 },
{ @"&lrm;", 8206 },
{ @"&rlm;", 8207 },
{ @"&ndash;", 8211 },
{ @"&mdash;", 8212 },
{ @"&lsquo;", 8216 },
{ @"&rsquo;", 8217 },
{ @"&sbquo;", 8218 },
{ @"&ldquo;", 8220 },
{ @"&rdquo;", 8221 },
{ @"&bdquo;", 8222 },
{ @"&dagger;", 8224 },
{ @"&Dagger;", 8225 },
{ @"&permil;", 8240 },
{ @"&lsaquo;", 8249 },
{ @"&rsaquo;", 8250 },
{ @"&euro;", 8364 },
};
// Utility function for Bsearching table above
static int EscapeMapCompare(const void *ucharVoid, const void *mapVoid) {
const unichar *uchar = (const unichar*)ucharVoid;
const HTMLEscapeMap *map = (const HTMLEscapeMap*)mapVoid;
int val;
if (*uchar > map->uchar) {
val = 1;
} else if (*uchar < map->uchar) {
val = -1;
} else {
val = 0;
}
return val;
}
@implementation NSString (GTMNSStringHTMLAdditions)
- (NSString *)gtm_stringByEscapingHTMLUsingTable:(HTMLEscapeMap*)table
ofSize:(NSUInteger)size
escapingUnicode:(BOOL)escapeUnicode {
NSUInteger length = [self length];
if (!length) {
return self;
}
NSMutableString *finalString = [NSMutableString string];
NSMutableData *data2 = [NSMutableData dataWithCapacity:sizeof(unichar) * length];
// this block is common between GTMNSString+HTML and GTMNSString+XML but
// it's so short that it isn't really worth trying to share.
const unichar *buffer = CFStringGetCharactersPtr((CFStringRef)self);
if (!buffer) {
// We want this buffer to be autoreleased.
NSMutableData *data = [NSMutableData dataWithLength:length * sizeof(UniChar)];
if (!data) {
// COV_NF_START - Memory fail case
_GTMDevLog(@"couldn't alloc buffer");
return nil;
// COV_NF_END
}
[self getCharacters:[data mutableBytes]];
buffer = [data bytes];
}
if (!buffer || !data2) {
// COV_NF_START
_GTMDevLog(@"Unable to allocate buffer or data2");
return nil;
// COV_NF_END
}
unichar *buffer2 = (unichar *)[data2 mutableBytes];
NSUInteger buffer2Length = 0;
for (NSUInteger i = 0; i < length; ++i) {
HTMLEscapeMap *val = bsearch(&buffer[i], table,
size / sizeof(HTMLEscapeMap),
sizeof(HTMLEscapeMap), EscapeMapCompare);
if (val || (escapeUnicode && buffer[i] > 127)) {
if (buffer2Length) {
CFStringAppendCharacters((CFMutableStringRef)finalString,
buffer2,
buffer2Length);
buffer2Length = 0;
}
if (val) {
[finalString appendString:val->escapeSequence];
}
else {
_GTMDevAssert(escapeUnicode && buffer[i] > 127, @"Illegal Character");
[finalString appendFormat:@"&#%d;", buffer[i]];
}
} else {
buffer2[buffer2Length] = buffer[i];
buffer2Length += 1;
}
}
if (buffer2Length) {
CFStringAppendCharacters((CFMutableStringRef)finalString,
buffer2,
buffer2Length);
}
return finalString;
}
- (NSString *)gtm_stringByEscapingForHTML {
return [self gtm_stringByEscapingHTMLUsingTable:gUnicodeHTMLEscapeMap
ofSize:sizeof(gUnicodeHTMLEscapeMap)
escapingUnicode:NO];
} // gtm_stringByEscapingHTML
- (NSString *)gtm_stringByEscapingForAsciiHTML {
return [self gtm_stringByEscapingHTMLUsingTable:gAsciiHTMLEscapeMap
ofSize:sizeof(gAsciiHTMLEscapeMap)
escapingUnicode:YES];
} // gtm_stringByEscapingAsciiHTML
- (NSString *)gtm_stringByUnescapingFromHTML {
NSRange range = NSMakeRange(0, [self length]);
NSRange subrange = [self rangeOfString:@"&" options:NSBackwardsSearch range:range];
// if no ampersands, we've got a quick way out
if (subrange.length == 0) return self;
NSMutableString *finalString = [NSMutableString stringWithString:self];
do {
NSRange semiColonRange = NSMakeRange(subrange.location, NSMaxRange(range) - subrange.location);
semiColonRange = [self rangeOfString:@";" options:0 range:semiColonRange];
range = NSMakeRange(0, subrange.location);
// if we don't find a semicolon in the range, we don't have a sequence
if (semiColonRange.location == NSNotFound) {
continue;
}
NSRange escapeRange = NSMakeRange(subrange.location, semiColonRange.location - subrange.location + 1);
NSString *escapeString = [self substringWithRange:escapeRange];
NSUInteger length = [escapeString length];
// a squence must be longer than 3 (&lt;) and less than 11 (&thetasym;)
if (length > 3 && length < 11) {
if ([escapeString characterAtIndex:1] == '#') {
unichar char2 = [escapeString characterAtIndex:2];
if (char2 == 'x' || char2 == 'X') {
// Hex escape squences &#xa3;
NSString *hexSequence = [escapeString substringWithRange:NSMakeRange(3, length - 4)];
NSScanner *scanner = [NSScanner scannerWithString:hexSequence];
unsigned value;
if ([scanner scanHexInt:&value] &&
value < USHRT_MAX &&
value > 0
&& [scanner scanLocation] == length - 4) {
unichar uchar = value;
NSString *charString = [NSString stringWithCharacters:&uchar length:1];
[finalString replaceCharactersInRange:escapeRange withString:charString];
}
} else {
// Decimal Sequences &#123;
NSString *numberSequence = [escapeString substringWithRange:NSMakeRange(2, length - 3)];
NSScanner *scanner = [NSScanner scannerWithString:numberSequence];
int value;
if ([scanner scanInt:&value] &&
value < USHRT_MAX &&
value > 0
&& [scanner scanLocation] == length - 3) {
unichar uchar = value;
NSString *charString = [NSString stringWithCharacters:&uchar length:1];
[finalString replaceCharactersInRange:escapeRange withString:charString];
}
}
} else {
// "standard" sequences
for (unsigned i = 0; i < sizeof(gAsciiHTMLEscapeMap) / sizeof(HTMLEscapeMap); ++i) {
if ([escapeString isEqualToString:gAsciiHTMLEscapeMap[i].escapeSequence]) {
[finalString replaceCharactersInRange:escapeRange withString:[NSString stringWithCharacters:&gAsciiHTMLEscapeMap[i].uchar length:1]];
break;
}
}
}
}
} while ((subrange = [self rangeOfString:@"&" options:NSBackwardsSearch range:range]).length != 0);
return finalString;
} // gtm_stringByUnescapingHTML
@end

View file

@ -0,0 +1,46 @@
//
// NSString+HTML.h
// MWFeedParser
//
// Copyright (c) 2010 Michael Waterfall
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// 1. The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// 2. This Software cannot be used to archive or collect data such as (but not
// limited to) that of events, news, experiences and activities, for the
// purpose of any concept relating to diary/journal keeping.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import <Foundation/Foundation.h>
// Dependant upon GTMNSString+HTML
@interface NSString (HTML)
// Instance Methods
- (NSString *)stringByConvertingHTMLToPlainText;
- (NSString *)stringByDecodingHTMLEntities;
- (NSString *)stringByEncodingHTMLEntities;
- (NSString *)stringWithNewLinesAsBRs;
- (NSString *)stringByRemovingNewLinesAndWhitespace;
// DEPRECIATED - Please use NSString stringByConvertingHTMLToPlainText
- (NSString *)stringByStrippingTags;
@end

View file

@ -0,0 +1,336 @@
//
// NSString+HTML.m
// MWFeedParser
//
// Copyright (c) 2010 Michael Waterfall
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// 1. The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// 2. This Software cannot be used to archive or collect data such as (but not
// limited to) that of events, news, experiences and activities, for the
// purpose of any concept relating to diary/journal keeping.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import "NSString+HTML.h"
#import "GTMNString+HTML.h"
@implementation NSString (HTML)
#pragma mark -
#pragma mark Class Methods
#pragma mark -
#pragma mark Instance Methods
// Strip HTML tags
- (NSString *)stringByConvertingHTMLToPlainText {
// Pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Character sets
NSCharacterSet *stopCharacters = [NSCharacterSet characterSetWithCharactersInString:[NSString stringWithFormat:@"< \t\n\r%C%C%C%C", 0x0085, 0x000C, 0x2028, 0x2029]];
NSCharacterSet *newLineAndWhitespaceCharacters = [NSCharacterSet characterSetWithCharactersInString:[NSString stringWithFormat:@" \t\n\r%C%C%C%C", 0x0085, 0x000C, 0x2028, 0x2029]];
NSCharacterSet *tagNameCharacters = [NSCharacterSet characterSetWithCharactersInString:@"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"]; /**/
// Scan and find all tags
NSMutableString *result = [[NSMutableString alloc] initWithCapacity:self.length];
NSScanner *scanner = [[NSScanner alloc] initWithString:self];
[scanner setCharactersToBeSkipped:nil];
[scanner setCaseSensitive:YES];
NSString *str = nil, *tagName = nil;
BOOL dontReplaceTagWithSpace = NO;
do {
// Scan up to the start of a tag or whitespace
if ([scanner scanUpToCharactersFromSet:stopCharacters intoString:&str]) {
[result appendString:str];
str = nil; // reset
}
// Check if we've stopped at a tag/comment or whitespace
if ([scanner scanString:@"<" intoString:NULL]) {
// Stopped at a comment or tag
if ([scanner scanString:@"!--" intoString:NULL]) {
// Comment
[scanner scanUpToString:@"-->" intoString:NULL];
[scanner scanString:@"-->" intoString:NULL];
} else {
// Tag - remove and replace with space unless it's
// a closing inline tag then dont replace with a space
if ([scanner scanString:@"/" intoString:NULL]) {
// Closing tag - replace with space unless it's inline
tagName = nil; dontReplaceTagWithSpace = NO;
if ([scanner scanCharactersFromSet:tagNameCharacters intoString:&tagName]) {
tagName = [tagName lowercaseString];
dontReplaceTagWithSpace = ([tagName isEqualToString:@"a"] ||
[tagName isEqualToString:@"b"] ||
[tagName isEqualToString:@"i"] ||
[tagName isEqualToString:@"q"] ||
[tagName isEqualToString:@"span"] ||
[tagName isEqualToString:@"em"] ||
[tagName isEqualToString:@"strong"] ||
[tagName isEqualToString:@"cite"] ||
[tagName isEqualToString:@"abbr"] ||
[tagName isEqualToString:@"acronym"] ||
[tagName isEqualToString:@"label"]);
}
// Replace tag with string unless it was an inline
if (!dontReplaceTagWithSpace && result.length > 0 && ![scanner isAtEnd]) [result appendString:@" "];
}
// Scan past tag
[scanner scanUpToString:@">" intoString:NULL];
[scanner scanString:@">" intoString:NULL];
}
} else {
// Stopped at whitespace - replace all whitespace and newlines with a space
if ([scanner scanCharactersFromSet:newLineAndWhitespaceCharacters intoString:NULL]) {
if (result.length > 0 && ![scanner isAtEnd]) [result appendString:@" "]; // Dont append space to beginning or end of result
}
}
} while (![scanner isAtEnd]);
// Cleanup
[scanner release];
// Decode HTML entities and return
NSString *retString = [[result stringByDecodingHTMLEntities] retain];
[result release];
// Drain
[pool drain];
// Return
return [retString autorelease];
}
// Decode all HTML entities using GTM
- (NSString *)stringByDecodingHTMLEntities {
// gtm_stringByUnescapingFromHTML can return self so create new string ;)
return [NSString stringWithString:[self gtm_stringByUnescapingFromHTML]];
}
// Encode all HTML entities using GTM
- (NSString *)stringByEncodingHTMLEntities {
// gtm_stringByUnescapingFromHTML can return self so create new string ;)
return [NSString stringWithString:[self gtm_stringByEscapingForAsciiHTML]];
}
// Replace newlines with <br /> tags
- (NSString *)stringWithNewLinesAsBRs {
// Pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Strange New lines:
// Next Line, U+0085
// Form Feed, U+000C
// Line Separator, U+2028
// Paragraph Separator, U+2029
// Scanner
NSScanner *scanner = [[NSScanner alloc] initWithString:self];
[scanner setCharactersToBeSkipped:nil];
NSMutableString *result = [[NSMutableString alloc] init];
NSString *temp;
NSCharacterSet *newLineCharacters = [NSCharacterSet characterSetWithCharactersInString:
[NSString stringWithFormat:@"\n\r%C%C%C%C", 0x0085, 0x000C, 0x2028, 0x2029]];
// Scan
do {
// Get non new line characters
temp = nil;
[scanner scanUpToCharactersFromSet:newLineCharacters intoString:&temp];
if (temp) [result appendString:temp];
temp = nil;
// Add <br /> s
if ([scanner scanString:@"\r\n" intoString:nil]) {
// Combine \r\n into just 1 <br />
[result appendString:@"<br />"];
} else if ([scanner scanCharactersFromSet:newLineCharacters intoString:&temp]) {
// Scan other new line characters and add <br /> s
if (temp) {
for (int i = 0; i < temp.length; i++) {
[result appendString:@"<br />"];
}
}
}
} while (![scanner isAtEnd]);
// Cleanup & return
[scanner release];
NSString *retString = [[NSString stringWithString:result] retain];
[result release];
// Drain
[pool drain];
// Return
return [retString autorelease];
}
// Remove newlines and white space from strong
- (NSString *)stringByRemovingNewLinesAndWhitespace {
// Pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Strange New lines:
// Next Line, U+0085
// Form Feed, U+000C
// Line Separator, U+2028
// Paragraph Separator, U+2029
// Scanner
NSScanner *scanner = [[NSScanner alloc] initWithString:self];
[scanner setCharactersToBeSkipped:nil];
NSMutableString *result = [[NSMutableString alloc] init];
NSString *temp;
NSCharacterSet *newLineAndWhitespaceCharacters = [NSCharacterSet characterSetWithCharactersInString:
[NSString stringWithFormat:@" \t\n\r%C%C%C%C", 0x0085, 0x000C, 0x2028, 0x2029]];
// Scan
while (![scanner isAtEnd]) {
// Get non new line or whitespace characters
temp = nil;
[scanner scanUpToCharactersFromSet:newLineAndWhitespaceCharacters intoString:&temp];
if (temp) [result appendString:temp];
// Replace with a space
if ([scanner scanCharactersFromSet:newLineAndWhitespaceCharacters intoString:NULL]) {
if (result.length > 0 && ![scanner isAtEnd]) // Dont append space to beginning or end of result
[result appendString:@" "];
}
}
// Cleanup
[scanner release];
// Return
NSString *retString = [[NSString stringWithString:result] retain];
[result release];
// Drain
[pool drain];
// Return
return [retString autorelease];
}
// Strip HTML tags
// DEPRECIATED - Please use NSString stringByConvertingHTMLToPlainText
- (NSString *)stringByStrippingTags {
// Pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Find first & and short-cut if we can
NSUInteger ampIndex = [self rangeOfString:@"<" options:NSLiteralSearch].location;
if (ampIndex == NSNotFound) {
return [NSString stringWithString:self]; // return copy of string as no tags found
}
// Scan and find all tags
NSScanner *scanner = [NSScanner scannerWithString:self];
[scanner setCharactersToBeSkipped:nil];
NSMutableSet *tags = [[NSMutableSet alloc] init];
NSString *tag;
do {
// Scan up to <
tag = nil;
[scanner scanUpToString:@"<" intoString:NULL];
[scanner scanUpToString:@">" intoString:&tag];
// Add to set
if (tag) {
NSString *t = [[NSString alloc] initWithFormat:@"%@>", tag];
[tags addObject:t];
[t release];
}
} while (![scanner isAtEnd]);
// Strings
NSMutableString *result = [[NSMutableString alloc] initWithString:self];
NSString *finalString;
// Replace tags
NSString *replacement;
for (NSString *t in tags) {
// Replace tag with space unless it's an inline element
replacement = @" ";
if ([t isEqualToString:@"<a>"] ||
[t isEqualToString:@"</a>"] ||
[t isEqualToString:@"<span>"] ||
[t isEqualToString:@"</span>"] ||
[t isEqualToString:@"<strong>"] ||
[t isEqualToString:@"</strong>"] ||
[t isEqualToString:@"<em>"] ||
[t isEqualToString:@"</em>"]) {
replacement = @"";
}
// Replace
[result replaceOccurrencesOfString:t
withString:replacement
options:NSLiteralSearch
range:NSMakeRange(0, result.length)];
}
// Remove multi-spaces and line breaks
finalString = [[result stringByRemovingNewLinesAndWhitespace] retain];
// Cleanup
[result release];
[tags release];
// Drain
[pool drain];
// Return
return [finalString autorelease];
}
@end

View file

@ -48,6 +48,8 @@
78FC34FA11CA94900055C312 /* SBJsonBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 78FC34F211CA94900055C312 /* SBJsonBase.m */; };
78FC34FB11CA94900055C312 /* SBJsonParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 78FC34F411CA94900055C312 /* SBJsonParser.m */; };
78FC34FC11CA94900055C312 /* SBJsonWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 78FC34F611CA94900055C312 /* SBJsonWriter.m */; };
FF38679B13D88EEC00F8AB3A /* NSString+HTML.m in Sources */ = {isa = PBXBuildFile; fileRef = FF38679A13D88EEC00F8AB3A /* NSString+HTML.m */; };
FF38679E13D8914A00F8AB3A /* GTMNString+HTML.m in Sources */ = {isa = PBXBuildFile; fileRef = FF38679D13D8914A00F8AB3A /* GTMNString+HTML.m */; };
FFCE7AE813D49165009A98F6 /* FeedTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = FFCE7AE613D49165009A98F6 /* FeedTableCell.m */; };
FFCE7AE913D49165009A98F6 /* FeedTableCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = FFCE7AE713D49165009A98F6 /* FeedTableCell.xib */; };
/* End PBXBuildFile section */
@ -122,6 +124,11 @@
78FC34F511CA94900055C312 /* SBJsonWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonWriter.h; sourceTree = "<group>"; };
78FC34F611CA94900055C312 /* SBJsonWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonWriter.m; sourceTree = "<group>"; };
8D1107310486CEB800E47090 /* NewsBlur-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "NewsBlur-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = "<group>"; };
FF38679913D88EEC00F8AB3A /* NSString+HTML.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+HTML.h"; sourceTree = "<group>"; };
FF38679A13D88EEC00F8AB3A /* NSString+HTML.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+HTML.m"; sourceTree = "<group>"; };
FF38679C13D8914A00F8AB3A /* GTMNString+HTML.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GTMNString+HTML.h"; sourceTree = "<group>"; };
FF38679D13D8914A00F8AB3A /* GTMNString+HTML.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNString+HTML.m"; sourceTree = "<group>"; };
FF38679F13D8916E00F8AB3A /* GTMDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMDefines.h; sourceTree = "<group>"; };
FFCE7AE513D49165009A98F6 /* FeedTableCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FeedTableCell.h; path = ../NewsBlur.xcodeproj/FeedTableCell.h; sourceTree = "<group>"; };
FFCE7AE613D49165009A98F6 /* FeedTableCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FeedTableCell.m; path = ../NewsBlur.xcodeproj/FeedTableCell.m; sourceTree = "<group>"; };
FFCE7AE713D49165009A98F6 /* FeedTableCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = FeedTableCell.xib; path = ../NewsBlur.xcodeproj/FeedTableCell.xib; sourceTree = "<group>"; };
@ -202,6 +209,11 @@
children = (
32CA4F630368D1EE00C91783 /* NewsBlur_Prefix.pch */,
29B97316FDCFA39411CA2CEA /* main.m */,
FF38679913D88EEC00F8AB3A /* NSString+HTML.h */,
FF38679C13D8914A00F8AB3A /* GTMNString+HTML.h */,
FF38679F13D8916E00F8AB3A /* GTMDefines.h */,
FF38679D13D8914A00F8AB3A /* GTMNString+HTML.m */,
FF38679A13D88EEC00F8AB3A /* NSString+HTML.m */,
);
name = "Other Sources";
sourceTree = "<group>";
@ -387,6 +399,8 @@
78095E3D128EF32200230C8E /* Reachability.m in Sources */,
78095EC9128F30B500230C8E /* OriginalStoryViewController.m in Sources */,
FFCE7AE813D49165009A98F6 /* FeedTableCell.m in Sources */,
FF38679B13D88EEC00F8AB3A /* NSString+HTML.m in Sources */,
FF38679E13D8914A00F8AB3A /* GTMNString+HTML.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};