123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- //
- // ReaderDocument.m
- // Reader v2.8.6
- //
- // Created by Julius Oklamcak on 2011-07-01.
- // Copyright © 2011-2015 Julius Oklamcak. All rights reserved.
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights to
- // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- // of the Software, and to permit persons to whom the Software is furnished to
- // do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in all
- // copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
- #import "ReaderDocument.h"
- #import "CGPDFDocument.h"
- #import <fcntl.h>
- @interface ReaderDocument ()
- @property (nonatomic, strong, readwrite) NSString *password;
- @property (nonatomic, strong, readwrite) NSString *filePath;
- @end
- @implementation ReaderDocument
- {
- NSString *_guid;
- NSDate *_fileDate;
- NSDate *_lastOpen;
- NSNumber *_fileSize;
- NSNumber *_pageCount;
- NSNumber *_pageNumber;
- NSMutableIndexSet *_bookmarks;
- NSString *_password;
- NSString *_fileName;
- NSString *_filePath;
- NSURL *_fileURL;
- }
- #pragma mark - Properties
- @synthesize guid = _guid;
- @synthesize fileDate = _fileDate;
- @synthesize lastOpen = _lastOpen;
- @synthesize fileSize = _fileSize;
- @synthesize pageCount = _pageCount;
- @synthesize pageNumber = _pageNumber;
- @synthesize bookmarks = _bookmarks;
- @synthesize password = _password;
- @synthesize filePath = _filePath;
- @dynamic fileName, fileURL;
- @dynamic canEmail, canExport, canPrint;
- #pragma mark - ReaderDocument class methods
- + (NSString *)GUID
- {
- CFUUIDRef theUUID = CFUUIDCreate(NULL);
- CFStringRef theString = CFUUIDCreateString(NULL, theUUID);
- NSString *unique = [NSString stringWithString:(__bridge id)theString];
- CFRelease(theString); CFRelease(theUUID); // Cleanup CF objects
- return unique;
- }
- + (NSString *)documentsPath
- {
- NSFileManager *fileManager = [NSFileManager defaultManager]; // Singleton
- NSURL *pathURL = [fileManager URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:NULL];
- return [pathURL path]; // Path to the application's "~/Documents" directory
- }
- + (NSString *)applicationSupportPath
- {
- NSFileManager *fileManager = [NSFileManager defaultManager]; // Singleton
- NSURL *pathURL = [fileManager URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:NULL];
- return [pathURL path]; // Path to the application's "~/Library/Application Support" directory
- }
- + (NSString *)archiveFilePath:(NSString *)fileName
- {
- NSFileManager *fileManager = [NSFileManager defaultManager]; // Singleton
- NSString *applicationSupportPath = [ReaderDocument applicationSupportPath]; // See above
- NSString *archivePath = [applicationSupportPath stringByAppendingPathComponent:@"Reader Metadata"];
- [fileManager createDirectoryAtPath:archivePath withIntermediateDirectories:NO attributes:nil error:NULL];
- NSString *archiveName = [[fileName stringByDeletingPathExtension] stringByAppendingPathExtension:@"plist"];
- return [archivePath stringByAppendingPathComponent:archiveName]; // "{archivePath}/'fileName'.plist"
- }
- + (ReaderDocument *)unarchiveFromFileName:(NSString *)filePath password:(NSString *)phrase
- {
- ReaderDocument *document = nil; // ReaderDocument object
- NSString *fileName = [filePath lastPathComponent]; // File name only
- NSString *archiveFilePath = [ReaderDocument archiveFilePath:fileName];
- @try // Unarchive an archived ReaderDocument object from its property list
- {
- document = [NSKeyedUnarchiver unarchiveObjectWithFile:archiveFilePath];
- if (document != nil) // Set the document's file path and password properties
- {
- document.filePath = [filePath copy]; document.password = [phrase copy];
- }
- }
- @catch (NSException *exception) // Exception handling (just in case O_o)
- {
- #ifdef DEBUG
- NSLog(@"%s Caught %@: %@", __FUNCTION__, [exception name], [exception reason]);
- #endif
- }
- return document;
- }
- + (ReaderDocument *)withDocumentFilePath:(NSString *)filePath password:(NSString *)phrase
- {
- ReaderDocument *document = nil; // ReaderDocument object
- document = [ReaderDocument unarchiveFromFileName:filePath password:phrase];
- if (document == nil) // Unarchive failed so create a new ReaderDocument object
- {
- document = [[ReaderDocument alloc] initWithFilePath:filePath password:phrase];
- }
- return document;
- }
- + (BOOL)isPDF:(NSString *)filePath
- {
- BOOL state = NO;
- if (filePath != nil) // Must have a file path
- {
- const char *path = [filePath fileSystemRepresentation];
- int fd = open(path, O_RDONLY); // Open the file
- if (fd > 0) // We have a valid file descriptor
- {
- const char sig[1024]; // File signature buffer
- ssize_t len = read(fd, (void *)&sig, sizeof(sig));
- state = (strnstr(sig, "%PDF", len) != NULL);
- close(fd); // Close the file
- }
- }
- return state;
- }
- #pragma mark - ReaderDocument instance methods
- - (instancetype)initWithFilePath:(NSString *)filePath password:(NSString *)phrase
- {
- if ((self = [super init])) // Initialize superclass first
- {
- if ([ReaderDocument isPDF:filePath] == YES) // Valid PDF
- {
- _guid = [ReaderDocument GUID]; // Create document's GUID
- _password = [phrase copy]; // Keep copy of document password
- _filePath = [filePath copy]; // Keep copy of document file path
- _pageNumber = [NSNumber numberWithInteger:1]; // Start on page one
- _bookmarks = [NSMutableIndexSet new]; // Bookmarked pages index set
- CFURLRef docURLRef = (__bridge CFURLRef)[self fileURL]; // CFURLRef from NSURL
- CGPDFDocumentRef thePDFDocRef = CGPDFDocumentCreateUsingUrl(docURLRef, _password);
- if (thePDFDocRef != NULL) // Get the total number of pages in the document
- {
- NSInteger pageCount = CGPDFDocumentGetNumberOfPages(thePDFDocRef);
- _pageCount = [NSNumber numberWithInteger:pageCount];
- CGPDFDocumentRelease(thePDFDocRef); // Cleanup
- }
- else // Cupertino, we have a problem with the document
- {
- NSAssert(NO, @"CGPDFDocumentRef == NULL");
- }
- _lastOpen = [NSDate dateWithTimeIntervalSinceReferenceDate:0.0];
- NSFileManager *fileManager = [NSFileManager defaultManager]; // Singleton
- NSDictionary *fileAttributes = [fileManager attributesOfItemAtPath:_filePath error:NULL];
- _fileDate = [fileAttributes objectForKey:NSFileModificationDate]; // File date
- _fileSize = [fileAttributes objectForKey:NSFileSize]; // File size (bytes)
- [self archiveDocumentProperties]; // Archive ReaderDocument object
- }
- else // Not a valid PDF file
- {
- self = nil;
- }
- }
- return self;
- }
- - (NSString *)fileName
- {
- if (_fileName == nil) _fileName = [_filePath lastPathComponent];
- return _fileName;
- }
- - (NSURL *)fileURL
- {
- if (_fileURL == nil) _fileURL = [[NSURL alloc] initFileURLWithPath:_filePath isDirectory:NO];
- return _fileURL;
- }
- - (BOOL)canEmail
- {
- return YES;
- }
- - (BOOL)canExport
- {
- return YES;
- }
- - (BOOL)canPrint
- {
- return YES;
- }
- - (BOOL)archiveDocumentProperties
- {
- NSString *archiveFilePath = [ReaderDocument archiveFilePath:[self fileName]];
- return [NSKeyedArchiver archiveRootObject:self toFile:archiveFilePath];
- }
- - (void)updateDocumentProperties
- {
- CFURLRef docURLRef = (__bridge CFURLRef)[self fileURL]; // CFURLRef from NSURL
- CGPDFDocumentRef thePDFDocRef = CGPDFDocumentCreateUsingUrl(docURLRef, _password);
- if (thePDFDocRef != NULL) // Get the total number of pages in the document
- {
- NSInteger pageCount = CGPDFDocumentGetNumberOfPages(thePDFDocRef);
- _pageCount = [NSNumber numberWithInteger:pageCount];
- CGPDFDocumentRelease(thePDFDocRef); // Cleanup
- }
- NSFileManager *fileManager = [NSFileManager defaultManager]; // Singleton
- NSDictionary *fileAttributes = [fileManager attributesOfItemAtPath:_filePath error:NULL];
- _fileDate = [fileAttributes objectForKey:NSFileModificationDate]; // File date
- _fileSize = [fileAttributes objectForKey:NSFileSize]; // File size (bytes)
- }
- #pragma mark - NSCoding protocol methods
- - (void)encodeWithCoder:(NSCoder *)encoder
- {
- [encoder encodeObject:_guid forKey:@"FileGUID"];
- [encoder encodeObject:_fileDate forKey:@"FileDate"];
- [encoder encodeObject:_pageCount forKey:@"PageCount"];
- [encoder encodeObject:_pageNumber forKey:@"PageNumber"];
- [encoder encodeObject:_bookmarks forKey:@"Bookmarks"];
- [encoder encodeObject:_fileSize forKey:@"FileSize"];
- [encoder encodeObject:_lastOpen forKey:@"LastOpen"];
- }
- - (instancetype)initWithCoder:(NSCoder *)decoder
- {
- if ((self = [super init])) // Superclass init
- {
- _guid = [decoder decodeObjectForKey:@"FileGUID"];
- _fileDate = [decoder decodeObjectForKey:@"FileDate"];
- _pageCount = [decoder decodeObjectForKey:@"PageCount"];
- _pageNumber = [decoder decodeObjectForKey:@"PageNumber"];
- _bookmarks = [decoder decodeObjectForKey:@"Bookmarks"];
- _fileSize = [decoder decodeObjectForKey:@"FileSize"];
- _lastOpen = [decoder decodeObjectForKey:@"LastOpen"];
- if (_guid == nil) _guid = [ReaderDocument GUID];
- if (_bookmarks != nil)
- _bookmarks = [_bookmarks mutableCopy];
- else
- _bookmarks = [NSMutableIndexSet new];
- }
- return self;
- }
- @end
|