From fff38539507a479f032507de2a99c6cec97df1a0 Mon Sep 17 00:00:00 2001 From: Horst Rutter Date: Tue, 25 Jul 2023 11:04:23 +0200 Subject: [PATCH] Fix #657 --- pkg/api/test/form_test.go | 3 +-- pkg/cli/cli.go | 10 ++++++++++ pkg/pdfcpu/form/fill.go | 7 ++++++- pkg/pdfcpu/form/form.go | 16 +++++++++++++++- pkg/pdfcpu/primitives/font.go | 6 +++++- pkg/pdfcpu/validate/action.go | 2 +- pkg/pdfcpu/validate/annotation.go | 32 ++++++++++++++++++++++++++++--- 7 files changed, 67 insertions(+), 9 deletions(-) diff --git a/pkg/api/test/form_test.go b/pkg/api/test/form_test.go index d7370539..6d81d25f 100644 --- a/pkg/api/test/form_test.go +++ b/pkg/api/test/form_test.go @@ -55,8 +55,7 @@ func TestRemoveFormFields(t *testing.T) { } want := len(ss) - 2 - // Remove "firstName1" by id'(=45) and "dob1" by name as per form list output. - if err := api.RemoveFormFieldsFile(inFile, outFile, []string{"dob1", "45"}, conf); err != nil { + if err := api.RemoveFormFieldsFile(inFile, outFile, []string{"dob1", "firstName1"}, conf); err != nil { t.Fatalf("%s: %v\n", msg, err) } diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index 97f92fef..4cad23d9 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -60,6 +60,7 @@ func ChangeOwnerPassword(cmd *Command) ([]string, error) { // ListPermissions of inFile. func ListPermissions(cmd *Command) ([]string, error) { return api.ListPermissionsFile(*cmd.InFile, cmd.Conf) + // TODO turn struct into []string } // SetPermissions of inFile. @@ -161,6 +162,7 @@ func ExtractMetadata(cmd *Command) ([]string, error) { // ListAttachments returns a list of embedded file attachments for inFile. func ListAttachments(cmd *Command) ([]string, error) { return api.ListAttachmentsFile(*cmd.InFile, cmd.Conf) + // TODO turn struct into []string } // AddAttachments embeds inFiles into a PDF context read from inFile and writes the result to outFile. @@ -181,6 +183,7 @@ func ExtractAttachments(cmd *Command) ([]string, error) { // Info gathers information about inFile and returns the result as []string. func Info(cmd *Command) ([]string, error) { return api.InfoFiles(cmd.InFiles, cmd.PageSelection, cmd.Conf) + // TODO turn struct into []string } // CreateCheatSheetsFonts creates single page PDF cheat sheets for user fonts in current dir. @@ -191,6 +194,7 @@ func CreateCheatSheetsFonts(cmd *Command) ([]string, error) { // ListFonts gathers information about supported fonts and returns the result as []string. func ListFonts(cmd *Command) ([]string, error) { return api.ListFonts() + // TODO turn struct into []string } // InstallFonts installs True Type fonts into the pdfcpu pconfig dir. @@ -201,6 +205,7 @@ func InstallFonts(cmd *Command) ([]string, error) { // ListKeywords returns a list of keywords for inFile. func ListKeywords(cmd *Command) ([]string, error) { return api.ListKeywordsFile(*cmd.InFile, cmd.Conf) + // TODO turn struct into []string } // AddKeywords adds keywords to inFile's document info dict and writes the result to outFile. @@ -216,6 +221,7 @@ func RemoveKeywords(cmd *Command) ([]string, error) { // ListProperties returns inFile's properties. func ListProperties(cmd *Command) ([]string, error) { return api.ListPropertiesFile(*cmd.InFile, cmd.Conf) + // TODO turn struct into []string } // AddProperties adds properties to inFile's document info dict and writes the result to outFile. @@ -236,6 +242,7 @@ func Collect(cmd *Command) ([]string, error) { // ListBoxes returns inFile's page boundaries. func ListBoxes(cmd *Command) ([]string, error) { return api.ListBoxesFile(*cmd.InFile, cmd.PageSelection, cmd.PageBoundaries, cmd.Conf) + // TODO turn struct into []string } // AddBoxes adds page boundaries to inFile's page tree and writes the result to outFile. @@ -256,6 +263,7 @@ func Crop(cmd *Command) ([]string, error) { // ListAnnotations returns inFile's page annotations. func ListAnnotations(cmd *Command) ([]string, error) { _, ss, err := api.ListAnnotationsFile(*cmd.InFile, cmd.PageSelection, cmd.Conf) + // TODO turn struct into []string return ss, err } @@ -268,6 +276,7 @@ func RemoveAnnotations(cmd *Command) ([]string, error) { // ListImages returns inFiles embedded images. func ListImages(cmd *Command) ([]string, error) { return api.ListImagesFile(cmd.InFiles, cmd.PageSelection, cmd.Conf) + // turn struct into []string } // Dump known object to stdout. @@ -286,6 +295,7 @@ func Create(cmd *Command) ([]string, error) { // ListFormFields returns inFile's form field ids. func ListFormFields(cmd *Command) ([]string, error) { return api.ListFormFieldsFile(cmd.InFiles, cmd.Conf) + // TODO turn struct into []string } // RemoveFormFields removes some form fields from inFile. diff --git a/pkg/pdfcpu/form/fill.go b/pkg/pdfcpu/form/fill.go index 45e309c2..b92adaad 100644 --- a/pkg/pdfcpu/form/fill.go +++ b/pkg/pdfcpu/form/fill.go @@ -605,7 +605,12 @@ func fillBtn( fillDetails func(id, name string, fieldType FieldType, format DataFormat) ([]string, bool, bool), ok *bool) error { - if len(d.ArrayEntry("Kids")) > 0 { + ff := d.IntEntry("Ff") + if ff != nil && primitives.FieldFlags(*ff)&primitives.FieldPushbutton > 0 { + return nil + } + + if len(d.ArrayEntry("Kids")) > 0 && primitives.FieldFlags(*ff)&primitives.FieldRadio > 0 { if err := fillRadioButtonGroup(ctx, d, id, name, locked, format, fillDetails, ok); err != nil { return err } diff --git a/pkg/pdfcpu/form/form.go b/pkg/pdfcpu/form/form.go index 6f4c1c05..30bc7e81 100644 --- a/pkg/pdfcpu/form/form.go +++ b/pkg/pdfcpu/form/form.go @@ -332,6 +332,12 @@ func collectRadioButtonGroup(xRefTable *model.XRefTable, d types.Dict, f *Field, } func collectBtn(xRefTable *model.XRefTable, d types.Dict, f *Field, fm *FieldMeta) error { + + ff := d.IntEntry("Ff") + if ff != nil && primitives.FieldFlags(*ff)&primitives.FieldPushbutton > 0 { + return nil + } + v := types.Name("Off") if s, found := d.Find("DV"); found { v = s.(types.Name) @@ -350,7 +356,9 @@ func collectBtn(xRefTable *model.XRefTable, d types.Dict, f *Field, fm *FieldMet } if len(d.ArrayEntry("Kids")) > 0 { - return collectRadioButtonGroup(xRefTable, d, f, fm) + if ff != nil && primitives.FieldFlags(*ff)&primitives.FieldRadio > 0 { + return collectRadioButtonGroup(xRefTable, d, f, fm) + } } f.typ = FTCheckBox @@ -1159,6 +1167,12 @@ func RemoveFormFields(ctx *model.Context, fieldIDsOrNames []string) (bool, error } func resetBtn(xRefTable *model.XRefTable, d types.Dict) error { + + ff := d.IntEntry("Ff") + if ff != nil && primitives.FieldFlags(*ff)&primitives.FieldPushbutton > 0 { + return nil + } + v := types.Name("Off") if s, found := d.Find("DV"); found { v = s.(types.Name) diff --git a/pkg/pdfcpu/primitives/font.go b/pkg/pdfcpu/primitives/font.go index 4ed980c9..3e3443b9 100644 --- a/pkg/pdfcpu/primitives/font.go +++ b/pkg/pdfcpu/primitives/font.go @@ -314,7 +314,11 @@ func fontFromAcroDict(xRefTable *model.XRefTable, fName, fLang *string, fontID s return err } - *fName, *fLang = *fN, *fL + *fName = *fN + + if fL != nil { + *fLang = *fL + } return err } diff --git a/pkg/pdfcpu/validate/action.go b/pkg/pdfcpu/validate/action.go index ab03c6b0..e8dead7f 100644 --- a/pkg/pdfcpu/validate/action.go +++ b/pkg/pdfcpu/validate/action.go @@ -566,7 +566,7 @@ func validateNamedActionDict(xRefTable *model.XRefTable, d types.Dict, dictName } // Some known non standard named actions - if types.MemberOf(s, []string{"GoToPage", "GoBack", "GoForward", "Find", "Print", "Quit", "FullScreen"}) { + if types.MemberOf(s, []string{"GoToPage", "GoBack", "GoForward", "Find", "Print", "SaveAs", "Quit", "FullScreen"}) { return true } diff --git a/pkg/pdfcpu/validate/annotation.go b/pkg/pdfcpu/validate/annotation.go index 25c548e0..ac337107 100644 --- a/pkg/pdfcpu/validate/annotation.go +++ b/pkg/pdfcpu/validate/annotation.go @@ -1357,8 +1357,31 @@ func validateAppearDictEntry(xRefTable *model.XRefTable, d types.Dict, dictName return err } -func validateBorderArrayLength(a types.Array) bool { - return len(a) == 0 || len(a) == 3 || len(a) == 4 +func validateBorderArray(xRefTable *model.XRefTable, a types.Array) bool { + if len(a) == 0 { + return true + } + if len(a) == 1 || len(a) == 2 || len(a) > 4 { + return false + } + if len(a) == 3 { + _, err := validateNumberArray(xRefTable, a) + return err == nil + } + + // len = 4 + + o := a[3] + a1, ok := o.(types.Array) + if !ok { + return false + } + if len(a1) != 2 { + return false + } + + _, err := validateNumberArray(xRefTable, a1) + return err == nil } func validateAnnotationDictGeneral(xRefTable *model.XRefTable, d types.Dict, dictName string) (*types.Name, error) { @@ -1424,10 +1447,13 @@ func validateAnnotationDictGeneral(xRefTable *model.XRefTable, d types.Dict, dic } // Border, optional, array of numbers - _, err = validateNumberArrayEntry(xRefTable, d, dictName, "Border", OPTIONAL, model.V10, validateBorderArrayLength) + a, err := validateArrayEntry(xRefTable, d, dictName, "Border", OPTIONAL, model.V10, nil) if err != nil { return nil, err } + if !validateBorderArray(xRefTable, a) { + return nil, errors.Errorf("invalid border array: %s", a) + } // C, optional array, of numbers, since V1.1 _, err = validateNumberArrayEntry(xRefTable, d, dictName, "C", OPTIONAL, model.V11, nil)