Revision: 2846
          http://skim-app.svn.sourceforge.net/skim-app/?rev=2846&view=rev
Author:   hofman
Date:     2007-09-08 05:36:53 -0700 (Sat, 08 Sep 2007)

Log Message:
-----------
Support import/export of FDF files. Import is not yet tested, and also the 
output is not yet tested on compatibility with Acrobat.

Modified Paths:
--------------
    trunk/Dutch.lproj/InfoPlist.strings
    trunk/English.lproj/InfoPlist.strings
    trunk/French.lproj/InfoPlist.strings
    trunk/Info.plist
    trunk/Italian.lproj/InfoPlist.strings
    trunk/NSScanner_SKExtensions.h
    trunk/NSScanner_SKExtensions.m
    trunk/NSString_SKExtensions.h
    trunk/NSString_SKExtensions.m
    trunk/SKDocument.h
    trunk/SKDocument.m
    trunk/SKDocumentController.h
    trunk/SKDocumentController.m
    trunk/SKPDFAnnotationNote.h
    trunk/SKPDFAnnotationNote.m
    trunk/Skim.xcodeproj/project.pbxproj

Added Paths:
-----------
    trunk/SKFDFParser.h
    trunk/SKFDFParser.m

Modified: trunk/Dutch.lproj/InfoPlist.strings
===================================================================
(Binary files differ)

Modified: trunk/English.lproj/InfoPlist.strings
===================================================================
(Binary files differ)

Modified: trunk/French.lproj/InfoPlist.strings
===================================================================
(Binary files differ)

Modified: trunk/Info.plist
===================================================================
--- trunk/Info.plist    2007-09-08 00:26:07 UTC (rev 2845)
+++ trunk/Info.plist    2007-09-08 12:36:53 UTC (rev 2846)
@@ -43,6 +43,7 @@
                                <string>Skim Notes</string>
                                <string>Notes as RTF</string>
                                <string>Notes as Text</string>
+                               <string>Notes as FDF</string>
                        </array>
                </dict>
                <dict>
@@ -79,6 +80,7 @@
                                <string>Skim Notes</string>
                                <string>Notes as RTF</string>
                                <string>Notes as Text</string>
+                               <string>Notes as FDF</string>
                        </array>
                        <key>NSPersistentStoreTypeKey</key>
                        <string>Binary</string>
@@ -339,6 +341,30 @@
                        <key>NSPersistentStoreTypeKey</key>
                        <string>Binary</string>
                </dict>
+               <dict>
+                       <key>CFBundleTypeExtensions</key>
+                       <array>
+                               <string>fdf</string>
+                       </array>
+                       <key>CFBundleTypeMIMETypes</key>
+                       <array>
+                               <string>application/vnd.fdf</string>
+                       </array>
+                       <key>CFBundleTypeName</key>
+                       <string>Notes as FDF</string>
+                       <key>CFBundleTypeOSTypes</key>
+                       <array>
+                               <string>FDF </string>
+                       </array>
+                       <key>CFBundleTypeRole</key>
+                       <string>None</string>
+                       <key>LSTypeIsPackage</key>
+                       <false/>
+                       <key>NSDocumentClass</key>
+                       <string>SKDocument</string>
+                       <key>NSPersistentStoreTypeKey</key>
+                       <string>Binary</string>
+               </dict>
        </array>
        <key>CFBundleExecutable</key>
        <string>${EXECUTABLE_NAME}</string>
@@ -428,7 +454,7 @@
                        <key>UTTypeTagSpecification</key>
                        <dict>
                                <key>com.apple.ostype</key>
-                <string>PDFD</string>
+                               <string>PDFD</string>
                                <key>public.filename-extension</key>
                                <array>
                                        <string>pdfd</string>
@@ -449,7 +475,7 @@
                        <key>UTTypeTagSpecification</key>
                        <dict>
                                <key>com.apple.ostype</key>
-                <string>SKNT</string>
+                               <string>SKNT</string>
                                <key>public.filename-extension</key>
                                <array>
                                        <string>skim</string>

Modified: trunk/Italian.lproj/InfoPlist.strings
===================================================================
(Binary files differ)

Modified: trunk/NSScanner_SKExtensions.h
===================================================================
--- trunk/NSScanner_SKExtensions.h      2007-09-08 00:26:07 UTC (rev 2845)
+++ trunk/NSScanner_SKExtensions.h      2007-09-08 12:36:53 UTC (rev 2846)
@@ -41,4 +41,5 @@
 
 @interface NSScanner (SKExtensions)
 - (BOOL)scanCharacter:(unichar *)ch;
+- (BOOL)peekCharacter:(unichar *)ch;
 @end

Modified: trunk/NSScanner_SKExtensions.m
===================================================================
--- trunk/NSScanner_SKExtensions.m      2007-09-08 00:26:07 UTC (rev 2845)
+++ trunk/NSScanner_SKExtensions.m      2007-09-08 12:36:53 UTC (rev 2846)
@@ -51,4 +51,12 @@
     return YES;
 }
 
+- (BOOL)peekCharacter:(unichar *)ch {
+    if ([self isAtEnd])
+        return NO;
+    if (ch != NULL)
+        *ch = [[self string] characterAtIndex:[self scanLocation]];
+    return YES;
+}
+
 @end

Modified: trunk/NSString_SKExtensions.h
===================================================================
--- trunk/NSString_SKExtensions.h       2007-09-08 00:26:07 UTC (rev 2845)
+++ trunk/NSString_SKExtensions.h       2007-09-08 12:36:53 UTC (rev 2846)
@@ -53,6 +53,8 @@
 
 - (NSString *)lossyASCIIString;
 
+- (NSString *)stringByEscapingParenthesis;
+
 - (NSRange)rangeOfLeadingEmptyLine;
 - (NSRange)rangeOfLeadingEmptyLineInRange:(NSRange)range;
 - (NSRange)rangeOfTrailingEmptyLine;

Modified: trunk/NSString_SKExtensions.m
===================================================================
--- trunk/NSString_SKExtensions.m       2007-09-08 00:26:07 UTC (rev 2845)
+++ trunk/NSString_SKExtensions.m       2007-09-08 12:36:53 UTC (rev 2846)
@@ -203,6 +203,27 @@
     return [[[NSString alloc] initWithData:[self 
dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES] 
encoding:NSASCIIStringEncoding] autorelease];
 }
 
+- (NSString *)stringByEscapingParenthesis {
+    static NSCharacterSet *parenAndBackslashCharSet = nil;
+    
+    if (parenAndBackslashCharSet == nil)
+        parenAndBackslashCharSet = [[NSCharacterSet 
characterSetWithCharactersInString:@"()\\"] retain];
+    
+    unsigned location = [self 
rangeOfCharacterFromSet:parenAndBackslashCharSet].location;
+    if (location == NSNotFound)
+        return self;
+    
+    NSRange range;
+    NSMutableString *string = [self mutableCopy];
+    
+    while (location != NSNotFound) {
+        [string insertString:@"\\" atIndex:location];
+        range = NSMakeRange(location + 2, [string length] - location - 2);
+        location = [string rangeOfCharacterFromSet:parenAndBackslashCharSet 
options:0 range:range].location;
+    }
+    return [string autorelease];
+}
+
 #pragma mark Empty lines
 
 // whitespace at the beginning of the string up to the end or until (and 
including) a newline

Modified: trunk/SKDocument.h
===================================================================
--- trunk/SKDocument.h  2007-09-08 00:26:07 UTC (rev 2845)
+++ trunk/SKDocument.h  2007-09-08 12:36:53 UTC (rev 2846)
@@ -102,6 +102,7 @@
 
 - (NSString *)notesString;
 - (NSData *)notesRTFData;
+- (NSString *)notesFDFString;
 
 - (NSDictionary *)currentDocumentSetup;
 

Modified: trunk/SKDocument.m
===================================================================
--- trunk/SKDocument.m  2007-09-08 00:26:07 UTC (rev 2845)
+++ trunk/SKDocument.m  2007-09-08 12:36:53 UTC (rev 2846)
@@ -61,6 +61,7 @@
 #import "SKApplicationController.h"
 #import "Files_SKExtensions.h"
 #import "NSTask_SKExtensions.h"
+#import "SKFDFParser.h"
 
 #define BUNDLE_DATA_FILENAME @"data"
 
@@ -371,6 +372,12 @@
             didWrite = [string writeToURL:absoluteURL atomically:YES 
encoding:NSUTF8StringEncoding error:outError];
         else if (outError != NULL)
             *outError = [NSError errorWithDomain:SKDocumentErrorDomain code:1 
userInfo:[NSDictionary dictionaryWithObjectsAndKeys:NSLocalizedString(@"Unable 
to write notes as text", @"Error description"), NSLocalizedDescriptionKey, 
nil]];
+    } else if ([typeName isEqualToString:SKNotesFDFDocumentType]) {
+        NSString *string = [self notesFDFString];
+        if (string)
+            didWrite = [string writeToURL:absoluteURL atomically:YES 
encoding:NSISOLatin1StringEncoding error:outError];
+        else if (outError != NULL)
+            *outError = [NSError errorWithDomain:SKDocumentErrorDomain code:1 
userInfo:[NSDictionary dictionaryWithObjectsAndKeys:NSLocalizedString(@"Unable 
to write notes as FDF", @"Error description"), NSLocalizedDescriptionKey, nil]];
     }
     
     if (didWrite == NO && outError != NULL && *outError == nil)
@@ -668,8 +675,17 @@
 - (void)openPanelDidEnd:(NSOpenPanel *)oPanel returnCode:(int)returnCode  
contextInfo:(void  *)contextInfo{
     if (returnCode == NSOKButton) {
         NSURL *notesURL = [[oPanel URLs] objectAtIndex:0];
-        NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithFile:[notesURL 
path]];
+        NSString *extension = [[notesURL path] pathExtension];
+        NSArray *array = nil;
         
+        if ([extension caseInsensitiveCompare:@"skim"] == NSOrderedSame) {
+            array = [NSKeyedUnarchiver unarchiveObjectWithFile:[notesURL 
path]];
+        } else {
+            NSString *fdfString = [NSString stringWithContentsOfURL:notesURL 
encoding:NSISOLatin1StringEncoding error:NULL];
+            if (fdfString)
+                array = [SKFDFParser notesDictionariesFromFDFString:fdfString];
+        }
+        
         if (array) {
             if ([[oPanel accessoryView] isEqual:readNotesAccessoryView] && 
[replaceNotesCheckButton state] == NSOnState)
                 [[self mainWindowController] 
setAnnotationsFromDictionaries:array];
@@ -678,7 +694,8 @@
             // previous undo actions are not reliable anymore
             [[self undoManager] removeAllActions];
             [self updateChangeCount:NSChangeDone];
-        }
+        } else
+            NSBeep();
         
     }
 }
@@ -699,7 +716,7 @@
     
     [oPanel beginSheetForDirectory:[path stringByDeletingLastPathComponent]
                               file:[[path lastPathComponent] 
stringByReplacingPathExtension:@"skim"]
-                             types:[NSArray arrayWithObject:@"skim"]
+                             types:[NSArray arrayWithObjects:@"skim", @"fdf", 
nil]
                     modalForWindow:[self windowForSheet]
                      modalDelegate:self
                     
didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
@@ -1305,6 +1322,26 @@
     return data;
 }
 
+- (NSString *)notesFDFString {
+    NSString *filename = [[[self fileURL] path] lastPathComponent];
+    int i, count = [[self notes] count];
+    NSMutableString *string = [NSMutableString 
stringWithFormat:@"%%FDF-1.2\n%%%C%C%C%C\n1 0 obj<</FDF<<", 0xe2, 0xe3, 0xcf, 
0xd3];
+    [string appendString:@"/Annots["];
+    for (i = 0; i < count; i++)
+        [string appendFormat:@"%i 0 R ", i + 2];
+    if (filename && [[self fileType] isEqualToString:SKPDFBundleDocumentType]) 
{
+        NSArray *files = [[NSFileManager defaultManager] subpathsAtPath:[[self 
fileURL] path]];
+        unsigned index = [[files 
valueForKeyPath:@"pathExtension.lowercaseString"] indexOfObject:@"pdf"];
+        if (index != NSNotFound)
+            filename = [filename stringByAppendingPathComponent:[files 
objectAtIndex:index]];
+    }
+    [string appendFormat:@"]/F(%@)>>\nendobj\n", filename ? [filename 
stringByEscapingParenthesis] : @""];
+    for (i = 0; i < count; i++)
+        [string appendFormat:@"obj %i 0<<%@>>\nendobj\n", i + 2, [[[self 
notes] objectAtIndex:i] fdfString]];
+    [string appendString:@"trailer\n<</Root 1 0 R>>\n%%EOF\n"];
+    return string;
+}
+
 - (void)setPrintInfo:(NSPrintInfo *)printInfo {
     [super setPrintInfo:printInfo];
     if (autoRotateButton)

Modified: trunk/SKDocumentController.h
===================================================================
--- trunk/SKDocumentController.h        2007-09-08 00:26:07 UTC (rev 2845)
+++ trunk/SKDocumentController.h        2007-09-08 12:36:53 UTC (rev 2846)
@@ -45,6 +45,7 @@
 extern NSString *SKNotesDocumentType;
 extern NSString *SKNotesRTFDocumentType;
 extern NSString *SKNotesTextDocumentType;
+extern NSString *SKNotesFDFDocumentType;
 extern NSString *SKPostScriptDocumentType;
 extern NSString *SKDVIDocumentType;
 

Modified: trunk/SKDocumentController.m
===================================================================
--- trunk/SKDocumentController.m        2007-09-08 00:26:07 UTC (rev 2845)
+++ trunk/SKDocumentController.m        2007-09-08 12:36:53 UTC (rev 2846)
@@ -51,6 +51,7 @@
 NSString *SKNotesDocumentType = @"Skim Notes";
 NSString *SKNotesRTFDocumentType = @"Notes as RTF";
 NSString *SKNotesTextDocumentType = @"Notes as Text";
+NSString *SKNotesFDFDocumentType = @"Notes as FDF";
 NSString *SKPostScriptDocumentType = @"PostScript document";
 NSString *SKDVIDocumentType = @"DVI document";
 

Added: trunk/SKFDFParser.h
===================================================================
--- trunk/SKFDFParser.h                         (rev 0)
+++ trunk/SKFDFParser.h 2007-09-08 12:36:53 UTC (rev 2846)
@@ -0,0 +1,15 @@
+//
+//  SKFDFParser.h
+//  Skim
+//
+//  Created by Christiaan Hofman on 6/9/07.
+//  Copyright 2007 Christiaan Hofman. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+
+
[EMAIL PROTECTED] SKFDFParser : NSObject
++ (NSArray *)notesDictionariesFromFDFString:(NSString *)string;
++ (NSDictionary *)fdfObjectsFromFDFString:(NSString *)string;
[EMAIL PROTECTED]

Added: trunk/SKFDFParser.m
===================================================================
--- trunk/SKFDFParser.m                         (rev 0)
+++ trunk/SKFDFParser.m 2007-09-08 12:36:53 UTC (rev 2846)
@@ -0,0 +1,622 @@
+//
+//  SKFDFParser.m
+//  Skim
+//
+//  Created by Christiaan Hofman on 6/9/07.
+//  Copyright 2007 Christiaan Hofman. All rights reserved.
+//
+
+#import "SKFDFParser.h"
+#import <Quartz/Quartz.h>
+#import "NSScanner_SKExtensions.h"
+#import "NSCharacterSet_SKExtensions.h"
+
[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)scanFDFIndirectObject:(id *)object;
[EMAIL PROTECTED]
+
+#pragma mark -
+
[EMAIL PROTECTED] SKIndirectObject : NSObject <NSCopying> {
+    int objectNumber;
+    int generationNumber;
+}
++ (id)indirectObjectWithNumber:(int)objNumber generation:(int)genNumber;
+- (id)initWithNumber:(int)objNumber generation:(int)genNumber;
+- (int)objectNumber;
+- (int)generationNumber;
[EMAIL PROTECTED]
+
+#pragma mark -
+
[EMAIL PROTECTED] SKFDFParser
+
++ (id)value:(id)value ofClass:(Class)aClass lookup:(NSDictionary *)lookup {
+    while ([value isKindOfClass:[SKIndirectObject class]])
+        value = [lookup objectForKey:value];
+    return ([value isKindOfClass:aClass]) ? value : nil;
+}
+
++ (NSDictionary *)noteDictionary:(NSDictionary *)dict lookup:(NSDictionary 
*)lookup {
+    NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
+    NSEnumerator *keyEnum = [dict keyEnumerator];
+    NSString *key;
+    BOOL success = YES;
+    
+    while (success && (key = [keyEnum nextObject])) {
+        id value = [dict valueForKey:key];
+        
+        if ([key isEqualToString:@"Type"]) {
+            if (value = [self value:value ofClass:[NSString class] 
lookup:lookup])
+                [dictionary setObject:value forKey:@"type"];
+            else
+                success = NO;
+        } else if ([key isEqualToString:@"Contents"]) {
+            if (value = [self value:value ofClass:[NSString class] 
lookup:lookup])
+                [dictionary setObject:value forKey:@"contents"];
+            else
+                success = NO;
+        } else if ([key isEqualToString:@"Rect"]) {
+            if ((value = [self value:value ofClass:[NSArray class] 
lookup:lookup]) && [value count] == 4) {
+                NSRect rect;
+                rect.origin.x = [[value objectAtIndex:0] floatValue];
+                rect.origin.y = [[value objectAtIndex:1] floatValue];
+                rect.size.width = [[value objectAtIndex:2] floatValue] - 
NSMinX(rect);
+                rect.size.height = [[value objectAtIndex:3] floatValue] - 
NSMinY(rect);
+                [dictionary setObject:NSStringFromRect(rect) forKey:@"bounds"];
+            } else {
+                success = NO;
+            }
+        } else if ([key isEqualToString:@"Page"]) {
+            if (value = [self value:value ofClass:[NSNumber class] 
lookup:lookup])
+                [dictionary setObject:value forKey:@"pageIndex"];
+            else
+                success = NO;
+        } else if ([key isEqualToString:@"C"]) {
+            if ((value = [self value:value ofClass:[NSArray class] 
lookup:lookup]) && [value count] == 3) {
+                float r, g, b;
+                r = [[value objectAtIndex:0] floatValue];
+                g = [[value objectAtIndex:1] floatValue];
+                b = [[value objectAtIndex:2] floatValue];
+                [dictionary setObject:[NSColor colorWithCalibratedRed:r 
green:g blue:b alpha:1.0] forKey:@"color"];
+            } else {
+                success = NO;
+            }
+        } else if ([key isEqualToString:@"BS"]) {
+            if (value = [self value:value ofClass:[NSDictionary class] 
lookup:lookup]) {
+                NSNumber *width = [value objectForKey:@"W"];
+                NSString *s = [value objectForKey:@"S"];
+                NSArray *dashPattern = [value objectForKey:@"D"];
+                int style = kPDFBorderStyleSolid;
+                if (s && [s isKindOfClass:[NSString class]]) {
+                    success = NO;
+                    break;
+                }
+                if (dashPattern && [dashPattern isKindOfClass:[NSArray class]] 
== NO) {
+                    success = NO;
+                    break;
+                }
+                if (width && [width isKindOfClass:[NSNumber class]] == NO) {
+                    success = NO;
+                    break;
+                }
+                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 ? [value objectAtIndex:2] : 
nil;
+            NSArray *dashPattern = [value count] > 3 ? [value objectAtIndex:3] 
: nil;
+            if (dashPattern && [dashPattern isKindOfClass:[NSArray class]] == 
NO) {
+                success = NO;
+                break;
+            }
+            if (width && [width isKindOfClass:[NSNumber class]] == NO) {
+                success = NO;
+                break;
+            }
+            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 value:value ofClass:[NSString class] 
lookup:lookup]) {
+                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 value:value ofClass:[NSArray class] 
lookup:lookup]) && [value count] == 3) {
+                float r, g, b;
+                r = [[value objectAtIndex:0] floatValue];
+                g = [[value objectAtIndex:1] floatValue];
+                b = [[value objectAtIndex:2] floatValue];
+                [dictionary setObject:[NSColor colorWithCalibratedRed:r 
green:g blue:b alpha:1.0] forKey:@"interiorColor"];
+            } else {
+                success = NO;
+            }
+        } else if ([key isEqualToString:@"LE"]) {
+            if ((value = [self value:value ofClass:[NSArray class] 
lookup:lookup]) && [value count] == 2) {
+                NSString *start = [value objectAtIndex:0];
+                NSString *end = [value objectAtIndex:1];
+                int startStyle = kPDFLineStyleNone;
+                int endStyle = kPDFLineStyleNone;
+                if (start && [start isKindOfClass:[NSNumber class]] == NO) {
+                    success = NO;
+                    break;
+                }
+                if (end && [end isKindOfClass:[NSNumber class]] == NO) {
+                    success = NO;
+                    break;
+                }
+                if ([end isEqualToString:@"None"])
+                    startStyle = kPDFLineStyleNone;
+                else if ([end isEqualToString:@"Square"])
+                    startStyle = kPDFLineStyleSquare;
+                else if ([end isEqualToString:@"Circle"])
+                    startStyle = kPDFLineStyleCircle;
+                else if ([end isEqualToString:@"Diamond"])
+                    startStyle = kPDFLineStyleDiamond;
+                else if ([end isEqualToString:@"OpenArrow"])
+                    startStyle = kPDFLineStyleOpenArrow;
+                else if ([end isEqualToString:@"ClosedArrow"])
+                    startStyle = 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 value:value ofClass:[NSArray class] 
lookup:lookup]) && [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];
+                    [quadPoints addObject:NSStringFromPoint(point)];
+                }
+                [dictionary setObject:quadPoints 
forKey:@"quadrilateralPoints"];
+            } else {
+                success = NO;
+            }
+        }
+    }
+    return success ? dictionary : nil;
+}
+
++ (NSArray *)notesDictionariesFromFDFString:(NSString *)string {
+    NSMutableArray *array = nil;
+    NSDictionary *fdfDict;
+    NSDictionary *trailer;
+    SKIndirectObject *root;
+    NSDictionary *rootDict;
+    NSArray *annots;
+    
+    if ((fdfDict = [self fdfObjectsFromFDFString:string]) &&
+        (trailer = [fdfDict objectForKey:@"trailer"]) &&
+        ([trailer isKindOfClass:[NSDictionary class]]) &&
+        (root = [trailer objectForKey:@"Root"]) &&
+        ([rootDict isKindOfClass:[NSDictionary class]]) &&
+        (annots = [trailer objectForKey:@"Annots"]) &&
+        ([annots isKindOfClass:[NSArray class]])) {
+    
+        NSEnumerator *annotEnum = [annots objectEnumerator];
+        NSDictionary *dict;
+        
+        array = [NSMutableArray array];
+        while (dict = [annotEnum nextObject]) {
+            if ([dict isKindOfClass:[NSDictionary class]] == NO)
+                return nil;
+            if (dict = [self noteDictionary:dict lookup:fdfDict])
+                [array addObject:dict];
+        }
+    }
+    
+    return array;
+}
+
++ (NSDictionary *)fdfObjectsFromFDFString:(NSString *)string {
+    NSMutableDictionary *fdfDict = [NSMutableDictionary dictionary];
+    
+    NSDictionary *dictionary;
+    int objNumber, genNumber;
+    id object;
+    BOOL success = YES;
+    
+    NSScanner *scanner = [NSScanner scannerWithString:string];
+    
+    [scanner setCharactersToBeSkipped:nil];
+    
+    // Scan the FDF header
+    [scanner scanString:@"%FDF-1.2" intoString:NULL];
+    [scanner scanCharactersFromSet:[NSCharacterSet 
whitespaceAndNewlineCharacterSet] intoString:NULL];
+    if ([scanner scanString:@"%" intoString:NULL])
+        [scanner scanUpToCharactersFromSet:[NSCharacterSet 
newlineCharacterSet] intoString:NULL];
+    [scanner scanCharactersFromSet:[NSCharacterSet 
whitespaceAndNewlineCharacterSet] intoString:NULL];
+    
+    // Scan the FDF body
+    while (success = success && [scanner scanInt:&objNumber] &&
+                    [scanner scanCharactersFromSet:[NSCharacterSet 
whitespaceAndNewlineCharacterSet] intoString:NULL] &&
+                    [scanner scanInt:&genNumber] &&
+                    [scanner scanCharactersFromSet:[NSCharacterSet 
whitespaceCharacterSet] intoString:NULL] &&
+                    [scanner scanString:@"obj" intoString:NULL]) {
+        
+        [scanner scanCharactersFromSet:[NSCharacterSet 
whitespaceAndNewlineCharacterSet] intoString:NULL];
+        if (success = [scanner scanFDFObject:&object]) {
+            [scanner scanCharactersFromSet:[NSCharacterSet 
whitespaceAndNewlineCharacterSet] intoString:NULL];
+            
+            if ([object isKindOfClass:[NSDictionary class]] && [scanner 
scanString:@"stream" intoString:NULL]) {
+                object = @"";
+                [scanner scanString:@"\n" intoString:NULL] || [scanner 
scanString:@"\r\n" intoString:NULL];
+                
+                if ([scanner scanUpToString:@"endstream" intoString:&object]) {
+                    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];
+                    }
+                }
+                [scanner scanString:@"endstream" intoString:NULL];
+                [scanner scanCharactersFromSet:[NSCharacterSet 
whitespaceAndNewlineCharacterSet] intoString:NULL];
+            }
+            [fdfDict setObject:object forKey:[SKIndirectObject 
indirectObjectWithNumber:objNumber generation:genNumber]];
+            success = [scanner scanString:@"endobj" intoString:NULL];
+            [scanner scanCharactersFromSet:[NSCharacterSet 
whitespaceAndNewlineCharacterSet] intoString:NULL];
+        }
+    }
+    
+    // Scan the FDF cross reference table, if present
+    while (success && [scanner scanString:@"xref" intoString:NULL]) {
+        [scanner scanUpToCharactersFromSet:[NSCharacterSet 
newlineCharacterSet] intoString:NULL];
+        [scanner scanCharactersFromSet:[NSCharacterSet 
whitespaceAndNewlineCharacterSet] intoString:NULL];
+        while ([scanner scanInt:NULL]) {
+            [scanner scanUpToCharactersFromSet:[NSCharacterSet 
newlineCharacterSet] intoString:NULL];
+            [scanner scanCharactersFromSet:[NSCharacterSet 
whitespaceAndNewlineCharacterSet] intoString:NULL];
+        }
+    }
+    
+    // Scan the FDF trailer
+    if (success = success && [scanner scanString:@"trailer" intoString:NULL]) {
+        [scanner scanCharactersFromSet:[NSCharacterSet 
whitespaceAndNewlineCharacterSet] intoString:NULL];
+        if (success = [scanner scanFDFDictionary:&dictionary] && 
+                [scanner scanCharactersFromSet:[NSCharacterSet 
whitespaceAndNewlineCharacterSet] intoString:NULL] &&
+                [scanner scanString:@"%%EOF" intoString:NULL])
+            [fdfDict setObject:dictionary forKey:@"trailer"];
+    }
+    
+    return success ? fdfDict : nil;
+}
+
[EMAIL PROTECTED]
+
+#pragma mark -
+
[EMAIL PROTECTED] NSScanner (SKFDFParserExtensions)
+
+- (BOOL)scanFDFObject:(id *)object {
+    id tmpObject = nil;
+    BOOL success = [self scanFDFName:&tmpObject] || 
+        [self scanFDFString:&tmpObject] || 
+        [self scanFDFHexString:&tmpObject] || 
+        [self scanFDFNumber:&tmpObject] || 
+        [self scanFDFArray:&tmpObject] || 
+        [self scanFDFDictionary:&tmpObject] || 
+        [self scanFDFIndirectObject:&tmpObject] || 
+        [self scanString:@"null" intoString:NULL];
+    
+    if (success && object)
+        *object = tmpObject;
+    
+    return success;
+}
+
+- (BOOL)scanFDFArray:(NSArray **)array {
+    NSMutableArray *tmpArray = [NSMutableArray array];
+    unichar ch;
+    id object;
+    BOOL success = [self scanString:@"[" intoString:NULL];
+    
+    while (success) {
+        [self scanCharactersFromSet:[NSCharacterSet 
whitespaceAndNewlineCharacterSet] intoString:NULL];
+        
+        if ([self peekCharacter:&ch] == NO) {
+            success = NO;
+            break;
+        }
+        if (ch == ']')
+            break;
+        else if ((success = [self scanFDFObject:&object]) && object)
+            [tmpArray addObject:object];
+    }
+    
+    if (success && array)
+        *array = tmpArray;
+    
+    return success;
+}
+
+- (BOOL)scanFDFDictionary:(NSDictionary **)dictionary {
+    NSMutableDictionary *tmpDict = [NSMutableDictionary dictionary];
+    unichar ch;
+    NSString *key;
+    id object;
+    BOOL success = [self scanString:@"<<" intoString:NULL];
+    
+    while (success) {
+        [self scanCharactersFromSet:[NSCharacterSet 
whitespaceAndNewlineCharacterSet] intoString:NULL];
+        
+        if ([self peekCharacter:&ch] == NO) {
+            success = NO;
+            break;
+        }
+        if ([self scanFDFName:&key]) {
+            [self scanCharactersFromSet:[NSCharacterSet 
whitespaceAndNewlineCharacterSet] intoString:NULL];
+            if ((success = [self scanFDFObject:&object]) && object)
+                [tmpDict setObject:object forKey:key];
+        } else if ([self scanString:@">>" intoString:NULL]) {
+            break;
+        } else {
+            success = NO;
+        }
+    }
+    
+    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 = [self scanString:@"(" intoString:NULL];
+    
+    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
+                        success = NO;
+                } else {
+                    success = NO;
+                }
+            }
+        } else {
+            success = NO;
+        }
+    }
+    
+    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 ([[NSCharacterSet whitespaceAndNewlineCharacterSet] 
characterIsMember:ch]) {
+            // ignore
+        } 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 invertedSet] copy];
+        [tmpSet release];
+    }
+    return [self scanString:@"/" intoString:NULL] && [self 
scanUpToCharactersFromSet:whitespaceOrDelimiterCharSet intoString:string];
+}
+
+- (BOOL)scanFDFNumber:(NSNumber **)number {
+    float f;
+    BOOL success = [self scanFloat:&f];
+    
+    if (success && number)
+        *number = [NSNumber numberWithFloat:f];
+    
+    return success;
+}
+
+- (BOOL)scanFDFIndirectObject:(id *)object {
+    int rewindLoc = [self scanLocation];
+    id tmpObject;
+    int objNumber, genNumber;
+    BOOL success;
+    
+    if (success = [self scanInt:&objNumber] && [self 
scanCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] intoString:NULL] 
&&
+        [self scanInt:&genNumber] && [self 
scanCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] intoString:NULL] 
&&
+        [self scanString:@"R" intoString:NULL])
+        tmpObject = [SKIndirectObject indirectObjectWithNumber:objNumber 
generation:genNumber];
+    
+    if (success == NO)
+        [self setScanLocation:rewindLoc];
+    
+    if (success && object)
+        *object = tmpObject;
+    
+    return success;
+}
+
[EMAIL PROTECTED]
+
+#pragma mark -
+
[EMAIL PROTECTED] SKIndirectObject : NSObject
+
++ (id)indirectObjectWithNumber:(int)objNumber generation:(int)genNumber {
+    return [[[self alloc] initWithNumber:objNumber generation:genNumber] 
autorelease];
+}
+
+- (id)initWithNumber:(int)objNumber generation:(int)genNumber {
+    if (self = [super init]) {
+        objectNumber = objNumber;
+        generationNumber = genNumber;
+    }
+    return self;
+}
+
+- (id)copyWithZone:(NSZone *)aZone {
+    return [self retain];
+}
+
+- (BOOL)isEqual:(id)other {
+    return [self isMemberOfClass:[other class]] && [self objectNumber] == 
[other objectNumber] && [self generationNumber] == [other generationNumber];
+}
+
+- (int)objectNumber {
+    return objectNumber;
+}
+
+- (int)generationNumber {
+    return generationNumber;
+}
+
[EMAIL PROTECTED]

Modified: trunk/SKPDFAnnotationNote.h
===================================================================
--- trunk/SKPDFAnnotationNote.h 2007-09-08 00:26:07 UTC (rev 2845)
+++ trunk/SKPDFAnnotationNote.h 2007-09-08 12:36:53 UTC (rev 2846)
@@ -50,6 +50,8 @@
 
 - (NSDictionary *)dictionaryValue;
 
+- (NSString *)fdfString;
+
 - (PDFDestination *)destination;
 - (unsigned int)pageIndex;
 - (int)noteType;

Modified: trunk/SKPDFAnnotationNote.m
===================================================================
--- trunk/SKPDFAnnotationNote.m 2007-09-08 00:26:07 UTC (rev 2845)
+++ trunk/SKPDFAnnotationNote.m 2007-09-08 12:36:53 UTC (rev 2846)
@@ -44,6 +44,7 @@
 #import "OBUtilities.h"
 #import "NSUserDefaultsController_SKExtensions.h"
 #import "NSGeometry_SKExtensions.h"
+#import "NSString_SKExtensions.h"
 
 enum {
     SKASTextNote = 'NTxt',
@@ -222,6 +223,50 @@
     return dict;
 }
 
+- (NSString *)fdfString {
+    NSMutableString *string = [NSMutableString string];
+    NSRect bounds = [self bounds];
+    float r, g, b, a = 0.0;
+    PDFBorder *border = [self border];
+    [[self color] getRed:&r green:&g blue:&b alpha:&a];
+    [string appendString:@"/Type/Annot/Subtype/"];
+    [string appendString:[[self type] isEqualToString:@"Note"] ? @"Text" : 
[self type]];
+    [string appendString:@"/Contents("];
+    [string appendString:[[self contents] stringByEscapingParenthesis]];
+    if ([self text]) {
+        [string appendString:@"\n"];
+        [string appendString:[[[self text] string] 
stringByEscapingParenthesis]];
+    }
+    [string appendString:@")"];
+    [string appendFormat:@"/Rect[%f %f %f %f]", NSMinX(bounds), 
NSMinY(bounds), NSMaxX(bounds), NSMaxY(bounds)];
+    if (a > 0.0)
+        [string appendFormat:@"/C[%f %f %f]", r, g, b];
+    [string appendFormat:@"/Page %i", [self pageIndex]];
+    if (border) {
+        [string appendFormat:@"/BS<</W%f/S", [border lineWidth]];
+        switch ([border style]) {
+            case kPDFBorderStyleSolid:
+                [string appendString:@"/S"];
+                break;
+            case kPDFBorderStyleDashed:
+                [string appendString:@"/D"];
+                break;
+            case kPDFBorderStyleBeveled:
+                [string appendString:@"/B"];
+                break;
+            case kPDFBorderStyleInset:
+                [string appendString:@"/I"];
+                break;
+            case kPDFBorderStyleUnderline:
+                [string appendString:@"/U"];
+                break;
+        }
+        [string appendFormat:@"/[EMAIL PROTECTED]", [[[border dashPattern] 
valueForKey:@"stringValue"] componentsJoinedByString:@" "]];
+        [string appendString:@">>"];
+    }
+    return string;
+}
+
 - (PDFDestination *)destination{
     NSRect bounds = [self bounds];
     NSPoint point = SKTopLeftPoint(bounds);
@@ -599,6 +644,15 @@
     return dict;
 }
 
+- (NSString *)fdfString {
+    NSMutableString *string = [[[super fdfString] mutableCopy] autorelease];
+    float r, g, b, a = 0.0;
+    [[self interiorColor] getRed:&r green:&g blue:&b alpha:&a];
+    if (a > 0.0)
+        [string appendFormat:@"/IC[%f %f %f]", r, g, b];
+    return string;
+}
+
 - (BOOL)isNoteAnnotation { return YES; }
 
 - (BOOL)isResizable { return YES; }
@@ -673,6 +727,15 @@
     return dict;
 }
 
+- (NSString *)fdfString {
+    NSMutableString *string = [[[super fdfString] mutableCopy] autorelease];
+    float r, g, b, a = 0.0;
+    [[self interiorColor] getRed:&r green:&g blue:&b alpha:&a];
+    if (a > 0.0)
+        [string appendFormat:@"/IC[%f %f %f]", r, g, b];
+    return string;
+}
+
 - (BOOL)isNoteAnnotation { return YES; }
 
 - (BOOL)isResizable { return YES; }
@@ -910,6 +973,20 @@
     return dict;
 }
 
+- (NSString *)fdfString {
+    NSMutableString *string = [[[super fdfString] mutableCopy] autorelease];
+    NSEnumerator *pointEnum = [[self quadrilateralPoints] objectEnumerator];
+    NSValue *value;
+    NSPoint point;
+    [string appendString:@"/QuadPoints["];
+    while (value = [pointEnum nextObject]) {
+        point = [value pointValue];
+        [string appendFormat:@"%f %f ", point.x, point.y];
+    }
+    [string appendString:@"]"];
+    return string;
+}
+
 - (void)regenerateLineRects {
     
     NSArray *quadPoints = [self quadrilateralPoints];
@@ -1063,6 +1140,12 @@
     return dict;
 }
 
+- (NSString *)fdfString {
+    NSMutableString *string = [[[super fdfString] mutableCopy] autorelease];
+    [string appendFormat:@"/DA(/%@ %f Tf)", [[self font] fontName], [[self 
font] pointSize]];
+    return string;
+}
+
 - (BOOL)isNoteAnnotation { return YES; }
 
 - (BOOL)isResizable { return YES; }
@@ -1179,6 +1262,32 @@
     return dict;
 }
 
+- (NSString *)fdfString {
+    NSMutableString *string = [[[super fdfString] mutableCopy] autorelease];
+    [string appendString:@"/Name"];
+    switch ([self iconType]) {
+        case kPDFTextAnnotationIconComment:
+            [string appendString:@"/Comment"];
+            break;
+        case kPDFTextAnnotationIconKey:
+            [string appendString:@"/Key"];
+            break;
+        case kPDFTextAnnotationIconNote:
+            [string appendString:@"/Note"];
+            break;
+        case kPDFTextAnnotationIconNewParagraph:
+            [string appendString:@"/NewParagraph"];
+            break;
+        case kPDFTextAnnotationIconParagraph:
+            [string appendString:@"/Paragraph"];
+            break;
+        case kPDFTextAnnotationIconInsert:
+            [string appendString:@"/Insert"];
+            break;
+    }
+    return string;
+}
+
 - (BOOL)isNoteAnnotation { return YES; }
 
 - (BOOL)isMovable { return YES; }
@@ -1374,6 +1483,59 @@
     return dict;
 }
 
+- (NSString *)fdfString {
+    NSMutableString *string = [[[super fdfString] mutableCopy] autorelease];
+    [string appendString:@"/LE["];
+    switch ([self startLineStyle]) {
+        case kPDFLineStyleNone:
+            [string appendString:@"/None"];
+            break;
+        case kPDFLineStyleSquare:
+            [string appendString:@"/Square"];
+            break;
+        case kPDFLineStyleCircle:
+            [string appendString:@"/Circle"];
+            break;
+        case kPDFLineStyleDiamond:
+            [string appendString:@"/Diamond"];
+            break;
+        case kPDFLineStyleOpenArrow:
+            [string appendString:@"/OpenArrow"];
+            break;
+        case kPDFLineStyleClosedArrow:
+            [string appendString:@"/ClosedArrow"];
+            break;
+        default:
+            [string appendString:@"/None"];
+            break;
+    }
+    switch ([self endLineStyle]) {
+        case kPDFLineStyleNone:
+            [string appendString:@"/None"];
+            break;
+        case kPDFLineStyleSquare:
+            [string appendString:@"/Square"];
+            break;
+        case kPDFLineStyleCircle:
+            [string appendString:@"/Circle"];
+            break;
+        case kPDFLineStyleDiamond:
+            [string appendString:@"/Diamond"];
+            break;
+        case kPDFLineStyleOpenArrow:
+            [string appendString:@"/OpenArrow"];
+            break;
+        case kPDFLineStyleClosedArrow:
+            [string appendString:@"/ClosedArrow"];
+            break;
+        default:
+            [string appendString:@"/None"];
+            break;
+    }
+    [string appendString:@"]"];
+    return string;
+}
+
 - (BOOL)isNoteAnnotation { return YES; }
 
 - (BOOL)isResizable { return YES; }

Modified: trunk/Skim.xcodeproj/project.pbxproj
===================================================================
--- trunk/Skim.xcodeproj/project.pbxproj        2007-09-08 00:26:07 UTC (rev 
2845)
+++ trunk/Skim.xcodeproj/project.pbxproj        2007-09-08 12:36:53 UTC (rev 
2846)
@@ -133,6 +133,7 @@
                CE5F42AF0BF89FE00069D89C /* AppleRemote.m in Sources */ = {isa 
= PBXBuildFile; fileRef = CE5F42AD0BF89FE00069D89C /* AppleRemote.m */; };
                CE5F43730BF8A3410069D89C /* IOKit.framework in Frameworks */ = 
{isa = PBXBuildFile; fileRef = CE5F42D30BF8A3400069D89C /* IOKit.framework */; 
};
                CE5F71560C8CDF9A008BE480 /* NSCell_SKExtensions.m in Sources */ 
= {isa = PBXBuildFile; fileRef = CE5F71540C8CDF9A008BE480 /* 
NSCell_SKExtensions.m */; };
+               CE5FA1680C909886008BE480 /* SKFDFParser.m in Sources */ = {isa 
= PBXBuildFile; fileRef = CE5FA1660C909886008BE480 /* SKFDFParser.m */; };
                CE67BB260BC44AC9007B6929 /* ZoomValues.strings in Resources */ 
= {isa = PBXBuildFile; fileRef = CE67BB240BC44AC9007B6929 /* ZoomValues.strings 
*/; };
                CE6C03F10BEDF759007BF0B5 /* NSParagraphStyle_SKExtensions.m in 
Sources */ = {isa = PBXBuildFile; fileRef = CE6C03EF0BEDF759007BF0B5 /* 
NSParagraphStyle_SKExtensions.m */; };
                CE74686F0B7F3B1C00CBF969 /* ToolbarInfo.tiff in Resources */ = 
{isa = PBXBuildFile; fileRef = CE7467330B7F2ED700CBF969 /* ToolbarInfo.tiff */; 
};
@@ -500,6 +501,8 @@
                CE5F42D30BF8A3400069D89C /* IOKit.framework */ = {isa = 
PBXFileReference; lastKnownFileType = wrapper.framework; name = 
IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree 
= "<absolute>"; };
                CE5F71530C8CDF9A008BE480 /* NSCell_SKExtensions.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
NSCell_SKExtensions.h; sourceTree = "<group>"; };
                CE5F71540C8CDF9A008BE480 /* NSCell_SKExtensions.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= NSCell_SKExtensions.m; sourceTree = "<group>"; };
+               CE5FA1650C909886008BE480 /* SKFDFParser.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
SKFDFParser.h; sourceTree = "<group>"; };
+               CE5FA1660C909886008BE480 /* SKFDFParser.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= SKFDFParser.m; sourceTree = "<group>"; };
                CE67BB250BC44AC9007B6929 /* English */ = {isa = 
PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; 
name = English; path = English.lproj/ZoomValues.strings; sourceTree = 
"<group>"; };
                CE67BB290BC44AD5007B6929 /* Dutch */ = {isa = PBXFileReference; 
fileEncoding = 10; lastKnownFileType = text.plist.strings; name = Dutch; path = 
Dutch.lproj/ZoomValues.strings; sourceTree = "<group>"; };
                CE6C03EE0BEDF759007BF0B5 /* NSParagraphStyle_SKExtensions.h */ 
= {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = 
sourcecode.c.h; path = NSParagraphStyle_SKExtensions.h; sourceTree = "<group>"; 
};
@@ -1004,6 +1007,8 @@
                                CE48BAD60C089EA300A166C6 /* SKTemplateParser.m 
*/,
                                CE5BD6710C7ADF1500EBDCF7 /* 
SKTypeSelectHelper.h */,
                                CE5BD6720C7ADF1500EBDCF7 /* 
SKTypeSelectHelper.m */,
+                               CE5FA1650C909886008BE480 /* SKFDFParser.h */,
+                               CE5FA1660C909886008BE480 /* SKFDFParser.m */,
                        );
                        name = Miscellaneous;
                        sourceTree = "<group>";
@@ -1500,6 +1505,7 @@
                                CE5BF8430C7CC24A00EBDCF7 /* SKOutlineView.m in 
Sources */,
                                CE820A220C8A0E310020E6B0 /* 
NSTask_SKExtensions.m in Sources */,
                                CE5F71560C8CDF9A008BE480 /* 
NSCell_SKExtensions.m in Sources */,
+                               CE5FA1680C909886008BE480 /* SKFDFParser.m in 
Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };


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