Skip to content

Commit

Permalink
Merge branch 'master' of github.com:Cocoanetics/NSAttributedString-Ad…
Browse files Browse the repository at this point in the history
…ditions-for-HTML
  • Loading branch information
odrobnik committed Jul 9, 2011
2 parents d1e2b3e + 7a5b27c commit ccba654
Show file tree
Hide file tree
Showing 12 changed files with 159 additions and 124 deletions.
7 changes: 6 additions & 1 deletion Classes/DTCoreTextFontCollection.m
Expand Up @@ -11,6 +11,11 @@

#import <CoreText/CoreText.h>

#ifndef DT_USE_THREAD_SAFE_INITIALIZATION
#ifndef DT_USE_THREAD_SAFE_INITIALIZATION_NOT_AVAILABLE
#warning Thread safe initialization is not enabled.
#endif
#endif


@interface DTCoreTextFontCollection ()
Expand Down Expand Up @@ -81,7 +86,7 @@ - (DTCoreTextFontDescriptor *)matchingFontDescriptorForFontDescriptor:(DTCoreTex

NSArray *matchingDescriptors = [self.fontDescriptors filteredArrayUsingPredicate:predicate];

NSLog(@"%@", matchingDescriptors);
//NSLog(@"%@", matchingDescriptors);

if ([matchingDescriptors count])
{
Expand Down
1 change: 1 addition & 0 deletions Classes/DTCoreTextGlyphRun.h
Expand Up @@ -28,6 +28,7 @@
NSInteger numberOfGlyphs;

const CGPoint *glyphPositionPoints;
BOOL needToFreeGlyphPositionPoints;

DTCoreTextLayoutLine *_line;
NSDictionary *attributes;
Expand Down
2 changes: 1 addition & 1 deletion Classes/DTCoreTextLayoutFrame.m
Expand Up @@ -59,7 +59,7 @@ - (id)initWithFrame:(CGRect)frame layouter:(DTCoreTextLayouter *)layouter range:
}
else
{
NSLog(@"Strange, should have gotten a valid framesetter");
// Strange, should have gotten a valid framesetter


[_layouter release];
Expand Down
5 changes: 0 additions & 5 deletions Classes/DTCoreTextLayouter.m
Expand Up @@ -103,11 +103,6 @@ - (CTFramesetterRef) framesetter
if (!framesetter)
{
framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)self.attributedString);

if (!framesetter)
{
NSLog(@"No Framesetter!");
}
}
}
}
Expand Down
10 changes: 7 additions & 3 deletions Classes/DTLazyImageView.m
Expand Up @@ -8,6 +8,12 @@

#import "DTLazyImageView.h"

#ifndef DT_USE_THREAD_SAFE_INITIALIZATION
#ifndef DT_USE_THREAD_SAFE_INITIALIZATION_NOT_AVAILABLE
#warning Thread safe initialization is not enabled.
#endif
#endif

static NSCache *_imageCache = nil;


Expand Down Expand Up @@ -89,7 +95,7 @@ -(CGImageRef)newTransitoryImage:(CGImageRef)partialImg
CGColorSpaceRelease(colorSpace);
if (!bmContext)
{
NSLog(@"fail creating context");
// fail creating context
return NULL;
}
CGContextDrawImage(bmContext, (CGRect){.origin.x = 0.0f, .origin.y = 0.0f, .size.width = _fullWidth, .size.height = height}, partialImg);
Expand Down Expand Up @@ -252,8 +258,6 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"Failed to load image at %@, %@", _url, [error localizedDescription]);

[_connection release], _connection = nil;
[_receivedData release], _receivedData = nil;

Expand Down
6 changes: 5 additions & 1 deletion Classes/DemoSnippetsViewController.m
Expand Up @@ -61,7 +61,10 @@ - (DTAttributedTextContentView *)contentViewForIndexPath:(NSIndexPath *)indexPat
contentViewCache = [[NSMutableDictionary alloc] init];
}

DTAttributedTextContentView *contentView = (id)[contentViewCache objectForKey:indexPath];
// workaround for iOS 5 bug
NSString *key = [NSString stringWithFormat:@"%d-%d", indexPath.section, indexPath.row];

DTAttributedTextContentView *contentView = (id)[contentViewCache objectForKey:key];

if (!contentView)
{
Expand All @@ -78,6 +81,7 @@ - (DTAttributedTextContentView *)contentViewForIndexPath:(NSIndexPath *)indexPat
CGFloat width = self.view.frame.size.width;
[DTAttributedTextContentView setLayerClass:nil];
contentView = [[[DTAttributedTextContentView alloc] initWithAttributedString:string width:width - 20.0] autorelease];
contentView.shouldDrawImages = YES;

contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
contentView.edgeInsets = UIEdgeInsetsMake(5, 5, 5, 5);
Expand Down
2 changes: 1 addition & 1 deletion Classes/NSAttributedString+HTML.m
Expand Up @@ -860,7 +860,7 @@ - (id)initWithHTML:(NSData *)data options:(NSDictionary *)options documentAttrib
}
else
{
NSLog(@"Ignoring non-open tag %@", currentTag.tagName);
// Ignoring non-open tag
}
}
else if (immediatelyClosed)
Expand Down
7 changes: 7 additions & 0 deletions Classes/NSCharacterSet+HTML.m
Expand Up @@ -8,6 +8,12 @@

#import "NSCharacterSet+HTML.h"

#ifndef DT_USE_THREAD_SAFE_INITIALIZATION
#ifndef DT_USE_THREAD_SAFE_INITIALIZATION_NOT_AVAILABLE
#warning Thread safe initialization is not enabled.
#endif
#endif

static NSCharacterSet *_tagNameCharacterSet = nil;
static NSCharacterSet *_tagAttributeNameCharacterSet = nil;
static NSCharacterSet *_quoteCharacterSet = nil;
Expand Down Expand Up @@ -37,6 +43,7 @@ + (NSCharacterSet *)tagAttributeNameCharacterSet
#ifdef DT_USE_THREAD_SAFE_INITIALIZATION
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
_tagAttributeNameCharacterSet = [[NSCharacterSet characterSetWithCharactersInString:@"-_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"] retain];
});
#else
if (!_tagAttributeNameCharacterSet)
Expand Down
6 changes: 6 additions & 0 deletions Classes/NSString+HTML.m
Expand Up @@ -10,6 +10,12 @@
#import "NSScanner+HTML.h"
#import "UIColor+HTML.h"

#ifndef DT_USE_THREAD_SAFE_INITIALIZATION
#ifndef DT_USE_THREAD_SAFE_INITIALIZATION_NOT_AVAILABLE
#warning Thread safe initialization is not enabled.
#endif
#endif

static NSSet *inlineTags = nil;
static NSSet *metaTags = nil;
static NSDictionary *entityLookup = nil;
Expand Down
222 changes: 111 additions & 111 deletions Classes/NSString+UTF8Cleaner.m
Expand Up @@ -13,10 +13,10 @@
typedef uint8_t UTF8; /* typically 8 bits */

typedef enum {
conversionOK, /* conversion successful */
sourceExhausted, /* partial character in source, but hit end */
targetExhausted, /* insuff. room in target for conversion */
sourceIllegal /* source sequence is illegal/malformed */
conversionOK, /* conversion successful */
sourceExhausted, /* partial character in source, but hit end */
targetExhausted, /* insuff. room in target for conversion */
sourceIllegal /* source sequence is illegal/malformed */
} ConversionResult;

#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
Expand Down Expand Up @@ -50,129 +50,129 @@
#pragma mark Unicode related functions

static __inline__ __attribute__((always_inline)) ConversionResult isValidCodePoint(UTF32 *u32CodePoint) {
ConversionResult result = conversionOK;
UTF32 ch = *u32CodePoint;

if((ch >= UNI_SUR_HIGH_START) && (ch <= UNI_SUR_LOW_END)) { result = sourceIllegal; ch = UNI_REPLACEMENT_CHAR; goto finished; }
if((ch >= 0xFDD0U) && ((ch <= 0xFDEFU) || ((ch & 0xFFFEU) == 0xFFFEU)) && (ch <= 0x10FFFFU)) { result = sourceIllegal; ch = UNI_REPLACEMENT_CHAR; goto finished; }
if( ch == 0U) { result = sourceIllegal; ch = UNI_REPLACEMENT_CHAR; goto finished; }

finished:
*u32CodePoint = ch;
return(result);
ConversionResult result = conversionOK;
UTF32 ch = *u32CodePoint;
if((ch >= UNI_SUR_HIGH_START) && (ch <= UNI_SUR_LOW_END)) { result = sourceIllegal; ch = UNI_REPLACEMENT_CHAR; goto finished; }
if((ch >= 0xFDD0U) && ((ch <= 0xFDEFU) || ((ch & 0xFFFEU) == 0xFFFEU)) && (ch <= 0x10FFFFU)) { result = sourceIllegal; ch = UNI_REPLACEMENT_CHAR; goto finished; }
if( ch == 0U) { result = sourceIllegal; ch = UNI_REPLACEMENT_CHAR; goto finished; }
finished:
*u32CodePoint = ch;
return(result);
}


static __inline__ __attribute__((always_inline)) int isLegalUTF8(const UTF8 *source, size_t length) {
const UTF8 *srcptr = source + length;
UTF8 a;

switch(length) {
default: return(0); // Everything else falls through when "true"...
case 4: if(((a = (*--srcptr)) < 0x80) || (a > 0xBF)) { return(0); }
case 3: if(((a = (*--srcptr)) < 0x80) || (a > 0xBF)) { return(0); }
case 2: if( (a = (*--srcptr)) > 0xBF ) { return(0); }
switch(*source) { // no fall-through in this inner switch
case 0xE0: if(a < 0xA0) { return(0); } break;
case 0xED: if(a > 0x9F) { return(0); } break;
case 0xF0: if(a < 0x90) { return(0); } break;
case 0xF4: if(a > 0x8F) { return(0); } break;
default: if(a < 0x80) { return(0); }
}
case 1: if((*source < 0xC2) && (*source >= 0x80)) { return(0); }
}

if(*source > 0xF4) { return(0); }

return(1);
const UTF8 *srcptr = source + length;
UTF8 a;
switch(length) {
default: return(0); // Everything else falls through when "true"...
case 4: if(((a = (*--srcptr)) < 0x80) || (a > 0xBF)) { return(0); }
case 3: if(((a = (*--srcptr)) < 0x80) || (a > 0xBF)) { return(0); }
case 2: if( (a = (*--srcptr)) > 0xBF ) { return(0); }
switch(*source) { // no fall-through in this inner switch
case 0xE0: if(a < 0xA0) { return(0); } break;
case 0xED: if(a > 0x9F) { return(0); } break;
case 0xF0: if(a < 0x90) { return(0); } break;
case 0xF4: if(a > 0x8F) { return(0); } break;
default: if(a < 0x80) { return(0); }
}
case 1: if((*source < 0xC2) && (*source >= 0x80)) { return(0); }
}
if(*source > 0xF4) { return(0); }
return(1);
}

static __inline__ __attribute__((always_inline)) ConversionResult ConvertSingleCodePointInUTF8(const UTF8 *sourceStart, const UTF8 *sourceEnd, UTF8 const **nextUTF8, UTF32 *convertedUTF32) {
ConversionResult result = conversionOK;
const UTF8 *source = sourceStart;
UTF32 ch = 0UL;

ConversionResult result = conversionOK;
const UTF8 *source = sourceStart;
UTF32 ch = 0UL;
#if !defined(DT_FAST_TRAILING_BYTES)
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
#else
unsigned short extraBytesToRead = __builtin_clz(((*source)^0xff) << 25);
unsigned short extraBytesToRead = __builtin_clz(((*source)^0xff) << 25);
#endif

if(((source + extraBytesToRead + 1) > sourceEnd) || (!isLegalUTF8(source, extraBytesToRead + 1))) {
source++;
while((source < sourceEnd) && (((*source) & 0xc0) == 0x80) && ((source - sourceStart) < (extraBytesToRead + 1))) { source++; }
NSCParameterAssert(source <= sourceEnd);
result = ((source < sourceEnd) && (((*source) & 0xc0) != 0x80)) ? sourceIllegal : ((sourceStart + extraBytesToRead + 1) > sourceEnd) ? sourceExhausted : sourceIllegal;
ch = UNI_REPLACEMENT_CHAR;
goto finished;
}

switch(extraBytesToRead) { // The cases all fall through.
case 5: ch += *source++; ch <<= 6;
case 4: ch += *source++; ch <<= 6;
case 3: ch += *source++; ch <<= 6;
case 2: ch += *source++; ch <<= 6;
case 1: ch += *source++; ch <<= 6;
case 0: ch += *source++;
}
ch -= offsetsFromUTF8[extraBytesToRead];

result = isValidCodePoint(&ch);
finished:
*nextUTF8 = source;
*convertedUTF32 = ch;
return(result);
if(((source + extraBytesToRead + 1) > sourceEnd) || (!isLegalUTF8(source, extraBytesToRead + 1))) {
source++;
while((source < sourceEnd) && (((*source) & 0xc0) == 0x80) && ((source - sourceStart) < (extraBytesToRead + 1))) { source++; }
NSCParameterAssert(source <= sourceEnd);
result = ((source < sourceEnd) && (((*source) & 0xc0) != 0x80)) ? sourceIllegal : ((sourceStart + extraBytesToRead + 1) > sourceEnd) ? sourceExhausted : sourceIllegal;
ch = UNI_REPLACEMENT_CHAR;
goto finished;
}
switch(extraBytesToRead) { // The cases all fall through.
case 5: ch += *source++; ch <<= 6;
case 4: ch += *source++; ch <<= 6;
case 3: ch += *source++; ch <<= 6;
case 2: ch += *source++; ch <<= 6;
case 1: ch += *source++; ch <<= 6;
case 0: ch += *source++;
}
ch -= offsetsFromUTF8[extraBytesToRead];
result = isValidCodePoint(&ch);
finished:
*nextUTF8 = source;
*convertedUTF32 = ch;
return(result);
}

@implementation NSString (MalformedUTF8Additions)

- (id)initWithPotentiallyMalformedUTF8Data:(NSData *)data
{
NSString *returnString = NULL;
if((returnString = [self initWithData:data encoding:NSUTF8StringEncoding]) == NULL) {
//NSLog(@"NSString failed to init with data, trying again by cleaning any malformed UTF8...");
NSMutableData *cleanUTF8Data = [NSMutableData dataWithData:data];
unsigned char *cleanUTF8Bytes = [cleanUTF8Data mutableBytes];
NSUInteger cleanUTF8Idx = 0UL, cleanUTF8Length = [cleanUTF8Data length];

while(cleanUTF8Idx < cleanUTF8Length) {
if(cleanUTF8Bytes[cleanUTF8Idx] < 0x80) { cleanUTF8Idx++; continue; }
unsigned char *nextValidCharacter = NULL;
UTF32 u32ch = 0U;
ConversionResult result;

if((result = ConvertSingleCodePointInUTF8(&cleanUTF8Bytes[cleanUTF8Idx], &cleanUTF8Bytes[cleanUTF8Length], (UTF8 const **)&nextValidCharacter, &u32ch)) == conversionOK) { cleanUTF8Idx = nextValidCharacter - cleanUTF8Bytes; }
else {
NSUInteger malformedUTF8Length = (nextValidCharacter - &cleanUTF8Bytes[cleanUTF8Idx]);
NSUInteger moveLength = &cleanUTF8Bytes[cleanUTF8Length] - &cleanUTF8Bytes[cleanUTF8Idx + malformedUTF8Length];

if(malformedUTF8Length < sizeof(sc_replacementCharUTF8)) {
[cleanUTF8Data increaseLengthBy:(sizeof(sc_replacementCharUTF8) - malformedUTF8Length)];
cleanUTF8Bytes = [cleanUTF8Data mutableBytes];
cleanUTF8Length = [cleanUTF8Data length];
memmove(&cleanUTF8Bytes[cleanUTF8Idx + sizeof(sc_replacementCharUTF8)], &cleanUTF8Bytes[cleanUTF8Idx + malformedUTF8Length], moveLength);
memcpy(&cleanUTF8Bytes[cleanUTF8Idx], sc_replacementCharUTF8, sizeof(sc_replacementCharUTF8));
cleanUTF8Idx += sizeof(sc_replacementCharUTF8);
} else {
if(moveLength > 3UL) {
memmove(&cleanUTF8Bytes[cleanUTF8Idx + sizeof(sc_replacementCharUTF8)], &cleanUTF8Bytes[cleanUTF8Idx + malformedUTF8Length], moveLength);
[cleanUTF8Data setLength:(malformedUTF8Length - sizeof(sc_replacementCharUTF8))];
cleanUTF8Bytes = [cleanUTF8Data mutableBytes];
cleanUTF8Length = [cleanUTF8Data length];
}
memcpy(&cleanUTF8Bytes[cleanUTF8Idx], sc_replacementCharUTF8, sizeof(sc_replacementCharUTF8));
cleanUTF8Idx += sizeof(sc_replacementCharUTF8);
}
}
}
returnString = [[NSString alloc] initWithData:cleanUTF8Data encoding:NSUTF8StringEncoding];
}
return(returnString);
NSString *returnString = NULL;
if((returnString = [self initWithData:data encoding:NSUTF8StringEncoding]) == NULL) {
// NSString failed to init with data, trying again by cleaning any malformed UTF8...
NSMutableData *cleanUTF8Data = [NSMutableData dataWithData:data];
unsigned char *cleanUTF8Bytes = [cleanUTF8Data mutableBytes];
NSUInteger cleanUTF8Idx = 0UL, cleanUTF8Length = [cleanUTF8Data length];
while(cleanUTF8Idx < cleanUTF8Length) {
if(cleanUTF8Bytes[cleanUTF8Idx] < 0x80) { cleanUTF8Idx++; continue; }
unsigned char *nextValidCharacter = NULL;
UTF32 u32ch = 0U;
ConversionResult result;
if((result = ConvertSingleCodePointInUTF8(&cleanUTF8Bytes[cleanUTF8Idx], &cleanUTF8Bytes[cleanUTF8Length], (UTF8 const **)&nextValidCharacter, &u32ch)) == conversionOK) { cleanUTF8Idx = nextValidCharacter - cleanUTF8Bytes; }
else {
NSUInteger malformedUTF8Length = (nextValidCharacter - &cleanUTF8Bytes[cleanUTF8Idx]);
NSUInteger moveLength = &cleanUTF8Bytes[cleanUTF8Length] - &cleanUTF8Bytes[cleanUTF8Idx + malformedUTF8Length];
if(malformedUTF8Length < sizeof(sc_replacementCharUTF8)) {
[cleanUTF8Data increaseLengthBy:(sizeof(sc_replacementCharUTF8) - malformedUTF8Length)];
cleanUTF8Bytes = [cleanUTF8Data mutableBytes];
cleanUTF8Length = [cleanUTF8Data length];
memmove(&cleanUTF8Bytes[cleanUTF8Idx + sizeof(sc_replacementCharUTF8)], &cleanUTF8Bytes[cleanUTF8Idx + malformedUTF8Length], moveLength);
memcpy(&cleanUTF8Bytes[cleanUTF8Idx], sc_replacementCharUTF8, sizeof(sc_replacementCharUTF8));
cleanUTF8Idx += sizeof(sc_replacementCharUTF8);
} else {
if(moveLength > 3UL) {
memmove(&cleanUTF8Bytes[cleanUTF8Idx + sizeof(sc_replacementCharUTF8)], &cleanUTF8Bytes[cleanUTF8Idx + malformedUTF8Length], moveLength);
[cleanUTF8Data setLength:(malformedUTF8Length - sizeof(sc_replacementCharUTF8))];
cleanUTF8Bytes = [cleanUTF8Data mutableBytes];
cleanUTF8Length = [cleanUTF8Data length];
}
memcpy(&cleanUTF8Bytes[cleanUTF8Idx], sc_replacementCharUTF8, sizeof(sc_replacementCharUTF8));
cleanUTF8Idx += sizeof(sc_replacementCharUTF8);
}
}
}
returnString = [[NSString alloc] initWithData:cleanUTF8Data encoding:NSUTF8StringEncoding];
}
return(returnString);
}

@end

0 comments on commit ccba654

Please sign in to comment.