Revision: 2880
          http://skim-app.svn.sourceforge.net/skim-app/?rev=2880&view=rev
Author:   hofman
Date:     2007-09-10 10:10:16 -0700 (Mon, 10 Sep 2007)

Log Message:
-----------
Rewrite FDF parser. Use CGPDFDocument to parse the document after fooling it 
that the data is PDF.

Modified Paths:
--------------
    trunk/SKDocument.m
    trunk/SKFDFParser.h
    trunk/SKFDFParser.m

Modified: trunk/SKDocument.m
===================================================================
--- trunk/SKDocument.m  2007-09-10 17:09:31 UTC (rev 2879)
+++ trunk/SKDocument.m  2007-09-10 17:10:16 UTC (rev 2880)
@@ -671,9 +671,9 @@
         if ([extension caseInsensitiveCompare:@"skim"] == NSOrderedSame) {
             array = [NSKeyedUnarchiver unarchiveObjectWithFile:[notesURL 
path]];
         } else {
-            NSString *fdfString = [NSString stringWithContentsOfURL:notesURL 
encoding:NSISOLatin1StringEncoding error:NULL];
-            if (fdfString)
-                array = [SKFDFParser noteDictionariesFromFDFString:fdfString];
+            NSData *fdfData = [NSData dataWithContentsOfURL:notesURL];
+            if (fdfData)
+                array = [SKFDFParser noteDictionariesFromFDFData:fdfData];
         }
         
         if (array) {

Modified: trunk/SKFDFParser.h
===================================================================
--- trunk/SKFDFParser.h 2007-09-10 17:09:31 UTC (rev 2879)
+++ trunk/SKFDFParser.h 2007-09-10 17:10:16 UTC (rev 2880)
@@ -37,11 +37,9 @@
  */
 
 #import <Cocoa/Cocoa.h>
+#import <ApplicationServices/ApplicationServices.h>
 
 
[EMAIL PROTECTED] SKFDFParser : NSObject {
-    NSDictionary *fdfDictionary;
-    NSString *fdfString;
-}
-+ (NSArray *)noteDictionariesFromFDFString:(NSString *)string;
[EMAIL PROTECTED] SKFDFParser : NSObject
++ (NSArray *)noteDictionariesFromFDFData:(NSData *)data;
 @end

Modified: trunk/SKFDFParser.m
===================================================================
--- trunk/SKFDFParser.m 2007-09-10 17:09:31 UTC (rev 2879)
+++ trunk/SKFDFParser.m 2007-09-10 17:10:16 UTC (rev 2880)
@@ -44,767 +44,285 @@
 
 
 @interface SKFDFParser (SKPrivate)
-- (id)initWithString:(NSString *)aString;
-- (BOOL)parseFDFString;
-- (NSArray *)noteDictionaries;
-- (NSDictionary *)noteDictionary:(NSDictionary *)dict;
-- (id)value:(id)value ofClass:(Class)aClass;
-- (NSString *)stringValue:(id)value;
-- (NSNumber *)numberValue:(id)value;
-- (NSArray *)arrayValue:(id)value;
-- (NSDictionary *)dictionaryValue:(id)value;
++ (NSDictionary *)noteDictionaryFromPDFDictionary:(CGPDFDictionaryRef)annot;
 @end
 
 
[EMAIL PROTECTED] NSScanner (SKFDFParserExtensions)
-- (BOOL)scanFDFObject:(id *)object;
-- (BOOL)scanFDFArray:(NSArray **)array;
-- (BOOL)scanFDFDictionary:(NSDictionary **)dictionary;
-- (BOOL)scanFDFString:(NSString **)string;
-- (BOOL)scanFDFHexString:(NSString **)string;
-- (BOOL)scanFDFName:(NSString **)string;
-- (BOOL)scanFDFNumber:(NSNumber **)number;
-- (BOOL)scanFDFBoolean:(id *)boolNumber;
-- (BOOL)scanFDFIndirectObject:(id *)object;
-- (BOOL)scanFDFComment:(NSString **)comment;
[EMAIL PROTECTED]
[EMAIL PROTECTED] SKFDFParser
 
-#pragma mark -
+static const void *getCFDataBytePointer(void *info) { return 
CFDataGetBytePtr((CFDataRef)info); }
+static void releaseCFData(void *info) { CFRelease((CFDataRef)info); }
 
[EMAIL PROTECTED] SKIndirectObject : NSObject <NSCopying> {
-    unsigned int objectNumber;
-    unsigned int generationNumber;
-}
-+ (id)indirectObjectWithNumber:(unsigned int)objNumber generation:(unsigned 
int)genNumber;
-- (id)initWithNumber:(unsigned int)objNumber generation:(unsigned 
int)genNumber;
-- (unsigned int)objectNumber;
-- (unsigned int)generationNumber;
[EMAIL PROTECTED]
++ (NSArray *)noteDictionariesFromFDFData:(NSData *)data {
+    const char *pdfHeader = "%PDF";
+    unsigned pdfHeaderLength = strlen(pdfHeader);
+    
+    if ([data length] < pdfHeaderLength)
+        return NO;
+    
+    NSMutableData *pdfData = [data mutableCopy];
+    
+    [pdfData replaceBytesInRange:NSMakeRange(0, pdfHeaderLength) 
withBytes:pdfHeader length:pdfHeaderLength];
 
-#pragma mark -
-
[EMAIL PROTECTED] SKFDFParser
-
-+ (NSArray *)noteDictionariesFromFDFString:(NSString *)string {
-    NSArray *notes = nil;
-    SKFDFParser *parser = [[self alloc] initWithString:string];
+    static const CGDataProviderDirectAccessCallbacks callbacks = 
{&getCFDataBytePointer, NULL, NULL, &releaseCFData };
+    void *info = (void *)pdfData;
+    CGDataProviderRef provider = CGDataProviderCreateDirectAccess(info, 
[pdfData length], &callbacks);
+    CGPDFDocumentRef document = CGPDFDocumentCreateWithProvider(provider);
+    NSMutableArray *notes = nil;
     
-    if ([parser parseFDFString])
-        notes = [parser noteDictionaries];
-    [parser release];
+    if (document) {
+        CGPDFDictionaryRef catalog = CGPDFDocumentGetCatalog(document);
+        CGPDFDictionaryRef fdfDict;
+        CGPDFArrayRef annots;
+        
+        if (catalog &&
+            CGPDFDictionaryGetDictionary(catalog, "FDF", &fdfDict) &&
+            CGPDFDictionaryGetArray(fdfDict, "Annots", &annots)) {
+            
+            size_t i, count = CGPDFArrayGetCount(annots);
+            notes = [NSMutableArray arrayWithCapacity:count];
+            for (i = 0; i < count; i++) {
+                CGPDFDictionaryRef annot;
+                NSDictionary *note;
+                if (CGPDFArrayGetDictionary(annots, i, &annot) && 
+                    (note = [self noteDictionaryFromPDFDictionary:annot])) {
+                    [notes addObject:note];
+                }
+            }
+        }
+        
+        CGPDFDocumentRelease(document);
+    }
     
+    CGDataProviderRelease(provider);
+    [pdfData release];
+    
     return notes;
 }
 
-- (id)initWithString:(NSString *)string {
-    if (self = [super init]) {
-        fdfString = [string retain];
-        fdfDictionary = nil;
-    }
-    return self;
-}
-
-- (void)dealloc {
-    [fdfString release];
-    [fdfDictionary release];
-    [super dealloc];
-}
-
-- (BOOL)parseFDFString {
-    NSMutableDictionary *fdfDict = [[NSMutableDictionary alloc] init];
++ (NSDictionary *)noteDictionaryFromPDFDictionary:(CGPDFDictionaryRef)annot {
+    if (annot == NULL)
+        return nil;
     
-    NSDictionary *dictionary;
-    int objNumber, genNumber;
-    id object;
+    NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
+    CGPDFDictionaryRef dict;
+    CGPDFArrayRef array;
+    CGPDFStringRef string;
+    const char *name;
+    CGPDFReal real;
+    CGPDFInteger integer;
     BOOL success = YES;
     
-    NSScanner *scanner = [[NSScanner alloc] initWithString:fdfString];
+    if (CGPDFDictionaryGetName(annot, "Type", &name) == NO || strcmp(name, 
"Annot") != 0) {
+        success = NO;
+    }
     
-    // Scan the FDF header
-    [scanner scanString:@"%FDF-1.2" intoString:NULL];
-    while ([scanner scanFDFComment:NULL]);
+    if (CGPDFDictionaryGetName(annot, "Subtype", &name)) {
+        [dictionary setObject:[NSString stringWithFormat:@"%s", name] 
forKey:@"type"];
+    } else {
+        success = NO;
+    }
     
-    // Scan the FDF body
-    while (success && [scanner scanInt:&objNumber]) {
-        while ([scanner scanFDFComment:NULL]);
-        if (success = [scanner scanInt:&genNumber]) {
-            while ([scanner scanFDFComment:NULL]);
-            if (success = [scanner scanString:@"obj" intoString:NULL] && 
[scanner scanFDFObject:&object]) {
-                while ([scanner scanFDFComment:NULL]);
-                if ([object isKindOfClass:[NSDictionary class]] && [scanner 
scanString:@"stream" intoString:NULL]) {
-                    object = @"";
-                    if ([scanner scanUpToString:@"endstream" 
intoString:&object] && [scanner scanString:@"endstream" intoString:NULL]) {
-                        int end = [object length];
-                        unichar ch = end ? [object characterAtIndex:end - 1] : 
0;
-                        if ([[NSCharacterSet newlineCharacterSet] 
characterIsMember:ch]) {
-                            end--;
-                            if (end && ch == '\n' && [object 
characterAtIndex:end - 1] == '\r')
-                                end--;
-                            object = [object substringToIndex:end];
-                        }
-                    }
-                }
-                if (success) {
-                    success = [scanner scanString:@"endobj" intoString:NULL];
-                    while ([scanner scanFDFComment:NULL]);
-                    [fdfDict setObject:object forKey:[SKIndirectObject 
indirectObjectWithNumber:objNumber generation:genNumber]];
-                }
-            }
+    if (CGPDFDictionaryGetArray(annot, "Rect", &array)) {
+        CGPDFReal l, b, r, t;
+        if (CGPDFArrayGetCount(array) == 4 && CGPDFArrayGetNumber(array, 0, 
&l) && CGPDFArrayGetNumber(array, 1, &b) && CGPDFArrayGetNumber(array, 2, &r) 
&& CGPDFArrayGetNumber(array, 3, &t)) {
+            [dictionary setObject:NSStringFromRect(NSMakeRect(l, b, r - l, t - 
b)) forKey:@"bounds"];
         }
+    } else {
+        success = NO;
     }
     
-    // Scan the FDF cross reference table, if present
-    if (success) {
-        while ([scanner scanString:@"xref" intoString:NULL]) {
-            while ([scanner scanFDFComment:NULL]);
-            while ([scanner scanInt:NULL] && [scanner scanInt:NULL]) {
-                [scanner scanString:@"n" intoString:NULL] || [scanner 
scanString:@"f" intoString:NULL];
-                while ([scanner scanFDFComment:NULL]);
-            }
-        }
+    if (CGPDFDictionaryGetInteger(annot, "Page", &integer)) {
+        [dictionary setObject:[NSNumber numberWithInt:integer] 
forKey:@"pageIndex"];
+    } else {
+        success = NO;
     }
     
-    // Scan the FDF trailer
-    if (success = success && [scanner scanString:@"trailer" intoString:NULL]) {
-        while ([scanner scanFDFComment:NULL]);
-        if (success = [scanner scanFDFDictionary:&dictionary]) {
-            while ([scanner scanFDFComment:NULL]);
-            [fdfDict setObject:dictionary forKey:@"trailer"];
-            [scanner scanString:@"%%EOF" intoString:NULL];
+    if (CGPDFDictionaryGetString(annot, "Contents", &string)) {
+        NSString *contents = (NSString *)CGPDFStringCopyTextString(string);
+        if (contents)
+            [dictionary setObject:contents forKey:@"contents"];
+        [contents release];
+    }
+    
+    if (CGPDFDictionaryGetArray(annot, "C", &array)) {
+        CGPDFReal r, g, b;
+        if (CGPDFArrayGetCount(array) == 3 && CGPDFArrayGetNumber(array, 0, 
&r) && CGPDFArrayGetNumber(array, 1, &g) && CGPDFArrayGetNumber(array, 2, &b)) {
+            [dictionary setObject:[NSColor colorWithCalibratedRed:r green:g 
blue:b alpha:1.0] forKey:@"color"];
         }
     }
     
-    [scanner release];
-    
-    if (success)
-        fdfDictionary = fdfDict;
-    else
-        [fdfDict release];
-    
-    return success;
-}
-
-- (NSArray *)noteDictionaries {
-    NSMutableArray *array = nil;
-    NSDictionary *trailer;
-    NSDictionary *root;
-    NSDictionary *fdfDict;
-    NSArray *annots;
-    
-    if ((trailer = [self dictionaryValue:[fdfDictionary 
objectForKey:@"trailer"]]) &&
-        (root = [self dictionaryValue:[trailer objectForKey:@"Root"]]) &&
-        (fdfDict = [self dictionaryValue:[root objectForKey:@"FDF"]]) &&
-        (annots = [self arrayValue:[fdfDict objectForKey:@"Annots"]])) {
-    
-        NSEnumerator *annotEnum = [annots objectEnumerator];
-        NSDictionary *dict;
-        
-        array = [NSMutableArray arrayWithCapacity:[annots count]];
-        while (dict = [annotEnum nextObject]) {
-            if (dict = [self noteDictionary:[self dictionaryValue:dict]])
-                [array addObject:dict];
+    if (CGPDFDictionaryGetArray(annot, "IC", &array)) {
+        CGPDFReal r, g, b;
+        if (CGPDFArrayGetCount(array) == 3 && CGPDFArrayGetNumber(array, 0, 
&r) && CGPDFArrayGetNumber(array, 1, &g) && CGPDFArrayGetNumber(array, 2, &b)) {
+            [dictionary setObject:[NSColor colorWithCalibratedRed:r green:g 
blue:b alpha:1.0] forKey:@"interiorColor"];
         }
     }
     
-    return array;
-}
-
-- (id)value:(id)value ofClass:(Class)aClass {
-    while ([value isKindOfClass:[SKIndirectObject class]])
-        value = [fdfDictionary objectForKey:value];
-    return (aClass == Nil || [value isKindOfClass:aClass]) ? value : nil;
-}
-
-- (NSString *)stringValue:(id)value {
-    return [self value:value ofClass:[NSString class]];
-}
-
-- (NSNumber *)numberValue:(id)value {
-    return [self value:value ofClass:[NSNumber class]];
-}
-
-- (NSArray *)arrayValue:(id)value {
-    return [self value:value ofClass:[NSArray class]];
-}
-
-- (NSDictionary *)dictionaryValue:(id)value {
-    return [self value:value ofClass:[NSDictionary class]];
-}
-
-- (NSDictionary *)noteDictionary:(NSDictionary *)dict {
-    NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
-    NSSet *validTypes = [NSSet setWithObjects:@"FreeText", @"Note", @"Circle", 
@"Square", @"Highlight", @"Underline", @"StrikeOut", @"Line", nil];
-    NSEnumerator *keyEnum = [dict keyEnumerator];
-    NSString *key;
-    BOOL success = dict != nil;
-    
-    while (success && (key = [keyEnum nextObject])) {
-        id value = [dict valueForKey:key];
-        
-        if ([key isEqualToString:@"Type"]) {
-            if (value = [self stringValue:value]) {
-                if ([value isEqualToString:@"Annot"] == NO) {
-                    success = NO;
+    if (CGPDFDictionaryGetDictionary(annot, "BS", &dict)) {
+        if (CGPDFDictionaryGetNumber(dict, "W", &real)) {
+            if (real > 0.0) {
+                [dictionary setObject:[NSNumber numberWithFloat:real] 
forKey:@"lineWidth"];
+                if (CGPDFDictionaryGetName(dict, "S", &name)) {
+                    int style = kPDFBorderStyleSolid;
+                    if (strcmp(name, "S") == 0)
+                        style = kPDFBorderStyleSolid;
+                    else if (strcmp(name, "D") == 0)
+                        style = kPDFBorderStyleDashed;
+                    else if (strcmp(name, "B") == 0)
+                        style = kPDFBorderStyleBeveled;
+                    else if (strcmp(name, "I") == 0)
+                        style = kPDFBorderStyleInset;
+                    else if (strcmp(name, "U") == 0)
+                        style = kPDFBorderStyleUnderline;
+                    [dictionary setObject:[NSNumber numberWithInt:style] 
forKey:@"borderStyle"];
                 }
-            } else {
-                success = NO;
-            }
-        } else if ([key isEqualToString:@"Subtype"]) {
-            if (value = [self stringValue:value]) {
-                if ([value isEqualToString:@"Text"])
-                    value = @"Note";
-                if ([validTypes containsObject:value]) {
-                    [dictionary setObject:value forKey:@"type"];
-                } else {
-                    success = NO;
+                if (CGPDFDictionaryGetArray(annot, "D", &array)) {
+                    size_t i, count = CGPDFArrayGetCount(array);
+                    NSMutableArray *dp = [NSMutableArray array];
+                    for (i = 0; i < count; i++) {
+                        if (CGPDFArrayGetNumber(array, i, &real))
+                            [dp addObject:[NSNumber numberWithFloat:real]];
+                    }
+                    [dictionary setObject:dp forKey:@"dashPattern"];
                 }
-            } else {
-                success = NO;
             }
-        } else if ([key isEqualToString:@"Contents"]) {
-            if (value = [self stringValue:value]) {
-                [dictionary setObject:value forKey:@"contents"];
-            } else {
-                success = NO;
-            }
-        } else if ([key isEqualToString:@"Rect"]) {
-            if ((value = [self arrayValue:value]) && [value count] == 4) {
-                NSNumber *l = [self numberValue:[value objectAtIndex:0]];
-                NSNumber *b = [self numberValue:[value objectAtIndex:1]];
-                NSNumber *r = [self numberValue:[value objectAtIndex:2]];
-                NSNumber *t = [self numberValue:[value objectAtIndex:3]];
-                if (l && b && r && t) {
-                    NSRect rect;
-                    rect.origin.x = [l floatValue];
-                    rect.origin.y = [b floatValue];
-                    rect.size.width = [r floatValue] - NSMinX(rect);
-                    rect.size.height = [t floatValue] - NSMinY(rect);
-                    [dictionary setObject:NSStringFromRect(rect) 
forKey:@"bounds"];
-                } else {
-                    success = NO;
+        }
+    } else if (CGPDFDictionaryGetArray(annot, "Border", &array)) {
+        size_t i, count = CGPDFArrayGetCount(array);
+        if (count > 2 && CGPDFArrayGetNumber(array, 2, &real) && real > 0.0) {
+            [dictionary setObject:[NSNumber numberWithFloat:real] 
forKey:@"lineWidth"];
+            CGPDFArrayRef dp;
+            if (count > 3 && CGPDFArrayGetArray(array, 3, &dp)) {
+                count = CGPDFArrayGetCount(dp);
+                NSMutableArray *dashPattern = [NSMutableArray 
arrayWithCapacity:count];
+                for (i = 0; i < count; i++) {
+                    if (CGPDFArrayGetNumber(dp, i, &real))
+                        [dashPattern addObject:[NSNumber 
numberWithFloat:real]];
                 }
+                [dictionary setObject:dashPattern forKey:@"dashPattern"];
+                [dictionary setObject:[NSNumber 
numberWithInt:kPDFBorderStyleDashed] forKey:@"borderStyle"];
             } else {
-                success = NO;
+                 [dictionary setObject:[NSNumber 
numberWithInt:kPDFBorderStyleSolid] forKey:@"borderStyle"];
             }
-        } else if ([key isEqualToString:@"Page"]) {
-            if (value = [self numberValue:value]) {
-                [dictionary setObject:value forKey:@"pageIndex"];
-            } else {
-                success = NO;
-            }
-        } else if ([key isEqualToString:@"C"]) {
-            if ((value = [self arrayValue:value]) && [value count] == 3) {
-                NSNumber *r = [self numberValue:[value objectAtIndex:0]];
-                NSNumber *g = [self numberValue:[value objectAtIndex:1]];
-                NSNumber *b = [self numberValue:[value objectAtIndex:2]];
-                if (r && g && b) {
-                    [dictionary setObject:[NSColor colorWithCalibratedRed:[r 
floatValue] green:[g floatValue] blue:[b floatValue] alpha:1.0] 
forKey:@"color"];
-                } else {
-                    success = NO;
-                }
-            } else {
-                success = NO;
-            }
-        } else if ([key isEqualToString:@"BS"]) {
-            if (value = [self dictionaryValue:value]) {
-                NSNumber *width = [self numberValue:[value objectForKey:@"W"]];
-                NSString *s = [self stringValue:[value objectForKey:@"S"]];
-                NSArray *dashPattern = [self arrayValue:[value 
objectForKey:@"D"]];
-                int style = kPDFBorderStyleSolid;
-                if ([s isEqualToString:@"S"])
-                    style = kPDFBorderStyleSolid;
-                else if ([s isEqualToString:@"D"])
-                    style = kPDFBorderStyleDashed;
-                else if ([s isEqualToString:@"B"])
-                    style = kPDFBorderStyleBeveled;
-                else if ([s isEqualToString:@"I"])
-                    style = kPDFBorderStyleInset;
-                else if ([s isEqualToString:@"U"])
-                    style = kPDFBorderStyleUnderline;
-                if (width && [width floatValue] > 0.0) {
-                    [dictionary setObject:width forKey:@"lineWidth"];
-                    [dictionary setObject:[NSNumber numberWithInt:style] 
forKey:@"borderStyle"];
-                    if (dashPattern)
-                        [dictionary setObject:dashPattern 
forKey:@"dashPattern"];
-                }
-            } else {
-                success = NO;
-            }
-        } else if ([key isEqualToString:@"Border"]) {
-            if ([value isKindOfClass:[NSArray class]] == NO) {
-                success = NO;
-                break;
-            }
-            NSNumber *width = [value count] > 2 ?  [self numberValue:[value 
objectAtIndex:2]] : nil;
-            NSArray *dashPattern = [value count] > 3 ? [self arrayValue:[value 
objectAtIndex:2]] : nil;
-            if (width && [width floatValue] > 0.0) {
-                [dictionary setObject:width forKey:@"lineWidth"];
-                [dictionary setObject:[NSNumber numberWithInt:dashPattern ? 
kPDFBorderStyleDashed : kPDFBorderStyleSolid] forKey:@"borderStyle"];
-                if (dashPattern)
-                    [dictionary setObject:dashPattern forKey:@"dashPattern"];
-            }
-        } else if ([key isEqualToString:@"Name"]) {
-            if (value = [self stringValue:value]) {
-                int icon = kPDFTextAnnotationIconNote;
-                if ([value isEqualToString:@"Comment"])
-                    icon = kPDFTextAnnotationIconComment;
-                else if ([value isEqualToString:@"Key"])
-                    icon = kPDFTextAnnotationIconKey;
-                else if ([value isEqualToString:@"Note"])
-                    icon = kPDFTextAnnotationIconNote;
-                else if ([value isEqualToString:@"NewParagraph"])
-                    icon = kPDFTextAnnotationIconNewParagraph;
-                else if ([value isEqualToString:@"Paragraph"])
-                    icon = kPDFTextAnnotationIconParagraph;
-                else if ([value isEqualToString:@"Insert"])
-                    icon = kPDFTextAnnotationIconInsert;
-                [dictionary setObject:[NSNumber numberWithInt:icon] 
forKey:@"iconType"];
-            } else {
-                success = NO;
-            }
-        } else if ([key isEqualToString:@"IC"]) {
-            if ((value = [self arrayValue:value]) && [value count] == 3) {
-                NSNumber *r = [self numberValue:[value objectAtIndex:0]];
-                NSNumber *g = [self numberValue:[value objectAtIndex:1]];
-                NSNumber *b = [self numberValue:[value objectAtIndex:2]];
-                if (r && g && b) {
-                    [dictionary setObject:[NSColor colorWithCalibratedRed:[r 
floatValue] green:[g floatValue] blue:[b floatValue] alpha:1.0] 
forKey:@"interiorColor"];
-                } else {
-                    success = NO;
-                }
-            } else {
-                success = NO;
-            }
-        } else if ([key isEqualToString:@"LE"]) {
-            if ((value = [self arrayValue:value]) && [value count] == 2) {
-                NSString *start = [self stringValue:[value objectAtIndex:0]];
-                NSString *end = [self stringValue:[value objectAtIndex:1]];
-                int startStyle = kPDFLineStyleNone;
-                int endStyle = kPDFLineStyleNone;
-                if ([start isEqualToString:@"None"])
+        }
+    }
+    
+    if (CGPDFDictionaryGetName(annot, "Name", &name)) {
+        int icon = kPDFTextAnnotationIconNote;
+        if (strcmp(name, "Comment") == 0)
+            icon = kPDFTextAnnotationIconComment;
+        else if (strcmp(name, "Key") == 0)
+            icon = kPDFTextAnnotationIconKey;
+        else if (strcmp(name, "Note") == 0)
+            icon = kPDFTextAnnotationIconNote;
+        else if (strcmp(name, "NewParagraph") == 0)
+            icon = kPDFTextAnnotationIconNewParagraph;
+        else if (strcmp(name, "Paragraph") == 0)
+            icon = kPDFTextAnnotationIconParagraph;
+        else if (strcmp(name, "Insert") == 0)
+            icon = kPDFTextAnnotationIconInsert;
+        [dictionary setObject:[NSNumber numberWithInt:icon] 
forKey:@"iconType"];
+    }
+    
+    if (CGPDFDictionaryGetArray(annot, "LE", &array)) {
+        int startStyle = kPDFLineStyleNone;
+        int endStyle = kPDFLineStyleNone;
+        if (CGPDFArrayGetCount(array) == 2) {
+            if (CGPDFArrayGetName(array, 0, &name)) {
+                if (strcmp(name, "None") == 0)
                     startStyle = kPDFLineStyleNone;
-                else if ([start isEqualToString:@"Square"])
+                else if (strcmp(name, "Square") == 0)
                     startStyle = kPDFLineStyleSquare;
-                else if ([start isEqualToString:@"Circle"])
+                else if (strcmp(name, "Circle") == 0)
                     startStyle = kPDFLineStyleCircle;
-                else if ([start isEqualToString:@"Diamond"])
+                else if (strcmp(name, "Diamond") == 0)
                     startStyle = kPDFLineStyleDiamond;
-                else if ([start isEqualToString:@"OpenArrow"])
+                else if (strcmp(name, "OpenArrow") == 0)
                     startStyle = kPDFLineStyleOpenArrow;
-                else if ([start isEqualToString:@"ClosedArrow"])
+                else if (strcmp(name, "ClosedArrow") == 0)
                     startStyle = kPDFLineStyleClosedArrow;
-                if ([end isEqualToString:@"None"])
+            }
+            if (CGPDFArrayGetName(array, 1, &name)) {
+                if (strcmp(name, "None") == 0)
                     startStyle = kPDFLineStyleNone;
-                else if ([end isEqualToString:@"Square"])
+                else if (strcmp(name, "Square") == 0)
                     endStyle = kPDFLineStyleSquare;
-                else if ([end isEqualToString:@"Circle"])
+                else if (strcmp(name, "Circle") == 0)
                     endStyle = kPDFLineStyleCircle;
-                else if ([end isEqualToString:@"Diamond"])
+                else if (strcmp(name, "Diamond") == 0)
                     endStyle = kPDFLineStyleDiamond;
-                else if ([end isEqualToString:@"OpenArrow"])
+                else if (strcmp(name, "OpenArrow") == 0)
                     endStyle = kPDFLineStyleOpenArrow;
-                else if ([end isEqualToString:@"ClosedArrow"])
+                else if (strcmp(name, "ClosedArrow") == 0)
                     endStyle = kPDFLineStyleClosedArrow;
-                [dictionary setObject:[NSNumber numberWithInt:startStyle] 
forKey:@"startLineStyle"];
-                [dictionary setObject:[NSNumber numberWithInt:endStyle] 
forKey:@"endLineStyle"];
-            } else {
-                success = NO;
             }
-        } else if ([key isEqualToString:@"QuadPoints"]) {
-            if ((value = [self arrayValue:value]) && [value count] % 8 == 0) {
-                NSMutableArray *quadPoints = [NSMutableArray array];
-                int i, count = [value count];
-                for (i = 0; i < count; i++) {
-                    NSPoint point;
-                    point.x = [[value objectAtIndex:i] floatValue];
-                    point.y = [[value objectAtIndex:++i] floatValue];
+        }
+        [dictionary setObject:[NSNumber numberWithInt:endStyle] 
forKey:@"endLineStyle"];
+        [dictionary setObject:[NSNumber numberWithInt:startStyle] 
forKey:@"startLineStyle"];
+    }
+    
+    if (CGPDFDictionaryGetArray(annot, "QuadPoints", &array)) {
+        size_t i, count = CGPDFArrayGetCount(array);
+        if (i % 8 == 0) {
+            NSMutableArray *quadPoints = [NSMutableArray 
arrayWithCapacity:count / 2];
+            for (i = 0; i < count; i++) {
+                NSPoint point;
+                if (CGPDFArrayGetNumber(array, i, &point.x) && 
CGPDFArrayGetNumber(array, i, &point.y))
                     [quadPoints addObject:NSStringFromPoint(point)];
-                }
-                [dictionary setObject:quadPoints 
forKey:@"quadrilateralPoints"];
-            } else {
-                success = NO;
             }
-        } else if ([key isEqualToString:@"DA"]) {
-            if (value = [self stringValue:value]) {
-                NSScanner *scanner = [NSScanner scannerWithString:value];
-                NSString *fontName;
-                float fontSize;
-                if ([scanner scanUpToString:@"Tf" intoString:NULL] && [scanner 
isAtEnd] == NO) {
-                    unsigned location = [scanner scanLocation];
-                    NSRange r = [value rangeOfString:@"/" 
options:NSBackwardsSearch range:NSMakeRange(0, location)];
-                    if (r.location != NSNotFound) {
-                        [scanner setScanLocation:NSMaxRange(r)];
-                        if ([scanner scanCharactersFromSet:[NSCharacterSet 
nonWhitespaceAndNewlineCharacterSet] intoString:&fontName] && 
-                            [scanner scanFloat:&fontSize] && 
-                            [scanner scanString:@"Tf" intoString:NULL] && 
-                            [scanner scanLocation] == location + 2) {
-                            NSFont *font = [NSFont fontWithName:fontName 
size:fontSize];
-                            if (font == nil) {
-                                fontName = [[NSUserDefaults 
standardUserDefaults] stringForKey:SKTextNoteFontNameKey];
-                                font = [NSFont fontWithName:fontName 
size:fontSize];
-                            }
-                            if (font)
-                                [dictionary setObject:font forKey:@"font"];
-                        }
-                    }
-                }
-            }
+            [dictionary setObject:quadPoints forKey:@"quadrilateralPoints"];
         }
     }
     
+    if (CGPDFDictionaryGetString(annot, "DA", &string)) {
+        NSString *da = (NSString *)CGPDFStringCopyTextString(string);
+        if (da) {
+            NSScanner *scanner = [NSScanner scannerWithString:da];
+            NSString *fontName;
+            float fontSize;
+            if ([scanner scanUpToString:@"Tf" intoString:NULL] && [scanner 
isAtEnd] == NO) {
+                unsigned location = [scanner scanLocation];
+                NSRange r = [da rangeOfString:@"/" options:NSBackwardsSearch 
range:NSMakeRange(0, location)];
+                if (r.location != NSNotFound) {
+                    [scanner setScanLocation:NSMaxRange(r)];
+                    if ([scanner scanCharactersFromSet:[NSCharacterSet 
nonWhitespaceAndNewlineCharacterSet] intoString:&fontName] &&
+                        [scanner scanFloat:&fontSize] &&
+                        [scanner scanString:@"Tf" intoString:NULL] &&
+                        [scanner scanLocation] == location + 2) {
+                        NSFont *font = [NSFont fontWithName:fontName 
size:fontSize];
+                        if (font == nil) {
+                            fontName = [[NSUserDefaults standardUserDefaults] 
stringForKey:SKTextNoteFontNameKey];
+                            font = [NSFont fontWithName:fontName 
size:fontSize];
+                        }
+                        if (font)
+                            [dictionary setObject:font forKey:@"font"];
+                   }
+               }
+           }
+           [da release];
+       }
+    }
+    
+    NSSet *validTypes = [NSSet setWithObjects:@"FreeText", @"Note", @"Circle", 
@"Square", @"Highlight", @"Underline", @"StrikeOut", @"Line", nil];
     NSString *type = [dictionary objectForKey:@"type"];
     NSString *contents;
-    if ([type isEqualToString:@"Note"]) {
+    if ([type isEqualToString:@"Text"]) {
+        [dictionary setObject:@"Note" forKey:@"type"];
         if (contents = [dictionary objectForKey:@"contents"]) {
             unsigned contentsEnd, end;
             [contents getLineStart:NULL end:&end contentsEnd:&contentsEnd 
forRange:NSMakeRange(0, 0)];
-            if (end < [contents length]) {
+            if (contentsEnd < end) {
                 [dictionary setObject:[contents substringToIndex:contentsEnd] 
forKey:@"contents"];
-                [dictionary setObject:[[[NSAttributedString alloc] 
initWithString:[contents substringFromIndex:end]] autorelease] forKey:@"text"];
+                if (end < [contents length])
+                    [dictionary setObject:[[[NSAttributedString alloc] 
initWithString:[contents substringFromIndex:end]] autorelease] forKey:@"text"];
             }
         }
+    } else if ([validTypes containsObject:type] == NO) {
+        success = NO;
     }
     
     return success ? dictionary : nil;
 }
 
 @end
-
-#pragma mark -
-
[EMAIL PROTECTED] NSScanner (SKFDFParserExtensions)
-
-- (BOOL)scanFDFObject:(id *)object {
-    id tmpObject = nil;
-    BOOL success;
-    
-    while ([self scanFDFComment:NULL]);
-    
-    success = [self scanFDFName:&tmpObject] || 
-              [self scanFDFArray:&tmpObject] || 
-              [self scanFDFDictionary:&tmpObject] || 
-              [self scanFDFString:&tmpObject] || 
-              [self scanFDFHexString:&tmpObject] || 
-              [self scanFDFIndirectObject:&tmpObject] || 
-              [self scanFDFNumber:&tmpObject] || 
-              [self scanFDFBoolean:&tmpObject] || 
-              [self scanString:@"null" intoString:NULL];
-    
-    if (success && object)
-        *object = tmpObject;
-    
-    return success;
-}
-
-- (BOOL)scanFDFArray:(NSArray **)array {
-    NSMutableArray *tmpArray = [NSMutableArray array];
-    id object;
-    BOOL success = [self scanString:@"[" intoString:NULL];
-    
-    while (success) {
-        while ([self scanFDFComment:NULL]);
-        if ([self scanString:@"]" intoString:NULL]) {
-            break;
-        } else if (success = [self scanFDFObject:&object]) {
-           if (object)
-                [tmpArray addObject:object];
-        }
-    }
-    
-    if (success && array)
-        *array = tmpArray;
-    
-    return success;
-}
-
-- (BOOL)scanFDFDictionary:(NSDictionary **)dictionary {
-    NSMutableDictionary *tmpDict = [NSMutableDictionary dictionary];
-    NSString *key;
-    id object;
-    BOOL success = [self scanString:@"<<" intoString:NULL];
-    
-    while (success) {
-        while ([self scanFDFComment:NULL]);
-        if ([self scanString:@">>" intoString:NULL]) {
-            break;
-        } else if (success = ([self scanFDFName:&key] && [self 
scanFDFObject:&object])) {
-            if (object)
-                [tmpDict setObject:object forKey:key];
-        }
-    }
-    
-    if (success && dictionary)
-        *dictionary = tmpDict;
-    
-    return success;
-}
-
-- (BOOL)scanFDFString:(NSString **)string {
-    static NSCharacterSet *specialCharSet = nil;
-    if (specialCharSet == nil)
-        specialCharSet = [[NSCharacterSet 
characterSetWithCharactersInString:@"\\)"] retain];
-    
-    static NSCharacterSet *octalCharSet = nil;
-    if (octalCharSet == nil)
-        octalCharSet = [[NSCharacterSet 
characterSetWithCharactersInString:@"01234567"] retain];
-    
-    NSMutableString *tmpString = [NSMutableString string];
-    NSString *s;
-    unichar ch;
-    BOOL success;
-    
-    if (success = [self scanString:@"(" intoString:NULL]) {
-        NSCharacterSet *skipChars = [[self charactersToBeSkipped] retain];
-        [self setCharactersToBeSkipped:nil];
-        
-        while (success) {
-            if ([self scanUpToCharactersFromSet:specialCharSet intoString:&s])
-                [tmpString appendString:s];
-            if ([self scanCharacter:&ch]) {
-                if (ch == ')') {
-                    break;
-                } else if (ch == '\\') {
-                    if ([self scanCharacter:&ch]) {
-                        if (ch == 'n') {
-                            [tmpString appendString:@"\n"];
-                        } else if (ch == 'r') {
-                            [tmpString appendString:@"\r"];
-                        } else if (ch == 't') {
-                            [tmpString appendString:@"\r"];
-                        } else if (ch == 'b') {
-                            [tmpString appendString:@"\b"];
-                        } else if (ch == 'f') {
-                            [tmpString appendString:@"\f"];
-                        } else if (ch == '(') {
-                            [tmpString appendString:@"("];
-                        } else if (ch == ')') {
-                            [tmpString appendString:@")"];
-                        } else if (ch == '\\') {
-                            [tmpString appendString:@"\\"];
-                        } else if ([octalCharSet characterIsMember:ch]) {
-                            char octal = ch;
-                            if ([self peekCharacter:&ch] && [octalCharSet 
characterIsMember:ch]) {
-                                [self scanCharacter:NULL];
-                                octal = 8 * octal + ch;
-                                if ([self peekCharacter:&ch] && [octalCharSet 
characterIsMember:ch]) {
-                                    [self scanCharacter:NULL];
-                                    octal = 8 * octal + ch;
-                                }
-                            }
-                            NSString *s = [[NSString alloc] 
initWithBytes:&octal length:1 encoding:NSISOLatin1StringEncoding];
-                            if (success = s != nil)
-                                [tmpString appendString:s];
-                            [s release];
-                        } else if ([[NSCharacterSet newlineCharacterSet] 
characterIsMember:ch]) {
-                            if (ch == '\r')
-                                [self scanString:@"\n" intoString:NULL];
-                        } else {
-                            [self setScanLocation:[self scanLocation] - 1];
-                        }
-                    } else {
-                        success = NO;
-                    }
-                }
-            } else {
-                success = NO;
-            }
-        }
-        
-        [self setCharactersToBeSkipped:skipChars];
-        [skipChars release];
-    }
-    
-    if (success && string)
-        *string = tmpString;
-    
-    return success;
-}
-
-static inline int hexCharacterNumber(unichar ch) {
-    if (ch >= '0' && ch <= '9')
-        return ch - '0';
-    if (ch >= 'A' && ch <= 'F')
-        return ch - 'A' + 10;
-    if (ch >= 'a' && ch <= 'f')
-        return ch - 'a' + 10;
-    return 0;
-}
-
-- (BOOL)scanFDFHexString:(NSString **)string {
-    static NSCharacterSet *hexCharSet = nil;
-    if (hexCharSet == nil)
-        hexCharSet = [[NSCharacterSet 
characterSetWithCharactersInString:@"0123456789abcdefABCDEF"] retain];
-    
-    int rewindLoc = [self scanLocation];
-    NSString *hexString = nil;
-    unichar ch;
-    char hexChar;
-    char *bytes = NULL;
-    int length = 0;
-    BOOL isFirst = YES;
-    BOOL done = NO;
-    BOOL success = [self scanString:@"<" intoString:NULL];
-
-    while (done == NO && success && (success = [self scanCharacter:&ch])) {
-        hexChar = 0;
-        if ([hexCharSet characterIsMember:ch]) {
-            hexChar += hexCharacterNumber(ch);
-        } else if (ch == '>') {
-            done = YES;
-        } else {
-            success = NO;
-        }
-        if (isFirst) {
-            hexChar *= 16;
-        } else {
-            length++;
-            bytes = NSZoneRealloc([self zone], bytes, length * sizeof(char));
-            bytes[length - 1] = hexChar;
-            hexChar = 0;
-        }
-        isFirst = !isFirst;
-    }
-    
-    if (success) {
-        hexString = length == 0 ? @"" : [[[NSString alloc] initWithBytes:bytes 
length:length encoding:NSISOLatin1StringEncoding] autorelease];
-        success = hexString != nil;
-    }
-    
-    if (bytes)
-        NSZoneFree([self zone], bytes);
-    
-    if (success == NO)
-        [self setScanLocation:rewindLoc];
-    
-    if (success && string)
-        *string = hexString;
-    
-    return success;
-}
-
-- (BOOL)scanFDFName:(NSString **)string {
-    static NSCharacterSet *whitespaceOrDelimiterCharSet = nil;
-    if (whitespaceOrDelimiterCharSet == nil) {
-        NSMutableCharacterSet *tmpSet = [[NSCharacterSet 
whitespaceAndNewlineCharacterSet] mutableCopy];
-        [tmpSet addCharactersInString:@"()<>[]{}/%"];
-        whitespaceOrDelimiterCharSet = [tmpSet copy];
-        [tmpSet release];
-    }
-    
-    BOOL success;
-    
-    if (success = [self scanString:@"/" intoString:NULL]) {
-        NSCharacterSet *skipChars = [[self charactersToBeSkipped] retain];
-        [self setCharactersToBeSkipped:nil];
-        success =  [self 
scanUpToCharactersFromSet:whitespaceOrDelimiterCharSet intoString:string];
-        [self setCharactersToBeSkipped:skipChars];
-        [skipChars release];
-    }
-    
-    return  success;
-}
-
-- (BOOL)scanFDFNumber:(NSNumber **)number {
-    float f;
-    BOOL success = [self scanFloat:&f];
-    
-    if (success && number)
-        *number = [NSNumber numberWithFloat:f];
-    
-    return success;
-}
-
-- (BOOL)scanFDFBoolean:(id *)boolNumber {
-    NSNumber *tmpBoolNumber = nil;
-    BOOL success;
-    
-    if (success = [self scanString:@"true" intoString:NULL])
-        tmpBoolNumber = [NSNumber numberWithBool:YES];
-    else if (success = [self scanString:@"false" intoString:NULL])
-        tmpBoolNumber = [NSNumber numberWithBool:NO];
-    
-    if (success && boolNumber)
-        *boolNumber = tmpBoolNumber;
-    
-    return success;
-}
-
-- (BOOL)scanFDFIndirectObject:(id *)object {
-    int rewindLoc = [self scanLocation];
-    id tmpObject;
-    int objNumber, genNumber;
-    BOOL success;
-    
-    if (success = [self scanInt:&objNumber] && [self scanInt:&genNumber] && 
[self scanString:@"R" intoString:NULL]) {
-        tmpObject = [SKIndirectObject indirectObjectWithNumber:objNumber 
generation:genNumber];
-    } else {
-        [self setScanLocation:rewindLoc];
-    }
-    
-    if (success && object)
-        *object = tmpObject;
-    
-    return success;
-}
-
-- (BOOL)scanFDFComment:(NSString **)comment {
-    NSString *tmpComment = @"";
-    BOOL success;
-    
-    if (success = [self scanString:@"%" intoString:NULL]) {
-        NSCharacterSet *skipChars = [[self charactersToBeSkipped] retain];
-        [self setCharactersToBeSkipped:[NSCharacterSet 
whitespaceCharacterSet]];
-        [self scanUpToCharactersFromSet:[NSCharacterSet newlineCharacterSet] 
intoString:&tmpComment];
-        [self setCharactersToBeSkipped:skipChars];
-        [skipChars release];
-    }
-    
-    if (success && comment)
-        *comment = tmpComment;
-        
-    return  success;
-}
-
[EMAIL PROTECTED]
-
-#pragma mark -
-
[EMAIL PROTECTED] SKIndirectObject : NSObject
-
-+ (id)indirectObjectWithNumber:(unsigned int)objNumber generation:(unsigned 
int)genNumber {
-    return [[[self alloc] initWithNumber:objNumber generation:genNumber] 
autorelease];
-}
-
-- (id)initWithNumber:(unsigned int)objNumber generation:(unsigned 
int)genNumber {
-    if (self = [super init]) {
-        objectNumber = objNumber;
-        generationNumber = genNumber;
-    }
-    return self;
-}
-
-- (id)copyWithZone:(NSZone *)aZone {
-    return [self retain];
-}
-
-- (NSString *)description {
-    return [NSString stringWithFormat:@"<%@: %i %i>",[self class], 
objectNumber, generationNumber];
-}
-
-- (BOOL)isEqual:(id)other {
-    return [self isMemberOfClass:[other class]] && [self objectNumber] == 
[other objectNumber] && [self generationNumber] == [other generationNumber];
-}
-
-- (unsigned int)hash {
-    return (objectNumber << 16) | generationNumber;
-}
-
-- (unsigned int)objectNumber {
-    return objectNumber;
-}
-
-- (unsigned int)generationNumber {
-    return generationNumber;
-}
-
[EMAIL PROTECTED]


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Skim-app-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/skim-app-commit

Reply via email to