/* * Count Javascript occurrences in document. * * Required software: pCOS interface 8 (PDFlib+PDI/PPS 9, TET 4.1, PLOP 5.0) * Required data: PDF document */ package com.pdflib.cookbook.pcos.interactive; import com.pdflib.IpCOS; import com.pdflib.cookbook.pcos.pcos_cookbook_example; public class javascript extends pcos_cookbook_example { /* This is where the data files are. Adjust as necessary. */ private final static String SEARCH_PATH = "../input"; private interface script_info_printer { /** * Prints information about a JavaScript found in an action dictionary. * * @param scriptnr * number of the script * @param length * length of script in bytes */ void print_info(int scriptnr, int length); } public void example_code(IpCOS p, int doc) throws Exception { System.out.println("File name: " + p.pcos_get_string(doc, "filename")); /* Document-level JavaScript */ int docscripts = get_documentscripts(p, doc); /* Open action JavaScript */ int openscripts = get_openscripts(p, doc); /* Page-level JavaScript */ int pagescripts = get_pagescripts(p, doc); /* Annotation-level JavaScript */ int annotscripts = get_annotscripts(p, doc); /* Field-level JavaScript */ int fieldscripts = get_fieldscripts(p, doc); /* Bookmark-level JavaScript */ int bookmarkscripts = get_bookmarkscripts(p, doc); System.out.println(); System.out.println(openscripts + " JavaScript(s) for open action"); System.out.println(docscripts + " JavaScript(s) on document level"); System.out.println(pagescripts + " JavaScript(s) on page level"); System.out.println(annotscripts + " JavaScript(s) on annotation level"); System.out.println(fieldscripts + " JavaScript(s) on field level"); System.out .println(bookmarkscripts + " JavaScript(s) on bookmark level"); } private class bookmark_info_printer implements script_info_printer { private String title; bookmark_info_printer(String title) { this.title = title; } public void print_info(int scriptnr, int length) { System.out.println("Bookmark '" + title + "', script number " + (scriptnr + 1) + ", length=" + length); } } private int get_bookmarkscripts(IpCOS p, int doc) throws Exception { int bookmarkscripts = 0; int bookmarkcount = (int) p.pcos_get_number(doc, "length:bookmarks"); for (int bookmark = 0; bookmark < bookmarkcount; bookmark++) { int objid; String base = "bookmarks[" + bookmark + "]/A"; objid = (int) p.pcos_get_number(doc, "pcosid:" + base); String bookmark_name = p.pcos_get_string(doc, "bookmarks[" + bookmark + "]/Title"); script_info_printer info_printer = new bookmark_info_printer( bookmark_name); bookmarkscripts += walk_action_dictionary(p, doc, objid, 0, info_printer); } return bookmarkscripts; } private class field_trigger_info_printer implements script_info_printer { private String trigger; private String fullname; field_trigger_info_printer(String trigger, String fullname) { this.trigger = trigger; this.fullname = fullname; } public void print_info(int scriptnr, int length) { System.out.println("Form field '" + fullname + "', " + "trigger '" + trigger + "', script number " + (scriptnr + 1) + ", length=" + length); } } private int get_fieldscripts(IpCOS p, int doc) throws Exception { int fieldcount = (int) p.pcos_get_number(doc, "length:fields"); int fieldscripts = 0; for (int field = 0; field < fieldcount; field++) { int actioncount = (int) p.pcos_get_number(doc, "length:fields[" + field + "]/AA"); for (int action = 0; action < actioncount; action++) { String base = "fields[" + field + "]/AA[" + action + "]"; int objid = (int) p.pcos_get_number(doc, "pcosid:" + base); String trigger = p.pcos_get_string(doc, base + ".key"); String form_field = p.pcos_get_string(doc, "fields[" + field + "]/fullname"); script_info_printer info_printer = new field_trigger_info_printer( trigger, form_field); fieldscripts += walk_action_dictionary(p, doc, objid, 0, info_printer); } } return fieldscripts; } private class annot_activation_info_printer implements script_info_printer { private String subtype; private int pagenr; annot_activation_info_printer(String subtype, int pagenr) { this.subtype = subtype; this.pagenr = pagenr; } public void print_info(int scriptnr, int length) { System.out.print("Page " + (pagenr + 1) + ", " + subtype + " annotation, script number " + (scriptnr + 1) + ", "); System.out.println("activation script, length=" + length); } } private class annot_trigger_info_printer implements script_info_printer { private String subtype; private String trigger; private int pagenr; annot_trigger_info_printer(String subtype, String trigger, int pagenr) { this.subtype = subtype; this.trigger = trigger; this.pagenr = pagenr; } public void print_info(int scriptnr, int length) { System.out.print("Page " + (pagenr + 1) + ", " + subtype + " annotation, script number " + scriptnr + ", "); System.out.println("trigger '" + trigger + "', length=" + length); } } private int get_annotscripts(IpCOS p, int doc) throws Exception { int annotscripts = 0; int pagecount = (int) p.pcos_get_number(doc, "length:pages"); for (int page = 0; page < pagecount; page++) { int annotcount = (int) p.pcos_get_number(doc, "length:pages[" + page + "]/annots"); for (int ann = 0; ann < annotcount; ann++) { /* Avoid double-counting of form field Widgets */ String subtype = p.pcos_get_string(doc, "pages[" + page + "]/annots[" + ann + "]/Subtype"); if ("Widget".equals(subtype)) continue; /* old-style A entry with a single action */ String base = "pages[" + page + "]/annots[" + ann + "]/A"; int objid = (int) p.pcos_get_number(doc, "pcosid:" + base); script_info_printer info_printer = new annot_activation_info_printer( subtype, page); annotscripts += walk_action_dictionary(p, doc, objid, 0, info_printer); /* newer AA entry with multiple actions */ int actioncount = (int) p.pcos_get_number(doc, "length:pages[" + page + "]/annots[" + ann + "]/AA"); for (int action = 0; action < actioncount; action++) { base = "pages[" + page + "]/annots[" + ann + "]/AA[" + action + "]"; objid = (int) p.pcos_get_number(doc, "pcosid:" + base); String trigger = p.pcos_get_string(doc, base + ".key"); info_printer = new annot_trigger_info_printer(subtype, trigger, page); annotscripts += walk_action_dictionary(p, doc, objid, 0, info_printer); } } } return annotscripts; } private class open_action_info_printer implements script_info_printer { public void print_info(int scriptnr, int length) { System.out.println("Open action script number " + (scriptnr + 1) + ", length=" + length); } } private int get_openscripts(IpCOS p, int doc) throws Exception { int openscripts = 0; String base = "/Root/OpenAction"; /* * The "OpenAction" entry can be a "destination" or an "action * dictionary". Only examine the latter case for JavaScript occurences. */ String type = p.pcos_get_string(doc, "type:" + base); if (type.equals("dict")) { int objid = (int) p.pcos_get_number(doc, "pcosid:" + base); script_info_printer info_printer = new open_action_info_printer(); openscripts = walk_action_dictionary(p, doc, objid, 0, info_printer); } return openscripts; } private class document_info_printer implements script_info_printer { private String scriptname; document_info_printer(String scriptname) { this.scriptname = scriptname; } public void print_info(int scriptnr, int length) { System.out.println("Document-level script '" + scriptname + "', length=" + length); } } private class document_action_info_printer implements script_info_printer { private String trigger; document_action_info_printer(String trigger) { this.trigger = trigger; } public void print_info(int scriptnr, int length) { System.out.println("Document-level script, trigger '" + trigger + "', number " + (scriptnr + 1) + ", length=" + length); } } private int get_documentscripts(IpCOS p, int doc) throws Exception { int docscripts = 0; int scriptcount = (int) p.pcos_get_number(doc, "length:names/JavaScript"); for (int script = 0; script < scriptcount; script++) { String base = "names/JavaScript[" + script + "]"; int objid = (int) p.pcos_get_number(doc, "pcosid:" + base); String script_name = p.pcos_get_string(doc, base + ".key"); script_info_printer info_printer = new document_info_printer( script_name); if (check_for_script(p, doc, objid, docscripts, info_printer)) { docscripts++; } } /* Additional document-level JavaScript */ int actioncount = (int) p.pcos_get_number(doc, "length:/Root/AA"); for (int action = 0; action < actioncount; action++) { String base = "/Root/AA[" + action + "]"; int objid = (int) p.pcos_get_number(doc, "pcosid:" + base); String trigger = p.pcos_get_string(doc, base + ".key"); script_info_printer info_printer = new document_action_info_printer( trigger); docscripts += walk_action_dictionary(p, doc, objid, 0, info_printer); } return docscripts; } private class page_info_printer implements script_info_printer { private int pagenr; private String trigger; page_info_printer(int pagenr, String trigger) { this.trigger = trigger; this.pagenr = pagenr; } public void print_info(int scriptnr, int length) { System.out.println("Page " + (pagenr + 1) + ", trigger '" + trigger + "', script number " + (scriptnr + 1) + ", length=" + length); } } private int get_pagescripts(IpCOS p, int doc) throws Exception { int pagecount = (int) p.pcos_get_number(doc, "length:pages"); int pagescripts = 0; for (int page = 0; page < pagecount; page++) { int actioncount = (int) p.pcos_get_number(doc, "length:pages[" + page + "]/AA"); for (int action = 0; action < actioncount; action++) { String base = "pages[" + page + "]/AA[" + action + "]"; int objid = (int) p.pcos_get_number(doc, "pcosid:" + base); String trigger = p.pcos_get_string(doc, base + ".key"); script_info_printer info_printer = new page_info_printer(page, trigger); pagescripts += walk_action_dictionary(p, doc, objid, 0, info_printer); } } return pagescripts; } /** * Traverses an action dictionary. * * An action dictionary can contain a tree of action definitions, and a * subset of them can be JavaScript actions. This routine recursively * traverses the action tree and counts the JavaScript occurrences. * * For the definition of an action dictionary, see for example "8.5.1 Action * Dictionaries" in the PDF Reference version 1.7. The * * @param p * IpCOS object * @param doc * document handle * @param objid * pCOS id of the action dictionary to traverse * @param scriptnr * counter for the JavaScript occurrences in the action * dictionary tree * @param info_printer * used to print out the information about the action * * @return number of scripts found in the action dictionary tree * * @throws Exception * an error was detected in the PDF structure */ private int walk_action_dictionary(IpCOS p, int doc, int objid, int scriptnr, script_info_printer info_printer) throws Exception { int scripts = 0; while (objid != -1) { if (check_for_script(p, doc, objid, scriptnr + scripts, info_printer)) { scripts += 1; } String type = p.pcos_get_string(doc, "type:objects[" + objid + "]/Next"); if (type.equals("dict")) { objid = (int) p.pcos_get_number(doc, "pcosid:objects[" + objid + "]/Next"); } else if (type.equals("array")) { int length = (int) p.pcos_get_number(doc, "length:objects[" + objid + "]/Next"); for (int child = 0; child < length; child += 1) { objid = (int) p.pcos_get_number(doc, "pcosid:objects[" + objid + "]/Next[" + child + "]"); scripts += walk_action_dictionary(p, doc, objid, scriptnr + scripts, info_printer); } objid = -1; } else { objid = -1; } } return scripts; } /** * Checks whether the given action dictionary entry is a JavaScript action. * * @param p * IpCOS object * @param doc * document handle * @param objid * pCOS id of the action dictionary entry * @param scriptnr * counter for the JavaScript occurrences in the action * dictionary tree * @param info_printer * for printing the information about the action * * @return true if a script was found, false otherwise * @throws Exception */ private boolean check_for_script(IpCOS p, int doc, int objid, int scriptnr, script_info_printer info_printer) throws Exception { boolean retval = false; String action_dict_obj = "objects[" + objid + "]"; String objtype = p.pcos_get_string(doc, "type:" + action_dict_obj); if (objtype.equals("dict")) { /* The action type, not the type of PDF object */ String actiontype = p.pcos_get_string(doc, action_dict_obj + "/S"); if (actiontype.equals("JavaScript")) { int len; String js_path = action_dict_obj + "/JS"; objtype = p.pcos_get_string(doc, "type:" + js_path); if (objtype.equals("string")) { /* fetch string contents to determine length */ String js = p.pcos_get_string(doc, js_path); len = js.length(); } else if (objtype.equals("stream")) { /* fetch uncompressed stream data to determine length */ byte[] js = p.pcos_get_stream(doc, "convert=unicode", js_path); len = js.length; /* Unicode detection: test for BOM, determine proper length */ if (js[0] == 0xFF && js[1] == 0xFE) { len = (len - 2) / 2; } } else { throw new Exception("Could not get JavaScript contents" + "for object with id " + objid); } /* call the method that prints action-specific information */ info_printer.print_info(scriptnr, len); retval = true; } } return retval; } public javascript(String[] argv, String readable_name, String search_path) { super(argv, readable_name, search_path); } public static void main(String argv[]) { javascript example = new javascript(argv, "JavaScript", SEARCH_PATH); example.execute(); } }