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 <[email protected]> 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 <[email protected]> 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 <[email protected]> +// +// 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 <[email protected]> +// +// 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()); _______________________________________________ poppler mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/poppler
