[poppler] 2 commits - poppler/Annot.cc poppler/Annot.h poppler/Catalog.cc poppler/Catalog.h poppler/Form.cc poppler/Form.h poppler/Page.cc poppler/Page.h utils/CMakeLists.txt utils/JSInfo.cc utils/JSInfo.h utils/Makefile.am utils/pdfinfo.1 utils/pdfinfo.cc
Adrian Johnson
ajohnson at kemper.freedesktop.org
Fri Aug 23 22:35:20 PDT 2013
poppler/Annot.cc | 27 +++++
poppler/Annot.h | 8 +
poppler/Catalog.cc | 26 +++++
poppler/Catalog.h | 13 ++
poppler/Form.cc | 4
poppler/Form.h | 2
poppler/Page.cc | 20 ++++
poppler/Page.h | 10 +-
utils/CMakeLists.txt | 4
utils/JSInfo.cc | 233 +++++++++++++++++++++++++++++++++++++++++++++++++++
utils/JSInfo.h | 60 +++++++++++++
utils/Makefile.am | 4
utils/pdfinfo.1 | 6 +
utils/pdfinfo.cc | 18 +++
14 files changed, 434 insertions(+), 1 deletion(-)
New commits:
commit a47b7f853174d6101f2b882a2db1a7dc95b33293
Author: Adrian Johnson <ajohnson at redneon.com>
Date: Sat Aug 3 10:28:20 2013 +0930
Add pdfinfo option to print out javascript
diff --git a/poppler/Catalog.h b/poppler/Catalog.h
index 0486bf0..eb1dd29 100644
--- a/poppler/Catalog.h
+++ b/poppler/Catalog.h
@@ -153,6 +153,7 @@ public:
// Get the number of javascript scripts
int numJS() { return getJSNameTree()->numEntries(); }
+ GooString *getJSName(int i) { return getJSNameTree()->getName(i); }
// Get the i'th JavaScript script (at the Document level) in the document
GooString *getJS(int i);
diff --git a/utils/JSInfo.cc b/utils/JSInfo.cc
index 6b66888..e3205c4 100644
--- a/utils/JSInfo.cc
+++ b/utils/JSInfo.cc
@@ -13,6 +13,7 @@
#include "config.h"
+#include <stdio.h>
#include "Object.h"
#include "Dict.h"
#include "Annot.h"
@@ -20,6 +21,8 @@
#include "JSInfo.h"
#include "Link.h"
#include "Form.h"
+#include "UnicodeMap.h"
+#include "UTF.h"
JSInfo::JSInfo(PDFDoc *docA, int firstPage) {
doc = docA;
@@ -29,23 +32,68 @@ JSInfo::JSInfo(PDFDoc *docA, int firstPage) {
JSInfo::~JSInfo() {
}
+void JSInfo::printJS(GooString *js) {
+ Unicode *u;
+ char buf[8];
+ int i, n, len;
-void JSInfo::scanLinkAction(LinkAction *link) {
+ if (!js || !js->getCString())
+ return;
+
+ len = TextStringToUCS4(js, &u);
+ for (i = 0; i < len; i++) {
+ n = uniMap->mapUnicode(u[i], buf, sizeof(buf));
+ fwrite(buf, 1, n, file);
+ }
+}
+
+void JSInfo::scanLinkAction(LinkAction *link, const char *action) {
if (!link)
return;
if (link->getKind() == actionJavaScript) {
hasJS = gTrue;
+ if (print) {
+ LinkJavaScript *linkjs = static_cast<LinkJavaScript *>(link);
+ GooString *s = linkjs->getScript();
+ if (s && s->getCString()) {
+ fprintf(file, "%s:\n", action);
+ printJS(s);
+ fputs("\n\n", file);
+ }
+ }
}
if (link->getKind() == actionRendition) {
LinkRendition *linkr = static_cast<LinkRendition *>(link);
- if (linkr->getScript())
+ if (linkr->getScript()) {
hasJS = gTrue;
+ if (print) {
+ GooString *s = linkr->getScript();
+ if (s && s->getCString()) {
+ fprintf(file, "%s (Rendition):\n", action);
+ printJS(s);
+ fputs("\n\n", file);
+ }
+ }
+ }
}
}
void JSInfo::scanJS(int nPages) {
+ print = gFalse;
+ file = NULL;
+ scan(nPages);
+}
+
+void JSInfo::scanJS(int nPages, FILE *fout, UnicodeMap *uMap) {
+ print = gTrue;
+ file = fout;
+ uniMap = uMap;
+ scan(nPages);
+}
+
+void JSInfo::scan(int nPages) {
Page *page;
Annots *annots;
Object obj1, obj2;
@@ -54,16 +102,29 @@ void JSInfo::scanJS(int nPages) {
hasJS = gFalse;
// Names
- if (doc->getCatalog()->numJS() > 0) {
+ int numNames = doc->getCatalog()->numJS();
+ if (numNames > 0) {
hasJS = gTrue;
+ if (print) {
+ for (int i = 0; i < numNames; i++) {
+ fprintf(file, "Name Dictionary \"%s\":\n", doc->getCatalog()->getJSName(i)->getCString());
+ printJS(doc->getCatalog()->getJS(i));
+ fputs("\n\n", file);
+ }
+ }
}
// document actions
- scanLinkAction(doc->getCatalog()->getAdditionalAction(Catalog::actionCloseDocument));
- scanLinkAction(doc->getCatalog()->getAdditionalAction(Catalog::actionSaveDocumentStart));
- scanLinkAction(doc->getCatalog()->getAdditionalAction(Catalog::actionSaveDocumentFinish));
- scanLinkAction(doc->getCatalog()->getAdditionalAction(Catalog::actionPrintDocumentStart));
- scanLinkAction(doc->getCatalog()->getAdditionalAction(Catalog::actionPrintDocumentFinish));
+ scanLinkAction(doc->getCatalog()->getAdditionalAction(Catalog::actionCloseDocument),
+ "Before Close Document");
+ scanLinkAction(doc->getCatalog()->getAdditionalAction(Catalog::actionSaveDocumentStart),
+ "Before Save Document");
+ scanLinkAction(doc->getCatalog()->getAdditionalAction(Catalog::actionSaveDocumentFinish),
+ "After Save Document");
+ scanLinkAction(doc->getCatalog()->getAdditionalAction(Catalog::actionPrintDocumentStart),
+ "Before Print Document");
+ scanLinkAction(doc->getCatalog()->getAdditionalAction(Catalog::actionPrintDocumentFinish),
+ "After Print Document");
// form field actions
if (doc->getCatalog()->getFormType() == Catalog::AcroForm) {
@@ -72,11 +133,16 @@ void JSInfo::scanJS(int nPages) {
FormField *field = form->getRootField(i);
for (int j = 0; j < field->getNumWidgets(); j++) {
FormWidget *widget = field->getWidget(j);
- scanLinkAction(widget->getActivationAction());
- scanLinkAction(widget->getAdditionalAction(Annot::actionFieldModified));
- scanLinkAction(widget->getAdditionalAction(Annot::actionFormatField));
- scanLinkAction(widget->getAdditionalAction(Annot::actionValidateField));
- scanLinkAction(widget->getAdditionalAction(Annot::actionCalculateField));
+ scanLinkAction(widget->getActivationAction(),
+ "Field Activated");
+ scanLinkAction(widget->getAdditionalAction(Annot::actionFieldModified),
+ "Field Modified");
+ scanLinkAction(widget->getAdditionalAction(Annot::actionFormatField),
+ "Format Field");
+ scanLinkAction(widget->getAdditionalAction(Annot::actionValidateField),
+ "Validate Field");
+ scanLinkAction(widget->getAdditionalAction(Annot::actionCalculateField),
+ "Calculate Field");
}
}
}
@@ -97,42 +163,64 @@ void JSInfo::scanJS(int nPages) {
if (!page) continue;
// page actions (open, close)
- scanLinkAction(page->getAdditionalAction(Page::actionOpenPage));
- scanLinkAction(page->getAdditionalAction(Page::actionClosePage));
+ scanLinkAction(page->getAdditionalAction(Page::actionOpenPage), "Page Open");
+ scanLinkAction(page->getAdditionalAction(Page::actionClosePage), "Page Close");
// annotation actions (links, screen, widget)
annots = page->getAnnots();
for (int i = 0; i < annots->getNumAnnots(); ++i) {
if (annots->getAnnot(i)->getType() == Annot::typeLink) {
AnnotLink *annot = static_cast<AnnotLink *>(annots->getAnnot(i));
- scanLinkAction(annot->getAction());
+ scanLinkAction(annot->getAction(), "Link Annotation Activated");
} else if (annots->getAnnot(i)->getType() == Annot::typeScreen) {
AnnotScreen *annot = static_cast<AnnotScreen *>(annots->getAnnot(i));
- scanLinkAction(annot->getAction());
- scanLinkAction(annot->getAdditionalAction(Annot::actionCursorEntering));
- scanLinkAction(annot->getAdditionalAction(Annot::actionCursorLeaving));
- scanLinkAction(annot->getAdditionalAction(Annot::actionMousePressed));
- scanLinkAction(annot->getAdditionalAction(Annot::actionMouseReleased));
- scanLinkAction(annot->getAdditionalAction(Annot::actionFocusIn));
- scanLinkAction(annot->getAdditionalAction(Annot::actionFocusOut));
- scanLinkAction(annot->getAdditionalAction(Annot::actionPageOpening));
- scanLinkAction(annot->getAdditionalAction(Annot::actionPageClosing));
- scanLinkAction(annot->getAdditionalAction(Annot::actionPageVisible));
- scanLinkAction(annot->getAdditionalAction(Annot::actionPageVisible));
+ scanLinkAction(annot->getAction(),
+ "Screen Annotation Activated");
+ scanLinkAction(annot->getAdditionalAction(Annot::actionCursorEntering),
+ "Screen Annotation Cursor Enter");
+ scanLinkAction(annot->getAdditionalAction(Annot::actionCursorLeaving),
+ "Screen Annotation Cursor Leave");
+ scanLinkAction(annot->getAdditionalAction(Annot::actionMousePressed),
+ "Screen Annotation Mouse Pressed");
+ scanLinkAction(annot->getAdditionalAction(Annot::actionMouseReleased),
+ "Screen Annotation Mouse Released");
+ scanLinkAction(annot->getAdditionalAction(Annot::actionFocusIn),
+ "Screen Annotation Focus In");
+ scanLinkAction(annot->getAdditionalAction(Annot::actionFocusOut),
+ "Screen Annotation Focus Out");
+ scanLinkAction(annot->getAdditionalAction(Annot::actionPageOpening),
+ "Screen Annotation Page Open");
+ scanLinkAction(annot->getAdditionalAction(Annot::actionPageClosing),
+ "Screen Annotation Page Close");
+ scanLinkAction(annot->getAdditionalAction(Annot::actionPageVisible),
+ "Screen Annotation Page Visible");
+ scanLinkAction(annot->getAdditionalAction(Annot::actionPageInvisible),
+ "Screen Annotation Page Invisible");
} else if (annots->getAnnot(i)->getType() == Annot::typeWidget) {
AnnotWidget *annot = static_cast<AnnotWidget *>(annots->getAnnot(i));
- scanLinkAction(annot->getAction());
- scanLinkAction(annot->getAdditionalAction(Annot::actionCursorEntering));
- scanLinkAction(annot->getAdditionalAction(Annot::actionCursorLeaving));
- scanLinkAction(annot->getAdditionalAction(Annot::actionMousePressed));
- scanLinkAction(annot->getAdditionalAction(Annot::actionMouseReleased));
- scanLinkAction(annot->getAdditionalAction(Annot::actionFocusIn));
- scanLinkAction(annot->getAdditionalAction(Annot::actionFocusOut));
- scanLinkAction(annot->getAdditionalAction(Annot::actionPageOpening));
- scanLinkAction(annot->getAdditionalAction(Annot::actionPageClosing));
- scanLinkAction(annot->getAdditionalAction(Annot::actionPageVisible));
- scanLinkAction(annot->getAdditionalAction(Annot::actionPageVisible));
+ scanLinkAction(annot->getAction(),
+ "Widget Annotation Activated");
+ scanLinkAction(annot->getAdditionalAction(Annot::actionCursorEntering),
+ "Widget Annotation Cursor Enter");
+ scanLinkAction(annot->getAdditionalAction(Annot::actionCursorLeaving),
+ "Widget Annotation Cursor Leave");
+ scanLinkAction(annot->getAdditionalAction(Annot::actionMousePressed),
+ "Widget Annotation Mouse Pressed");
+ scanLinkAction(annot->getAdditionalAction(Annot::actionMouseReleased),
+ "Widget Annotation Mouse Released");
+ scanLinkAction(annot->getAdditionalAction(Annot::actionFocusIn),
+ "Widget Annotation Focus In");
+ scanLinkAction(annot->getAdditionalAction(Annot::actionFocusOut),
+ "Widget Annotation Focus Out");
+ scanLinkAction(annot->getAdditionalAction(Annot::actionPageOpening),
+ "Widget Annotation Page Open");
+ scanLinkAction(annot->getAdditionalAction(Annot::actionPageClosing),
+ "Widget Annotation Page Close");
+ scanLinkAction(annot->getAdditionalAction(Annot::actionPageVisible),
+ "Widget Annotation Page Visible");
+ scanLinkAction(annot->getAdditionalAction(Annot::actionPageInvisible),
+ "Widget Annotation Page Invisible");
}
}
}
diff --git a/utils/JSInfo.h b/utils/JSInfo.h
index fed3f68..19b786f 100644
--- a/utils/JSInfo.h
+++ b/utils/JSInfo.h
@@ -14,11 +14,13 @@
#ifndef JS_INFO_H
#define JS_INFO_H
+#include <stdio.h>
#include "Object.h"
#include "PDFDoc.h"
#include "goo/gtypes.h"
#include "Link.h"
+#include "UnicodeMap.h"
class PDFDoc;
@@ -34,6 +36,9 @@ public:
// scan for JS in the PDF
void scanJS(int nPages);
+ // scan and print JS in the PDF
+ void scanJS(int nPages, FILE *fout, UnicodeMap *uMap);
+
// return true if PDF contains JavaScript
GBool containsJS();
@@ -42,8 +47,13 @@ private:
PDFDoc *doc;
int currentPage;
GBool hasJS;
+ GBool print;
+ FILE *file;
+ UnicodeMap *uniMap;
- void scanLinkAction(LinkAction *link);
+ void scan(int nPages);
+ void scanLinkAction(LinkAction *link, const char *action);
+ void printJS(GooString *js);
};
diff --git a/utils/pdfinfo.1 b/utils/pdfinfo.1
index 134bd3f..1dd7466 100644
--- a/utils/pdfinfo.1
+++ b/utils/pdfinfo.1
@@ -93,6 +93,9 @@ TrimBox, and ArtBox.
Prints document-level metadata. (This is the "Metadata" stream from
the PDF file's Catalog object.)
.TP
++.B \-js
++Prints all JavaScript in the PDF.
++.TP
.B \-rawdates
Prints the raw (undecoded) date strings, directly from the PDF file.
.TP
diff --git a/utils/pdfinfo.cc b/utils/pdfinfo.cc
index 902200f..0927855 100644
--- a/utils/pdfinfo.cc
+++ b/utils/pdfinfo.cc
@@ -64,6 +64,7 @@ static int firstPage = 1;
static int lastPage = 0;
static GBool printBoxes = gFalse;
static GBool printMetadata = gFalse;
+static GBool printJS = gFalse;
static GBool rawDates = gFalse;
static char textEncName[128] = "";
static char ownerPassword[33] = "\001";
@@ -81,6 +82,8 @@ static const ArgDesc argDesc[] = {
"print the page bounding boxes"},
{"-meta", argFlag, &printMetadata, 0,
"print the document metadata (XML)"},
+ {"-js", argFlag, &printJS, 0,
+ "print all JavaScript in the PDF"},
{"-rawdates", argFlag, &rawDates, 0,
"print the undecoded date strings directly from the PDF file"},
{"-enc", argString, textEncName, sizeof(textEncName),
@@ -383,6 +386,13 @@ int main(int argc, char *argv[]) {
delete metadata;
}
+ // print javascript
+ if (printJS) {
+ JSInfo jsInfo(doc, firstPage - 1);
+ fputs("\n", stdout);
+ jsInfo.scanJS(lastPage - firstPage + 1, stdout, uMap);
+ }
+
exitCode = 0;
// clean up
commit 8f7155e7e3180bb1966a5e7df6af6acdd479939b
Author: Adrian Johnson <ajohnson at redneon.com>
Date: Sat Aug 3 09:05:21 2013 +0930
pdfinfo: indicate if pdf contains javascript
diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 00291f8..bbe1e36 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -234,6 +234,28 @@ static LinkAction* getAdditionalAction(Annot::AdditionalActionsType type, Object
return linkAction;
}
+static LinkAction* getFormAdditionalAction(Annot::FormAdditionalActionsType type, Object *additionalActions, PDFDoc *doc) {
+ Object additionalActionsObject;
+ LinkAction *linkAction = NULL;
+
+ if (additionalActions->fetch(doc->getXRef(), &additionalActionsObject)->isDict()) {
+ const char *key = (type == Annot::actionFieldModified ? "K" :
+ type == Annot::actionFormatField ? "F" :
+ type == Annot::actionValidateField ? "V" :
+ type == Annot::actionCalculateField ? "C" : NULL);
+
+ Object actionObject;
+
+ if (additionalActionsObject.dictLookup(key, &actionObject)->isDict())
+ linkAction = LinkAction::parseAction(&actionObject, doc->getCatalog()->getBaseURI());
+ actionObject.free();
+ }
+
+ additionalActionsObject.free();
+
+ return linkAction;
+}
+
//------------------------------------------------------------------------
// AnnotBorderEffect
//------------------------------------------------------------------------
@@ -3911,6 +3933,11 @@ LinkAction* AnnotWidget::getAdditionalAction(AdditionalActionsType type)
return ::getAdditionalAction(type, &additionalActions, doc);
}
+LinkAction* AnnotWidget::getFormAdditionalAction(FormAdditionalActionsType type)
+{
+ return ::getFormAdditionalAction(type, &additionalActions, doc);
+}
+
// Grand unified handler for preparing text strings to be drawn into form
// fields. Takes as input a text string (in PDFDocEncoding or UTF-16).
// Converts some or all of this string to the appropriate encoding for the
diff --git a/poppler/Annot.h b/poppler/Annot.h
index 2865d23..ef2b1d0 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -536,6 +536,13 @@ public:
actionPageInvisible ///< Performed when the page containing the annotation becomes invisible
};
+ enum FormAdditionalActionsType {
+ actionFieldModified, ///< Performed when the when the user modifies the field
+ actionFormatField, ///< Performed before the field is formatted to display its value
+ actionValidateField, ///< Performed when the field value changes
+ actionCalculateField, ///< Performed when the field needs to be recalculated
+ };
+
Annot(PDFDoc *docA, PDFRectangle *rectA);
Annot(PDFDoc *docA, Dict *dict);
Annot(PDFDoc *docA, Dict *dict, Object *obj);
@@ -1305,6 +1312,7 @@ public:
AnnotAppearanceCharacs *getAppearCharacs() { return appearCharacs; }
LinkAction *getAction() { return action; }
LinkAction *getAdditionalAction(AdditionalActionsType type);
+ LinkAction *getFormAdditionalAction(FormAdditionalActionsType type);
Dict *getParent() { return parent; }
private:
diff --git a/poppler/Catalog.cc b/poppler/Catalog.cc
index 25a8997..beb74c3 100644
--- a/poppler/Catalog.cc
+++ b/poppler/Catalog.cc
@@ -126,6 +126,9 @@ Catalog::Catalog(PDFDoc *docA) {
}
optContentProps.free();
+ // actions
+ catDict.dictLookupNF("AA", &additionalActions);
+
// get the ViewerPreferences dictionary
catDict.dictLookup("ViewerPreferences", &viewerPreferences);
catDict.free();
@@ -181,6 +184,7 @@ Catalog::~Catalog() {
outline.free();
acroForm.free();
viewerPreferences.free();
+ additionalActions.free();
#if MULTITHREADED
gDestroyMutex(&mutex);
#endif
@@ -1062,3 +1066,25 @@ NameTree *Catalog::getJSNameTree()
return jsNameTree;
}
+LinkAction* Catalog::getAdditionalAction(DocumentAdditionalActionsType type) {
+ Object additionalActionsObject;
+ LinkAction *linkAction = NULL;
+
+ if (additionalActions.fetch(doc->getXRef(), &additionalActionsObject)->isDict()) {
+ const char *key = (type == actionCloseDocument ? "WC" :
+ type == actionSaveDocumentStart ? "WS" :
+ type == actionSaveDocumentFinish ? "DS" :
+ type == actionPrintDocumentStart ? "WP" :
+ type == actionPrintDocumentFinish ? "DP" : NULL);
+
+ Object actionObject;
+
+ if (additionalActionsObject.dictLookup(key, &actionObject)->isDict())
+ linkAction = LinkAction::parseAction(&actionObject, doc->getCatalog()->getBaseURI());
+ actionObject.free();
+ }
+
+ additionalActionsObject.free();
+
+ return linkAction;
+}
diff --git a/poppler/Catalog.h b/poppler/Catalog.h
index a89d9aa..0486bf0 100644
--- a/poppler/Catalog.h
+++ b/poppler/Catalog.h
@@ -48,6 +48,7 @@ class Page;
class PageAttrs;
struct Ref;
class LinkDest;
+class LinkAction;
class PageLabelInfo;
class Form;
class OCGs;
@@ -202,6 +203,16 @@ public:
PageMode getPageMode();
PageLayout getPageLayout();
+ enum DocumentAdditionalActionsType {
+ actionCloseDocument, ///< Performed before closing the document
+ actionSaveDocumentStart, ///< Performed before saving the document
+ actionSaveDocumentFinish, ///< Performed after saving the document
+ actionPrintDocumentStart, ///< Performed before printing the document
+ actionPrintDocumentFinish, ///< Performed after printing the document
+ };
+
+ LinkAction *getAdditionalAction(DocumentAdditionalActionsType type);
+
private:
// Get page label info.
@@ -237,6 +248,7 @@ private:
PageLabelInfo *pageLabelInfo; // info about page labels
PageMode pageMode; // page mode
PageLayout pageLayout; // page layout
+ Object additionalActions; // page additional actions
GBool cachePageTree(int page); // Cache first <page> pages.
Object *findDestInTree(Object *tree, GooString *name, Object *obj);
diff --git a/poppler/Form.cc b/poppler/Form.cc
index 78c25e3..3070927 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -156,6 +156,10 @@ LinkAction *FormWidget::getActivationAction() {
return widget ? widget->getAction() : NULL;
}
+LinkAction *FormWidget::getAdditionalAction(Annot::FormAdditionalActionsType type) {
+ return widget ? widget->getFormAdditionalAction(type) : NULL;
+}
+
FormWidgetButton::FormWidgetButton (PDFDoc *docA, Object *aobj, unsigned num, Ref ref, FormField *p) :
FormWidget(docA, aobj, num, ref, p)
{
diff --git a/poppler/Form.h b/poppler/Form.h
index ef67748..6cc54a9 100644
--- a/poppler/Form.h
+++ b/poppler/Form.h
@@ -21,6 +21,7 @@
#endif
#include "Object.h"
+#include "Annot.h"
#include <set>
@@ -101,6 +102,7 @@ public:
bool isReadOnly() const;
LinkAction *getActivationAction();
+ LinkAction *getAdditionalAction(Annot::FormAdditionalActionsType type);
// return the unique ID corresponding to pageNum/fieldNum
static int encodeID (unsigned pageNum, unsigned fieldNum);
diff --git a/poppler/Page.cc b/poppler/Page.cc
index e0a3b29..7825f80 100644
--- a/poppler/Page.cc
+++ b/poppler/Page.cc
@@ -823,3 +823,23 @@ void Page::getDefaultCTM(double *ctm, double hDPI, double vDPI,
}
delete state;
}
+
+LinkAction* Page::getAdditionalAction(PageAdditionalActionsType type) {
+ Object additionalActionsObject;
+ LinkAction *linkAction = NULL;
+
+ if (actions.fetch(doc->getXRef(), &additionalActionsObject)->isDict()) {
+ const char *key = (type == actionOpenPage ? "O" :
+ type == actionClosePage ? "C" : NULL);
+
+ Object actionObject;
+
+ if (additionalActionsObject.dictLookup(key, &actionObject)->isDict())
+ linkAction = LinkAction::parseAction(&actionObject, doc->getCatalog()->getBaseURI());
+ actionObject.free();
+ }
+
+ additionalActionsObject.free();
+
+ return linkAction;
+}
diff --git a/poppler/Page.h b/poppler/Page.h
index 1c9d0a9..95adf3a 100644
--- a/poppler/Page.h
+++ b/poppler/Page.h
@@ -44,6 +44,7 @@ class PDFDoc;
class XRef;
class OutputDev;
class Links;
+class LinkAction;
class Annots;
class Annot;
class Gfx;
@@ -211,6 +212,13 @@ public:
// Get actions
Object *getActions(Object *obj) { return actions.fetch(xref, obj); }
+ enum PageAdditionalActionsType {
+ actionOpenPage, ///< Performed when opening the page
+ actionClosePage, ///< Performed when closing the page
+ };
+
+ LinkAction *getAdditionalAction(PageAdditionalActionsType type);
+
Gfx *createGfx(OutputDev *out, double hDPI, double vDPI,
int rotate, GBool useMediaBox, GBool crop,
int sliceX, int sliceY, int sliceW, int sliceH,
@@ -267,7 +275,7 @@ private:
Object contents; // page contents
Object thumb; // page thumbnail
Object trans; // page transition
- Object actions; // page addiction actions
+ Object actions; // page additional actions
double duration; // page duration
GBool ok; // true if page is valid
#if MULTITHREADED
diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt
index f82cfa4..2f04b39 100644
--- a/utils/CMakeLists.txt
+++ b/utils/CMakeLists.txt
@@ -69,6 +69,8 @@ set(pdfimages_SOURCES ${common_srcs}
pdfimages.cc
ImageOutputDev.cc
ImageOutputDev.h
+ JSInfo.cc
+ JSInfo.h
)
add_executable(pdfimages ${pdfimages_SOURCES})
target_link_libraries(pdfimages ${common_libs})
@@ -78,6 +80,8 @@ install(FILES pdfimages.1 DESTINATION share/man/man1)
# pdfinfo
set(pdfinfo_SOURCES ${common_srcs}
pdfinfo.cc printencodings.cc
+ JSInfo.cc
+ JSInfo.h
)
add_executable(pdfinfo ${pdfinfo_SOURCES})
target_link_libraries(pdfinfo ${common_libs})
diff --git a/utils/JSInfo.cc b/utils/JSInfo.cc
new file mode 100644
index 0000000..6b66888
--- /dev/null
+++ b/utils/JSInfo.cc
@@ -0,0 +1,145 @@
+//========================================================================
+//
+// JSInfo.cc
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright (C) 2013 Adrian Johnson <ajohnson at redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+
+#include "config.h"
+#include "Object.h"
+#include "Dict.h"
+#include "Annot.h"
+#include "PDFDoc.h"
+#include "JSInfo.h"
+#include "Link.h"
+#include "Form.h"
+
+JSInfo::JSInfo(PDFDoc *docA, int firstPage) {
+ doc = docA;
+ currentPage = firstPage + 1;
+}
+
+JSInfo::~JSInfo() {
+}
+
+
+void JSInfo::scanLinkAction(LinkAction *link) {
+ if (!link)
+ return;
+
+ if (link->getKind() == actionJavaScript) {
+ hasJS = gTrue;
+ }
+
+ if (link->getKind() == actionRendition) {
+ LinkRendition *linkr = static_cast<LinkRendition *>(link);
+ if (linkr->getScript())
+ hasJS = gTrue;
+ }
+}
+
+void JSInfo::scanJS(int nPages) {
+ Page *page;
+ Annots *annots;
+ Object obj1, obj2;
+ int lastPage;
+
+ hasJS = gFalse;
+
+ // Names
+ if (doc->getCatalog()->numJS() > 0) {
+ hasJS = gTrue;
+ }
+
+ // document actions
+ scanLinkAction(doc->getCatalog()->getAdditionalAction(Catalog::actionCloseDocument));
+ scanLinkAction(doc->getCatalog()->getAdditionalAction(Catalog::actionSaveDocumentStart));
+ scanLinkAction(doc->getCatalog()->getAdditionalAction(Catalog::actionSaveDocumentFinish));
+ scanLinkAction(doc->getCatalog()->getAdditionalAction(Catalog::actionPrintDocumentStart));
+ scanLinkAction(doc->getCatalog()->getAdditionalAction(Catalog::actionPrintDocumentFinish));
+
+ // form field actions
+ if (doc->getCatalog()->getFormType() == Catalog::AcroForm) {
+ Form *form = doc->getCatalog()->getForm();
+ for (int i = 0; i < form->getNumFields(); i++) {
+ FormField *field = form->getRootField(i);
+ for (int j = 0; j < field->getNumWidgets(); j++) {
+ FormWidget *widget = field->getWidget(j);
+ scanLinkAction(widget->getActivationAction());
+ scanLinkAction(widget->getAdditionalAction(Annot::actionFieldModified));
+ scanLinkAction(widget->getAdditionalAction(Annot::actionFormatField));
+ scanLinkAction(widget->getAdditionalAction(Annot::actionValidateField));
+ scanLinkAction(widget->getAdditionalAction(Annot::actionCalculateField));
+ }
+ }
+ }
+
+ // scan pages
+
+ if (currentPage > doc->getNumPages()) {
+ return;
+ }
+
+ lastPage = currentPage + nPages;
+ if (lastPage > doc->getNumPages() + 1) {
+ lastPage = doc->getNumPages() + 1;
+ }
+
+ for (int pg = currentPage; pg < lastPage; ++pg) {
+ page = doc->getPage(pg);
+ if (!page) continue;
+
+ // page actions (open, close)
+ scanLinkAction(page->getAdditionalAction(Page::actionOpenPage));
+ scanLinkAction(page->getAdditionalAction(Page::actionClosePage));
+
+ // annotation actions (links, screen, widget)
+ annots = page->getAnnots();
+ for (int i = 0; i < annots->getNumAnnots(); ++i) {
+ if (annots->getAnnot(i)->getType() == Annot::typeLink) {
+ AnnotLink *annot = static_cast<AnnotLink *>(annots->getAnnot(i));
+ scanLinkAction(annot->getAction());
+ } else if (annots->getAnnot(i)->getType() == Annot::typeScreen) {
+ AnnotScreen *annot = static_cast<AnnotScreen *>(annots->getAnnot(i));
+ scanLinkAction(annot->getAction());
+ scanLinkAction(annot->getAdditionalAction(Annot::actionCursorEntering));
+ scanLinkAction(annot->getAdditionalAction(Annot::actionCursorLeaving));
+ scanLinkAction(annot->getAdditionalAction(Annot::actionMousePressed));
+ scanLinkAction(annot->getAdditionalAction(Annot::actionMouseReleased));
+ scanLinkAction(annot->getAdditionalAction(Annot::actionFocusIn));
+ scanLinkAction(annot->getAdditionalAction(Annot::actionFocusOut));
+ scanLinkAction(annot->getAdditionalAction(Annot::actionPageOpening));
+ scanLinkAction(annot->getAdditionalAction(Annot::actionPageClosing));
+ scanLinkAction(annot->getAdditionalAction(Annot::actionPageVisible));
+ scanLinkAction(annot->getAdditionalAction(Annot::actionPageVisible));
+
+ } else if (annots->getAnnot(i)->getType() == Annot::typeWidget) {
+ AnnotWidget *annot = static_cast<AnnotWidget *>(annots->getAnnot(i));
+ scanLinkAction(annot->getAction());
+ scanLinkAction(annot->getAdditionalAction(Annot::actionCursorEntering));
+ scanLinkAction(annot->getAdditionalAction(Annot::actionCursorLeaving));
+ scanLinkAction(annot->getAdditionalAction(Annot::actionMousePressed));
+ scanLinkAction(annot->getAdditionalAction(Annot::actionMouseReleased));
+ scanLinkAction(annot->getAdditionalAction(Annot::actionFocusIn));
+ scanLinkAction(annot->getAdditionalAction(Annot::actionFocusOut));
+ scanLinkAction(annot->getAdditionalAction(Annot::actionPageOpening));
+ scanLinkAction(annot->getAdditionalAction(Annot::actionPageClosing));
+ scanLinkAction(annot->getAdditionalAction(Annot::actionPageVisible));
+ scanLinkAction(annot->getAdditionalAction(Annot::actionPageVisible));
+ }
+ }
+ }
+
+ currentPage = lastPage;
+}
+
+GBool JSInfo::containsJS() {
+ return hasJS;
+};
diff --git a/utils/JSInfo.h b/utils/JSInfo.h
new file mode 100644
index 0000000..fed3f68
--- /dev/null
+++ b/utils/JSInfo.h
@@ -0,0 +1,50 @@
+//========================================================================
+//
+// JSInfo.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright (C) 2013 Adrian Johnson <ajohnson at redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef JS_INFO_H
+#define JS_INFO_H
+
+#include "Object.h"
+#include "PDFDoc.h"
+#include "goo/gtypes.h"
+
+#include "Link.h"
+
+class PDFDoc;
+
+class JSInfo {
+public:
+
+ // Constructor.
+ JSInfo(PDFDoc *doc, int firstPage = 0);
+
+ // Destructor.
+ ~JSInfo();
+
+ // scan for JS in the PDF
+ void scanJS(int nPages);
+
+ // return true if PDF contains JavaScript
+ GBool containsJS();
+
+private:
+
+ PDFDoc *doc;
+ int currentPage;
+ GBool hasJS;
+
+ void scanLinkAction(LinkAction *link);
+
+};
+
+#endif
diff --git a/utils/Makefile.am b/utils/Makefile.am
index 0c95441..1dd9a12 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -88,12 +88,16 @@ pdfimages_SOURCES = \
pdfimages.cc \
ImageOutputDev.cc \
ImageOutputDev.h \
+ JSInfo.cc \
+ JSInfo.h \
$(common)
pdfinfo_SOURCES = \
pdfinfo.cc \
printencodings.cc \
printencodings.h \
+ JSInfo.cc \
+ JSInfo.h \
$(common)
pdftops_SOURCES = \
diff --git a/utils/pdfinfo.1 b/utils/pdfinfo.1
index a3ad1c3..134bd3f 100644
--- a/utils/pdfinfo.1
+++ b/utils/pdfinfo.1
@@ -48,6 +48,9 @@ tagged (yes/no)
form (AcroForm / XFA / none)
.RE
.RS
+javascript (yes/no)
+.RE
+.RS
page count
.RE
.RS
diff --git a/utils/pdfinfo.cc b/utils/pdfinfo.cc
index f297614..902200f 100644
--- a/utils/pdfinfo.cc
+++ b/utils/pdfinfo.cc
@@ -53,6 +53,7 @@
#include "UTF.h"
#include "Error.h"
#include "DateInfo.h"
+#include "JSInfo.h"
static void printInfoString(Dict *infoDict, const char *key, const char *text,
UnicodeMap *uMap);
@@ -246,6 +247,13 @@ int main(int argc, char *argv[]) {
break;
}
+ // print javascript info
+ {
+ JSInfo jsInfo(doc, firstPage - 1);
+ jsInfo.scanJS(lastPage - firstPage + 1);
+ printf("JavaScript: %s\n", jsInfo.containsJS() ? "yes" : "no");
+ }
+
// print page count
printf("Pages: %d\n", doc->getNumPages());
More information about the poppler
mailing list