From 8f22f14c3dd882fee36550065736f74069afd1a8 Mon Sep 17 00:00:00 2001 From: Bradley Hilton Date: Mon, 10 May 2021 19:33:32 -0500 Subject: [PATCH 1/3] Parse the fields from pdftk dump_data_fields --- getfields.go | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++ sample/main.go | 7 +++++ utils.go | 13 ++++++++ 3 files changed, 103 insertions(+) create mode 100644 getfields.go diff --git a/getfields.go b/getfields.go new file mode 100644 index 0000000..f148110 --- /dev/null +++ b/getfields.go @@ -0,0 +1,83 @@ +package fillpdf + +import ( + "fmt" + "os/exec" + "path/filepath" + "strings" +) + +// Field contains information about the fields exported from a pdf via pdftk +type Field struct { + Type string + Name string + AltName string + Flags string +} + +func GetFields(formPDFFile string) ([]Field, error) { + formPDFFile, err := filepath.Abs(formPDFFile) + if err != nil { + return nil, fmt.Errorf("failed to create the absolute path: %v", err) + } + + // Check if the form file exists. + e, err := exists(formPDFFile) + if err != nil { + return nil, fmt.Errorf("failed to check if form PDF file exists: %v", err) + } else if !e { + return nil, fmt.Errorf("form PDF file does not exists: '%s'", formPDFFile) + } + + // Check if the pdftk utility exists. + _, err = exec.LookPath("pdftk") + if err != nil { + return nil, fmt.Errorf("pdftk utility is not installed") + } + + // Create the pdftk command line arguments. + args := []string{ + formPDFFile, + "dump_data_fields", + } + + output, err := runCommandWithResults("pdftk", args...) + if err != nil { + return nil, fmt.Errorf("pdftk error: %v", err) + } + + fieldsData := strings.Split(output, "---\n") + + fields := []Field{} + for _, f := range fieldsData { + lines := strings.Split(f, "\n") + if len(lines) <= 2 { + continue + } + + field := Field{} + + for _, line := range lines { + props := strings.Split(line, ": ") + + if len(props) != 2 { + continue + } + + switch props[0] { + case "FieldType": + field.Type = strings.ToLower(props[1]) + case "FieldName": + field.Name = props[1] + case "FieldNameAlt": + field.AltName = props[1] + case "FieldFlags": + field.Flags = props[1] + } + } + + fields = append(fields, field) + } + + return fields, nil +} diff --git a/sample/main.go b/sample/main.go index 0e2d258..57a6f90 100644 --- a/sample/main.go +++ b/sample/main.go @@ -18,4 +18,11 @@ func main() { if err != nil { log.Fatal(err) } + + fields, err := fillpdf.GetFields("form.pdf") + if err != nil { + log.Fatal(err) + } + + log.Printf("%+v", fields) } diff --git a/utils.go b/utils.go index 7ca645c..a8e8585 100644 --- a/utils.go +++ b/utils.go @@ -84,3 +84,16 @@ func runCommandInPath(dir, name string, args ...string) error { return nil } + +func runCommandWithResults(name string, args ...string) (string, error) { + var stderr bytes.Buffer + cmd := exec.Command(name, args...) + cmd.Stderr = &stderr + + out, err := cmd.Output() + if err != nil { + return "", fmt.Errorf(strings.TrimSpace(stderr.String())) + } + + return string(out), nil +} From 28b3c74112cffe716de7bbd876110e020796e64d Mon Sep 17 00:00:00 2001 From: Bradley Hilton Date: Mon, 10 May 2021 19:57:46 -0500 Subject: [PATCH 2/3] Only split the field properties once based on the colon and space --- getfields.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/getfields.go b/getfields.go index f148110..4951968 100644 --- a/getfields.go +++ b/getfields.go @@ -58,7 +58,7 @@ func GetFields(formPDFFile string) ([]Field, error) { field := Field{} for _, line := range lines { - props := strings.Split(line, ": ") + props := strings.SplitN(line, ": ", 1) if len(props) != 2 { continue From 79bfa0c6e9646c0c2965e3f7b7cc82d0c370fec1 Mon Sep 17 00:00:00 2001 From: Bradley Hilton Date: Mon, 10 May 2021 20:00:28 -0500 Subject: [PATCH 3/3] Fix the previous commit to expect 2 substrings instead of only 1 --- getfields.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/getfields.go b/getfields.go index 4951968..1fd7f59 100644 --- a/getfields.go +++ b/getfields.go @@ -58,7 +58,7 @@ func GetFields(formPDFFile string) ([]Field, error) { field := Field{} for _, line := range lines { - props := strings.SplitN(line, ": ", 1) + props := strings.SplitN(line, ": ", 2) if len(props) != 2 { continue