@@ -385,7 +385,7 @@ - (void)customBarButtonItemAction:(UIBarButtonItem *)sender {
385385 }
386386}
387387
388- - (NSURL *)pdfFileURLWithPath : (NSString *)path {
388+ - (NSURL *)fileURLWithPath : (NSString *)path {
389389 if (path) {
390390 path = [path stringByExpandingTildeInPath ];
391391 path = [path stringByReplacingOccurrencesOfString: @" file:" withString: @" " ];
@@ -397,6 +397,42 @@ - (NSURL *)pdfFileURLWithPath:(NSString *)path {
397397 return nil ;
398398}
399399
400+ - (NSURL *)writableFileURLWithPath : (NSString *)path override : (BOOL )override copyIfNeeded : (BOOL )copyIfNeeded {
401+ NSURL *writableFileURL;
402+ if (path.absolutePath ) {
403+ writableFileURL = [NSURL fileURLWithPath: path];
404+ } else {
405+ NSString *docsFolder = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES ).firstObject ;
406+ writableFileURL = [NSURL fileURLWithPath: [docsFolder stringByAppendingPathComponent: path]];
407+ }
408+
409+ NSFileManager *fileManager = NSFileManager .defaultManager ;
410+ if (override) {
411+ [fileManager removeItemAtURL: writableFileURL error: NULL ];
412+ }
413+
414+ // If we don't have a writable file already, we move the provided file to the ~/Documents folder.
415+ if (![fileManager fileExistsAtPath: (NSString *)writableFileURL.path]) {
416+ // Create the folder where the writable file will be saved.
417+ NSError *createFolderError;
418+ if (![fileManager createDirectoryAtPath: writableFileURL.path.stringByDeletingLastPathComponent withIntermediateDirectories: YES attributes: nil error: &createFolderError]) {
419+ NSLog (@" Failed to create directory: %@ " , createFolderError.localizedDescription );
420+ return nil ;
421+ }
422+
423+ // Copy the provided file to a writable location if it exists.
424+ NSURL *fileURL = [self fileURLWithPath: path];
425+ NSError *copyError;
426+ if (copyIfNeeded && [fileManager fileExistsAtPath: (NSString *)fileURL.path]) {
427+ if (![fileManager copyItemAtURL: fileURL toURL: writableFileURL error: ©Error]) {
428+ NSLog (@" Failed to copy item at URL '%@ ' with error: %@ " , path, copyError.localizedDescription );
429+ return nil ;
430+ }
431+ }
432+ }
433+ return writableFileURL;
434+ }
435+
400436- (BOOL )isImagePath : (NSString *)path {
401437 NSString *pathExtension = path.pathExtension .lowercaseString ;
402438 return [pathExtension isEqualToString: @" png" ] || [pathExtension isEqualToString: @" jpeg" ] || [pathExtension isEqualToString: @" jpg" ];
@@ -409,7 +445,7 @@ - (void)configurePDFViewControllerWithPath:(NSString *)path options:(NSDictionar
409445
410446 if (path) {
411447 // configure document
412- NSURL *url = [self pdfFileURLWithPath : path];
448+ NSURL *url = [self fileURLWithPath : path];
413449 if ([self isImagePath: path]) {
414450 _pdfDocument = [[PSPDFImageDocument alloc ] initWithImageURL: url];
415451 }
@@ -435,25 +471,11 @@ - (void)configurePDFViewControllerWithPath:(NSString *)path options:(NSDictionar
435471}
436472
437473- (PSPDFDocument *)createXFDFDocumentWithPath : (NSString *)xfdfFilePath {
438- NSURL *xfdfFileURL;
439- if (xfdfFilePath.isAbsolutePath ) {
440- xfdfFileURL = [self pdfFileURLWithPath: xfdfFilePath];
441- } else {
442- // Locate the XFDF file in the ~/Documents directory
443- NSString *docsFolder = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES ).firstObject ;
444- xfdfFileURL = [NSURL fileURLWithPath: [docsFolder stringByAppendingPathComponent: xfdfFilePath]];
445- }
474+ // Copy the XFDF file to the ~/Documents foler or create one if we don't have one.
475+ NSURL *xfdfFileURL = [self writableFileURLWithPath: xfdfFilePath override: NO copyIfNeeded: YES ];
446476
447477 // Create an XFDF file from the current document if one doesn't already exist.
448478 if (![NSFileManager .defaultManager fileExistsAtPath: (NSString *)xfdfFileURL.path]) {
449- // Create the folder where the XFDF file will be saved.
450- NSError *createFolderError;
451- if (![NSFileManager .defaultManager createDirectoryAtPath: xfdfFileURL.path.stringByDeletingLastPathComponent withIntermediateDirectories: YES attributes: nil error: &createFolderError]) {
452- NSLog (@" Failed to create directory: %@ " , createFolderError.localizedDescription );
453- return nil ;
454- }
455-
456- // Write the file
457479 NSError *error;
458480 PSPDFFileDataSink *dataSink = [[PSPDFFileDataSink alloc ] initWithFileURL: xfdfFileURL options: PSPDFDataSinkOptionNone error: &error];
459481 if (dataSink) {
@@ -729,7 +751,7 @@ - (void)setLicenseKey:(CDVInvokedUrlCommand *)command {
729751
730752- (void )setFileURLForPSPDFDocumentWithJSON : (NSString *)path {
731753 // Brute-Force-Set.
732- [_pdfDocument setValue: [self pdfFileURLWithPath : path] forKey: @" fileURL" ];
754+ [_pdfDocument setValue: [self fileURLWithPath : path] forKey: @" fileURL" ];
733755}
734756
735757- (NSString *)fileURLAsJSON {
@@ -1063,9 +1085,7 @@ - (void)presentWithXFDF:(CDVInvokedUrlCommand *)command {
10631085
10641086 // Validate the XFDF file path.
10651087 if (xfdfFilePath.length == 0 ) {
1066- NSLog (@" The XFDF path must be a valid string" );
1067- [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR]
1068- callbackId: command.callbackId];
1088+ [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR messageAsString: @" The XFDF path must be a valid string." ] callbackId: command.callbackId];
10691089 return ;
10701090 }
10711091
@@ -1413,7 +1433,7 @@ - (void)getAnnotations:(CDVInvokedUrlCommand *)command {
14131433 if (annotationsJSON) {
14141434 pluginResult = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsDictionary: @{@" annotations" : annotationsJSON}];
14151435 } else {
1416- pluginResult = [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR messageAsDictionary: @{ @" localizedDescription " : @" Failed to get annotations" } ];
1436+ pluginResult = [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR messageAsString: @" Failed to get annotations. " ];
14171437 }
14181438
14191439 [self .commandDelegate sendPluginResult: pluginResult callbackId: command.callbackId];
@@ -1427,9 +1447,7 @@ - (void)addAnnotation:(CDVInvokedUrlCommand *)command {
14271447 } else if ([jsonAnnotation isKindOfClass: NSDictionary .class]) {
14281448 data = [NSJSONSerialization dataWithJSONObject: jsonAnnotation options: 0 error: nil ];
14291449 } else {
1430- NSLog (@" Invalid JSON Annotation." );
1431- [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR]
1432- callbackId: command.callbackId];
1450+ [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR messageAsString: @" Invalid JSON Annotation." ] callbackId: command.callbackId];
14331451 return ;
14341452 }
14351453
@@ -1444,22 +1462,18 @@ - (void)addAnnotation:(CDVInvokedUrlCommand *)command {
14441462 }
14451463
14461464 if (success) {
1447- [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_OK]
1465+ [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsBool: YES ]
14481466 callbackId: command.callbackId];
14491467 } else {
1450- NSLog (@" Failed to add annotation." );
1451- [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR]
1452- callbackId: command.callbackId];
1468+ [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR messageAsString: @" Failed to add annotation." ] callbackId: command.callbackId];
14531469 }
14541470}
14551471
14561472- (void )removeAnnotation : (CDVInvokedUrlCommand *)command {
14571473 id jsonAnnotation = [command argumentAtIndex: 0 ];
14581474 NSString *annotationUUID = jsonAnnotation[@" uuid" ];
14591475 if (annotationUUID.length == 0 ) {
1460- NSLog (@" Invalid annotation UUID." );
1461- [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR]
1462- callbackId: command.callbackId];
1476+ [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR messageAsString: @" Invalid annotation UUID." ] callbackId: command.callbackId];
14631477 }
14641478
14651479 PSPDFDocument *document = self.pdfController .document ;
@@ -1476,12 +1490,10 @@ - (void)removeAnnotation:(CDVInvokedUrlCommand *)command {
14761490 }
14771491
14781492 if (success) {
1479- [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_OK]
1493+ [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsBool: YES ]
14801494 callbackId: command.callbackId];
14811495 } else {
1482- NSLog (@" Failed to remove annotation." );
1483- [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR]
1484- callbackId: command.callbackId];
1496+ [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR messageAsString: @" Failed to remove annotation." ] callbackId: command.callbackId];
14851497 }
14861498}
14871499
@@ -1496,7 +1508,7 @@ - (void)getAllUnsavedAnnotations:(CDVInvokedUrlCommand *)command {
14961508 if (annotationsJSON) {
14971509 pluginResult = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsDictionary: annotationsJSON];
14981510 } else {
1499- pluginResult = [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR messageAsDictionary: @{ @" localizedDescription " : @" Failed to get annotations" } ];
1511+ pluginResult = [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR messageAsString: @" Failed to get unsaved annotations" ];
15001512 }
15011513
15021514 [self .commandDelegate sendPluginResult: pluginResult callbackId: command.callbackId];
@@ -1510,9 +1522,7 @@ - (void)applyInstantJSON:(CDVInvokedUrlCommand *)command {
15101522 } else if ([jsonValue isKindOfClass: NSDictionary .class]) {
15111523 data = [NSJSONSerialization dataWithJSONObject: jsonValue options: 0 error: nil ];
15121524 } else {
1513- NSLog (@" Invalid JSON Annotations." );
1514- [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR]
1515- callbackId: command.callbackId];
1525+ [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR messageAsString: @" Invalid Instant JSON payload." ] callbackId: command.callbackId];
15161526 return ;
15171527 }
15181528
@@ -1523,12 +1533,10 @@ - (void)applyInstantJSON:(CDVInvokedUrlCommand *)command {
15231533 BOOL success = [document applyInstantJSONFromDataProvider: dataContainerProvider toDocumentProvider: documentProvider lenient: NO error: NULL ];
15241534 if (success) {
15251535 [self .pdfController reloadData ];
1526- [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_OK]
1536+ [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsBool: YES ]
15271537 callbackId: command.callbackId];
15281538 } else {
1529- NSLog (@" Failed to add annotations." );
1530- [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR]
1531- callbackId: command.callbackId];
1539+ [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR messageAsString: @" Failed to add annotations." ] callbackId: command.callbackId];
15321540 }
15331541}
15341542
@@ -1560,9 +1568,7 @@ - (void)getFormFieldValue:(CDVInvokedUrlCommand *)command {
15601568 NSString *fullyQualifiedName = [command argumentAtIndex: 0 ];
15611569
15621570 if (fullyQualifiedName.length == 0 ) {
1563- NSLog (@" Invalid fully qualified name." );
1564- [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR]
1565- callbackId: command.callbackId];
1571+ [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR messageAsString: @" Invalid fully qualified name." ] callbackId: command.callbackId];
15661572 return ;
15671573 }
15681574
@@ -1581,7 +1587,7 @@ - (void)getFormFieldValue:(CDVInvokedUrlCommand *)command {
15811587 if (formFieldValue) {
15821588 pluginResult = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsDictionary: @{@" value" : formFieldValue}];
15831589 } else {
1584- pluginResult = [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR messageAsDictionary: @{ @" localizedDescription " : @" Failed to get annotations " } ];
1590+ pluginResult = [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR messageAsString: @" Failed to get form field value. " ];
15851591 }
15861592
15871593 [self .commandDelegate sendPluginResult: pluginResult callbackId: command.callbackId];
@@ -1592,27 +1598,30 @@ - (void)setFormFieldValue:(CDVInvokedUrlCommand *)command {
15921598 NSString *fullyQualifiedName = [command argumentAtIndex: 1 ];
15931599
15941600 if (fullyQualifiedName.length == 0 ) {
1595- NSLog (@" Invalid fully qualified name." );
1596- [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR]
1597- callbackId: command.callbackId];
1601+ [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR messageAsString: @" Invalid fully qualified name." ] callbackId: command.callbackId];
15981602 return ;
15991603 }
16001604
16011605 PSPDFDocument *document = self.pdfController .document ;
16021606 VALIDATE_DOCUMENT (document)
16031607
1608+ BOOL success = NO ;
16041609 for (PSPDFFormElement *formElement in document.formParser .forms ) {
16051610 if ([formElement.fullyQualifiedFieldName isEqualToString: fullyQualifiedName]) {
16061611 if ([formElement isKindOfClass: PSPDFButtonFormElement.class]) {
16071612 if ([value isEqualToString: @" selected" ]) {
16081613 [(PSPDFButtonFormElement *)formElement select ];
1614+ success = YES ;
16091615 } else if ([value isEqualToString: @" deselected" ]) {
16101616 [(PSPDFButtonFormElement *)formElement deselect ];
1617+ success = YES ;
16111618 }
16121619 } else if ([formElement isKindOfClass: PSPDFChoiceFormElement.class]) {
16131620 ((PSPDFChoiceFormElement *)formElement).selectedIndices = [NSIndexSet indexSetWithIndex: value.integerValue];
1621+ success = YES ;
16141622 } else if ([formElement isKindOfClass: PSPDFTextFieldFormElement.class]) {
16151623 formElement.contents = value;
1624+ success = YES ;
16161625 } else if ([formElement isKindOfClass: PSPDFSignatureFormElement.class]) {
16171626 NSLog (@" Signature form elements are not supported." );
16181627 } else {
@@ -1621,5 +1630,90 @@ - (void)setFormFieldValue:(CDVInvokedUrlCommand *)command {
16211630 break ;
16221631 }
16231632 }
1633+ if (success) {
1634+ [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsBool: YES ]
1635+ callbackId: command.callbackId];
1636+ } else {
1637+ [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR messageAsString: @" Failed to set form field value." ] callbackId: command.callbackId];
1638+ }
1639+ }
1640+
1641+ #pragma mark - XFDF
1642+
1643+ - (void )importXFDF : (CDVInvokedUrlCommand *)command {
1644+ NSString *xfdfFilePath = [command argumentAtIndex: 0 ];
1645+ // Validate the XFDF file path.
1646+ if (xfdfFilePath.length == 0 ) {
1647+ [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR messageAsString: @" The XFDF path must be a valid string." ] callbackId: command.callbackId];
1648+ return ;
1649+ }
1650+
1651+ NSURL *xfdfFileURL = [self fileURLWithPath: xfdfFilePath];
1652+ if (![NSFileManager .defaultManager fileExistsAtPath: (NSString *)xfdfFileURL.path]) {
1653+ [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR messageAsString: @" The XFDF file does not exist." ] callbackId: command.callbackId];
1654+ return ;
1655+ }
1656+
1657+ PSPDFDocument *document = self.pdfController .document ;
1658+ VALIDATE_DOCUMENT (document)
1659+
1660+ PSPDFFileDataProvider *dataProvider = [[PSPDFFileDataProvider alloc ] initWithFileURL: xfdfFileURL];
1661+ PSPDFXFDFParser *parser = [[PSPDFXFDFParser alloc ] initWithDataProvider: dataProvider documentProvider: document.documentProviders[0 ]];
1662+
1663+ NSError *error;
1664+ if ([parser parseWithError: &error]) {
1665+ [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsBool: YES ]
1666+ callbackId: command.callbackId];
1667+ } else {
1668+ CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR
1669+ messageAsDictionary: @{@" localizedDescription" : error.localizedDescription , @" domain" : error.domain }];
1670+ [self .commandDelegate sendPluginResult: pluginResult callbackId: command.callbackId];
1671+ return ;
1672+ }
1673+
1674+ // Import annotations to the document.
1675+ NSArray <PSPDFAnnotation *> *annotations = parser.annotations ;
1676+ if (annotations) {
1677+ [document addAnnotations: annotations options: nil ];
1678+ }
16241679}
1680+
1681+ - (void )exportXFDF : (CDVInvokedUrlCommand *)command {
1682+ NSString *xfdfFilePath = [command argumentAtIndex: 0 ];
1683+ // Validate the XFDF file path.
1684+ if (xfdfFilePath.length == 0 ) {
1685+ [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR]
1686+ callbackId: command.callbackId];
1687+ return ;
1688+ }
1689+
1690+ // Always overwrite the XFDF file we export to.
1691+ NSURL *xfdfFileURL = [self writableFileURLWithPath: xfdfFilePath override: YES copyIfNeeded: NO ];
1692+ PSPDFDocument *document = self.pdfController .document ;
1693+ VALIDATE_DOCUMENT (document)
1694+
1695+ // Collect all existing annotations from the document
1696+ NSMutableArray *annotations = [NSMutableArray array ];
1697+ for (NSArray *pageAnnotations in [document allAnnotationsOfType: PSPDFAnnotationTypeAll].allValues ) {
1698+ [annotations addObjectsFromArray: pageAnnotations];
1699+ }
1700+ // Write to the XFDF file.
1701+ NSError *error;
1702+ PSPDFFileDataSink *dataSink = [[PSPDFFileDataSink alloc ] initWithFileURL: xfdfFileURL options: PSPDFDataSinkOptionNone error: &error];
1703+ if (dataSink) {
1704+ if ([[PSPDFXFDFWriter new ] writeAnnotations: annotations toDataSink: dataSink documentProvider: document.documentProviders[0 ] error: &error]) {
1705+ [self .commandDelegate sendPluginResult: [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsBool: YES ]
1706+ callbackId: command.callbackId];
1707+ } else {
1708+ CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR
1709+ messageAsDictionary: @{@" localizedDescription" : error.localizedDescription , @" domain" : error.domain }];
1710+ [self .commandDelegate sendPluginResult: pluginResult callbackId: command.callbackId];
1711+ }
1712+ } else {
1713+ CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR
1714+ messageAsDictionary: @{@" localizedDescription" : error.localizedDescription , @" domain" : error.domain }];
1715+ [self .commandDelegate sendPluginResult: pluginResult callbackId: command.callbackId];
1716+ }
1717+ }
1718+
16251719@end
0 commit comments