1 //========================================================================
2 //
3 // JSInfo.cc
4 //
5 // This file is licensed under the GPLv2 or later
6 //
7 // Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
8 // Copyright (C) 2017, 2020, 2021 Albert Astals Cid <aacid@kde.org>
9 // Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by the LiMux project of the city of Munich
10 // Copyright (C) 2020 Oliver Sander <oliver.sander@tu-dresden.de>
11 // Copyright (C) 2020 Nelson Benítez León <nbenitezl@gmail.com>
12 //
13 // To see a description of the changes please see the Changelog file that
14 // came with your tarball or type make ChangeLog if you are building from git
15 //
16 //========================================================================
17
18 #include "config.h"
19 #include <cstdio>
20 #include "Object.h"
21 #include "Dict.h"
22 #include "Annot.h"
23 #include "PDFDoc.h"
24 #include "JSInfo.h"
25 #include "Link.h"
26 #include "Form.h"
27 #include "UnicodeMap.h"
28 #include "UTF.h"
29 // #include "Win32Console.h"
30
JSInfo(PDFDoc * docA,int firstPage)31 JSInfo::JSInfo(PDFDoc *docA, int firstPage)
32 {
33 doc = docA;
34 currentPage = firstPage + 1;
35 }
36
~JSInfo()37 JSInfo::~JSInfo() { }
38
printJS(const GooString * js)39 void JSInfo::printJS(const GooString *js)
40 {
41 Unicode *u = nullptr;
42 char buf[8];
43 int i, n, len;
44
45 if (!js || !js->c_str())
46 return;
47
48 len = TextStringToUCS4(js->toStr(), &u);
49 for (i = 0; i < len; i++) {
50 n = uniMap->mapUnicode(u[i], buf, sizeof(buf));
51 fwrite(buf, 1, n, file);
52 }
53 gfree(u);
54 }
55
scanLinkAction(LinkAction * link,const char * action)56 void JSInfo::scanLinkAction(LinkAction *link, const char *action)
57 {
58 if (!link)
59 return;
60
61 if (link->getKind() == actionJavaScript) {
62 hasJS = true;
63 if (print) {
64 LinkJavaScript *linkjs = static_cast<LinkJavaScript *>(link);
65 if (linkjs->isOk()) {
66 const std::string &s = linkjs->getScript();
67 fprintf(file, "%s:\n", action);
68 GooString gooS = GooString(s);
69 printJS(&gooS);
70 fputs("\n\n", file);
71 }
72 }
73 }
74
75 if (link->getKind() == actionRendition) {
76 LinkRendition *linkr = static_cast<LinkRendition *>(link);
77 if (!linkr->getScript().empty()) {
78 hasJS = true;
79 if (print) {
80 fprintf(file, "%s (Rendition):\n", action);
81 const GooString s(linkr->getScript());
82 printJS(&s);
83 fputs("\n\n", file);
84 }
85 }
86 }
87 }
88
scanJS(int nPages)89 void JSInfo::scanJS(int nPages)
90 {
91 print = false;
92 file = nullptr;
93 onlyFirstJS = false;
94 scan(nPages);
95 }
96
scanJS(int nPages,FILE * fout,const UnicodeMap * uMap)97 void JSInfo::scanJS(int nPages, FILE *fout, const UnicodeMap *uMap)
98 {
99 print = true;
100 file = fout;
101 uniMap = uMap;
102 onlyFirstJS = false;
103 scan(nPages);
104 }
105
scanJS(int nPages,bool stopOnFirstJS)106 void JSInfo::scanJS(int nPages, bool stopOnFirstJS)
107 {
108 print = false;
109 file = nullptr;
110 onlyFirstJS = stopOnFirstJS;
111 scan(nPages);
112 }
113
scan(int nPages)114 void JSInfo::scan(int nPages)
115 {
116 Page *page;
117 Annots *annots;
118 int lastPage;
119
120 hasJS = false;
121
122 // Names
123 int numNames = doc->getCatalog()->numJS();
124 if (numNames > 0) {
125 hasJS = true;
126 if (onlyFirstJS) {
127 return;
128 }
129 if (print) {
130 for (int i = 0; i < numNames; i++) {
131 fprintf(file, "Name Dictionary \"%s\":\n", doc->getCatalog()->getJSName(i)->c_str());
132 GooString *js = doc->getCatalog()->getJS(i);
133 printJS(js);
134 delete js;
135 fputs("\n\n", file);
136 }
137 }
138 }
139
140 // document actions
141 scanLinkAction(doc->getCatalog()->getAdditionalAction(Catalog::actionCloseDocument).get(), "Before Close Document");
142 scanLinkAction(doc->getCatalog()->getAdditionalAction(Catalog::actionSaveDocumentStart).get(), "Before Save Document");
143 scanLinkAction(doc->getCatalog()->getAdditionalAction(Catalog::actionSaveDocumentFinish).get(), "After Save Document");
144 scanLinkAction(doc->getCatalog()->getAdditionalAction(Catalog::actionPrintDocumentStart).get(), "Before Print Document");
145 scanLinkAction(doc->getCatalog()->getAdditionalAction(Catalog::actionPrintDocumentFinish).get(), "After Print Document");
146
147 if (onlyFirstJS && hasJS) {
148 return;
149 }
150 // form field actions
151 if (doc->getCatalog()->getFormType() == Catalog::AcroForm) {
152 Form *form = doc->getCatalog()->getForm();
153 for (int i = 0; i < form->getNumFields(); i++) {
154 FormField *field = form->getRootField(i);
155 for (int j = 0; j < field->getNumWidgets(); j++) {
156 FormWidget *widget = field->getWidget(j);
157 scanLinkAction(widget->getActivationAction(), "Field Activated");
158 scanLinkAction(widget->getAdditionalAction(Annot::actionFieldModified).get(), "Field Modified");
159 scanLinkAction(widget->getAdditionalAction(Annot::actionFormatField).get(), "Format Field");
160 scanLinkAction(widget->getAdditionalAction(Annot::actionValidateField).get(), "Validate Field");
161 scanLinkAction(widget->getAdditionalAction(Annot::actionCalculateField).get(), "Calculate Field");
162 if (onlyFirstJS && hasJS) {
163 return;
164 }
165 }
166 }
167 }
168
169 // scan pages
170
171 if (currentPage > doc->getNumPages()) {
172 return;
173 }
174
175 lastPage = currentPage + nPages;
176 if (lastPage > doc->getNumPages() + 1) {
177 lastPage = doc->getNumPages() + 1;
178 }
179
180 for (int pg = currentPage; pg < lastPage; ++pg) {
181 page = doc->getPage(pg);
182 if (!page)
183 continue;
184
185 // page actions (open, close)
186 scanLinkAction(page->getAdditionalAction(Page::actionOpenPage).get(), "Page Open");
187 scanLinkAction(page->getAdditionalAction(Page::actionClosePage).get(), "Page Close");
188
189 if (onlyFirstJS && hasJS) {
190 return;
191 }
192 // annotation actions (links, screen, widget)
193 annots = page->getAnnots();
194 for (int i = 0; i < annots->getNumAnnots(); ++i) {
195 if (annots->getAnnot(i)->getType() == Annot::typeLink) {
196 AnnotLink *annot = static_cast<AnnotLink *>(annots->getAnnot(i));
197 scanLinkAction(annot->getAction(), "Link Annotation Activated");
198 if (onlyFirstJS && hasJS) {
199 return;
200 }
201 } else if (annots->getAnnot(i)->getType() == Annot::typeScreen) {
202 AnnotScreen *annot = static_cast<AnnotScreen *>(annots->getAnnot(i));
203 scanLinkAction(annot->getAction(), "Screen Annotation Activated");
204 scanLinkAction(annot->getAdditionalAction(Annot::actionCursorEntering).get(), "Screen Annotation Cursor Enter");
205 scanLinkAction(annot->getAdditionalAction(Annot::actionCursorLeaving).get(), "Screen Annotation Cursor Leave");
206 scanLinkAction(annot->getAdditionalAction(Annot::actionMousePressed).get(), "Screen Annotation Mouse Pressed");
207 scanLinkAction(annot->getAdditionalAction(Annot::actionMouseReleased).get(), "Screen Annotation Mouse Released");
208 scanLinkAction(annot->getAdditionalAction(Annot::actionFocusIn).get(), "Screen Annotation Focus In");
209 scanLinkAction(annot->getAdditionalAction(Annot::actionFocusOut).get(), "Screen Annotation Focus Out");
210 scanLinkAction(annot->getAdditionalAction(Annot::actionPageOpening).get(), "Screen Annotation Page Open");
211 scanLinkAction(annot->getAdditionalAction(Annot::actionPageClosing).get(), "Screen Annotation Page Close");
212 scanLinkAction(annot->getAdditionalAction(Annot::actionPageVisible).get(), "Screen Annotation Page Visible");
213 scanLinkAction(annot->getAdditionalAction(Annot::actionPageInvisible).get(), "Screen Annotation Page Invisible");
214
215 if (onlyFirstJS && hasJS) {
216 return;
217 }
218 } else if (annots->getAnnot(i)->getType() == Annot::typeWidget) {
219 AnnotWidget *annot = static_cast<AnnotWidget *>(annots->getAnnot(i));
220 scanLinkAction(annot->getAction(), "Widget Annotation Activated");
221 scanLinkAction(annot->getAdditionalAction(Annot::actionCursorEntering).get(), "Widget Annotation Cursor Enter");
222 scanLinkAction(annot->getAdditionalAction(Annot::actionCursorLeaving).get(), "Widget Annotation Cursor Leave");
223 scanLinkAction(annot->getAdditionalAction(Annot::actionMousePressed).get(), "Widget Annotation Mouse Pressed");
224 scanLinkAction(annot->getAdditionalAction(Annot::actionMouseReleased).get(), "Widget Annotation Mouse Released");
225 scanLinkAction(annot->getAdditionalAction(Annot::actionFocusIn).get(), "Widget Annotation Focus In");
226 scanLinkAction(annot->getAdditionalAction(Annot::actionFocusOut).get(), "Widget Annotation Focus Out");
227 scanLinkAction(annot->getAdditionalAction(Annot::actionPageOpening).get(), "Widget Annotation Page Open");
228 scanLinkAction(annot->getAdditionalAction(Annot::actionPageClosing).get(), "Widget Annotation Page Close");
229 scanLinkAction(annot->getAdditionalAction(Annot::actionPageVisible).get(), "Widget Annotation Page Visible");
230 scanLinkAction(annot->getAdditionalAction(Annot::actionPageInvisible).get(), "Widget Annotation Page Invisible");
231 if (onlyFirstJS && hasJS) {
232 return;
233 }
234 }
235 }
236 }
237
238 currentPage = lastPage;
239 }
240
containsJS()241 bool JSInfo::containsJS()
242 {
243 return hasJS;
244 }
245