Repository: dotemacs/pdfboxing
Pull request #6 (2015-04-04 19:41:52)

Common namespace added
Added the functionality as prompted by @nukecoder in https://github.com/dotemacs/pdfboxing/pull/3.

Added a pre PDF reading in check to see if the file supplied really is a PDF.


Patch:
diff --git a/project.clj b/project.clj
index 1cb758f..7eaee88 100644
--- a/project.clj
+++ b/project.clj
@@ -1,7 +1,8 @@
-(defproject pdfboxing "0.1.3"
+(defproject pdfboxing "0.1.4"
   :description "Clojure PDF manipulation library & wrapper for PDFBox"
   :url "https://github.com/dotemacs/pdfboxing"
   :license {:name "BSD"
             :url "http://www.opensource.org/licenses/bsd-license.php"}
   :dependencies [[org.clojure/clojure "1.5.1"]
-                 [org.apache.pdfbox/pdfbox "1.8.3"]])
+                 [org.apache.pdfbox/pdfbox "1.8.3"]
+                 [org.apache.pdfbox/preflight "1.8.3"]])
diff --git a/resources/log4j.properties b/resources/log4j.properties
new file mode 100644
index 0000000..bbe8cda
--- /dev/null
+++ b/resources/log4j.properties
@@ -0,0 +1,2 @@
+# turn off logging
+log4j.rootLogger=OFF
diff --git a/src/pdfboxing/common.clj b/src/pdfboxing/common.clj
new file mode 100644
index 0000000..4df98d9
--- /dev/null
+++ b/src/pdfboxing/common.clj
@@ -0,0 +1,25 @@
+(ns pdfboxing.common
+  (:import
+   [javax.activation FileDataSource]
+   [org.apache.pdfbox.pdmodel PDDocument]
+   [org.apache.pdfbox.preflight.parser PreflightParser]))
+
+
+(defn is-pdf?
+  "Confirm that the PDF supplied is really a PDF"
+  [pdf-file]
+  (let [data-source (FileDataSource. pdf-file)
+        parser (PreflightParser. data-source)]
+    (try
+      (do
+        (.parse parser)
+        true)
+      (catch Exception e false))))
+
+
+(defn load-pdf
+  "Load a given PDF only after checking if it really is a PDF"
+  [pdf-file]
+  (if (is-pdf? pdf-file)
+    (PDDocument/load pdf-file)
+    (throw (IllegalArgumentException. (format "%s is not a PDF file" pdf-file)))))
diff --git a/src/pdfboxing/form.clj b/src/pdfboxing/form.clj
index 035d882..78c7098 100644
--- a/src/pdfboxing/form.clj
+++ b/src/pdfboxing/form.clj
@@ -1,14 +1,15 @@
 (ns pdfboxing.form
+  (:require [pdfboxing.common :as common])
   (:import
-    [org.apache.pdfbox.pdmodel PDDocument PDDocumentCatalog]
-    [org.apache.pdfbox.pdmodel.common COSObjectable]
-    [org.apache.pdfbox.pdmodel.interactive.form PDAcroForm PDAppearance PDField PDSignatureField]
-    [java.io IOException]))
+   [org.apache.pdfbox.pdmodel PDDocumentCatalog]
+   [org.apache.pdfbox.pdmodel.common COSObjectable]
+   [org.apache.pdfbox.pdmodel.interactive.form PDAcroForm PDAppearance PDField PDSignatureField]
+   [java.io IOException]))
 
 (defn get-fields
   "get all the field names and their values from a PDF document"
   [pdfdoc]
-  (with-open [doc (PDDocument/load pdfdoc)]
+  (with-open [doc (common/load-pdf pdfdoc)]
     (let [catalog (.getDocumentCatalog doc)
           form (.getAcroForm catalog)
           fields (.getFields form)]
@@ -17,7 +18,7 @@
 (defn set-fields
   "fill in the fields with the values provided"
   [input output new-fields]
-  (with-open [doc (PDDocument/load input)]
+  (with-open [doc (common/load-pdf input)]
     (let [catalog (.getDocumentCatalog doc)
           form (.getAcroForm catalog)]
       (try
@@ -35,7 +36,7 @@
   the current form field names and values as the new names, and rename
   them"
   [input output fields-map]
-  (with-open [doc (PDDocument/load input)]
+  (with-open [doc (common/load-pdf input)]
     (let [catalog (.getDocumentCatalog doc)
           form (.getAcroForm catalog)]
       (doseq [field fields-map]
diff --git a/src/pdfboxing/info.clj b/src/pdfboxing/info.clj
index 0eebc4b..4ad5df6 100644
--- a/src/pdfboxing/info.clj
+++ b/src/pdfboxing/info.clj
@@ -1,13 +1,13 @@
 (ns pdfboxing.info
-  (:require [clojure.string :as string])
-  (:import
-   [clojure.lang Reflector]
-   [org.apache.pdfbox.pdmodel PDDocument PDDocumentCatalog PDDocumentInformation]))
+  (:require [clojure.string :as string]
+            [pdfboxing.common :as common])
+  (:import [clojure.lang Reflector]
+           [org.apache.pdfbox.pdmodel PDDocumentCatalog PDDocumentInformation]))
 
 (defn page-number
   "return number of pages of a PDF document"
   [pdfdoc]
-  (with-open [doc (PDDocument/load pdfdoc)]
+  (with-open [doc (common/load-pdf pdfdoc)]
     (.getNumberOfPages doc)))
 
 
@@ -22,7 +22,7 @@
    the values provided are for the fields defined by
    info-fields"
   [pdfdoc]
-  (with-open [doc (PDDocument/load pdfdoc)]
+  (with-open [doc (common/load-pdf pdfdoc)]
     (let [info (.getDocumentInformation doc)
           info-fields ["title" "author" "subject" "keywords" "creator" "producer"]]
       (into {}
diff --git a/src/pdfboxing/merge.clj b/src/pdfboxing/merge.clj
index 8164360..8ebe012 100644
--- a/src/pdfboxing/merge.clj
+++ b/src/pdfboxing/merge.clj
@@ -1,15 +1,30 @@
 (ns pdfboxing.merge
+  (:require [pdfboxing.common :as common])
   (:import [org.apache.pdfbox.util PDFMergerUtility]
            [java.io File FileInputStream]))
 
+(defn throw-exception
+  [message]
+  (throw (IllegalArgumentException. message)))
+
+(defn check-if-present
+  "Check if the input & output file names where supplied"
+  [input output]
+  (if (some true? (map empty? [input output]))
+    (throw-exception "argument can't be empty")))
+
+(defn check-for-pdfs
+  "Check if all the files supplied are actual PDFs."
+  [files]
+  (if (some false? (map common/is-pdf? files))
+    (throw-exception "the files supplied need to be PDFs")
+    true))
+
 (defn arg-check [output input]
-  (if (empty? output)
-    (throw (IllegalArgumentException. "output - required argument"))
-    (if (empty? input)
-      (throw (IllegalArgumentException. "input - required argument"))
-      (if (sequential? input)
-        true
-        (throw (IllegalArgumentException. "input - needs to be sequential"))))))
+  (check-if-present input output)
+  (if (sequential? input)
+    (check-for-pdfs input)
+    (throw-exception "input - needs to be sequential")))
 
 (defn merge-pdfs
   "merge multiple PDFs into output file"
diff --git a/src/pdfboxing/text.clj b/src/pdfboxing/text.clj
index 5ed0fad..731de74 100644
--- a/src/pdfboxing/text.clj
+++ b/src/pdfboxing/text.clj
@@ -1,10 +1,10 @@
 (ns pdfboxing.text
-  (:import [org.apache.pdfbox.pdmodel PDDocument]
-           [org.apache.pdfbox.util PDFTextStripper]))
+  (:require [pdfboxing.common :as common])
+  (:import [org.apache.pdfbox.util PDFTextStripper]))
 
 (defn extract
   "get text from a PDF document"
   [pdfdoc]
-  (with-open [doc (PDDocument/load pdfdoc)]
+  (with-open [doc (common/load-pdf pdfdoc)]
     (let [stripper (new PDFTextStripper)]
       (.getText stripper doc))))


Test patch:
diff --git a/test/pdfboxing/common_test.clj b/test/pdfboxing/common_test.clj
new file mode 100644
index 0000000..b98493f
--- /dev/null
+++ b/test/pdfboxing/common_test.clj
@@ -0,0 +1,8 @@
+(ns pdfboxing.common-test
+  (:require [clojure.test :refer :all]
+            [pdfboxing.common :refer :all]))
+
+(deftest pdf-existance-check
+  (testing "If document supplied is a PDF"
+    (is (false? (is-pdf? "test/pdfs/a.txt")))
+    (is (true? (is-pdf? "test/pdfs/hello.pdf")))))
diff --git a/test/pdfboxing/merge_test.clj b/test/pdfboxing/merge_test.clj
index f2ccf33..727af78 100644
--- a/test/pdfboxing/merge_test.clj
+++ b/test/pdfboxing/merge_test.clj
@@ -1,13 +1,14 @@
 (ns pdfboxing.merge-test
   (:require [clojure.test :refer :all]
             [clojure.java.io :as io]
-            [pdfboxing.merge :refer :all]))
+            [pdfboxing.merge :refer :all]
+            [pdfboxing.common :as common]))
 
 (deftest input-output-argument-check
   (is (thrown? IllegalArgumentException (arg-check)))
   (is (thrown? IllegalArgumentException (arg-check "input")))
   (is (thrown? IllegalArgumentException (arg-check "input" "output")))
-  (is (true? (arg-check "output" ["a.pdf" "b.pdf"]))))
+  (is (true? (arg-check "output" ["test/pdfs/clojure-1.pdf" "test/pdfs/clojure-2.pdf"]))))
 
 
 (deftest pdf-merge-exit-status
@@ -19,7 +20,8 @@
         merging-outcome (merge-pdfs :output file
                                     :input ["test/pdfs/clojure-1.pdf" "test/pdfs/clojure-2.pdf"])
         merged-pdf-file (.exists (io/as-file file))]
-    (is (true? merged-pdf-file))))
+    (is (true? merged-pdf-file))
+    (is (true? (common/is-pdf? file)))))
 
 ;; clean up
 (defn clean-up [file]