summaryrefslogtreecommitdiff
path: root/pdf
diff options
context:
space:
mode:
authorPaul Gardiner <paul@glidos.net>2012-04-19 16:27:53 +0100
committerPaul Gardiner <paul@glidos.net>2012-05-08 15:12:37 +0100
commit08a925d3ff7e703e1752dbdcd0f1188ec9cee8d0 (patch)
tree905e2bc90d26fae02ad1aeb1048a0f44bbdc6e29 /pdf
parent9ebe09595ad8088f518b6397e791aa44c27a374f (diff)
downloadmupdf-08a925d3ff7e703e1752dbdcd0f1188ec9cee8d0.tar.xz
Implement dummy JavaScript engine just for the sake of viewing calc.pdf
Diffstat (limited to 'pdf')
-rw-r--r--pdf/mupdf-internal.h8
-rw-r--r--pdf/pdf_form.c22
-rw-r--r--pdf/pdf_js.c7
-rw-r--r--pdf/pdf_jsimp.c294
-rw-r--r--pdf/pdf_xref.c2
5 files changed, 321 insertions, 12 deletions
diff --git a/pdf/mupdf-internal.h b/pdf/mupdf-internal.h
index d0617769..8ffb81f1 100644
--- a/pdf/mupdf-internal.h
+++ b/pdf/mupdf-internal.h
@@ -568,11 +568,15 @@ void *pdf_find_item(fz_context *ctx, fz_store_free_fn *free, pdf_obj *key);
void pdf_remove_item(fz_context *ctx, fz_store_free_fn *free, pdf_obj *key);
/*
- * Javascript engine interface
+ * Javascript handler
*/
pdf_js *pdf_new_js(pdf_document *doc);
void pdf_drop_js(pdf_js *js);
+void pdf_js_execute(pdf_js *js, char *code);
+/*
+ * Javascript engine interface
+ */
typedef struct pdf_jsimp_s pdf_jsimp;
typedef struct pdf_jsimp_type_s pdf_jsimp_type;
typedef struct pdf_jsimp_obj_s pdf_jsimp_obj;
@@ -596,4 +600,6 @@ void pdf_jsimp_set_this(pdf_jsimp *imp, pdf_jsimp_obj *obj);
pdf_jsimp_obj *pdf_jsimp_fromString(pdf_jsimp *imp, char *str);
char *pdf_jsimp_toString(pdf_jsimp *imp, pdf_jsimp_obj *obj);
+void pdf_jsimp_execute(pdf_jsimp *imp, char *code);
+
#endif
diff --git a/pdf/pdf_form.c b/pdf/pdf_form.c
index d1bc7576..31e1ce49 100644
--- a/pdf/pdf_form.c
+++ b/pdf/pdf_form.c
@@ -580,6 +580,26 @@ void pdf_synthesize_missing_appearance(pdf_document *doc, pdf_obj *obj)
}
}
+static void execute_action(pdf_document *doc, pdf_obj *obj)
+{
+ pdf_obj *a;
+
+ a = pdf_dict_gets(obj, "A");
+ while (a)
+ {
+ char *type = pdf_to_name(pdf_dict_gets(a, "S"));
+
+ if (!strcmp(type, "JavaScript"))
+ {
+ pdf_obj *js = pdf_dict_gets(a, "JS");
+ if (js)
+ pdf_js_execute(doc->js, pdf_to_str_buf(js));
+ }
+
+ a = pdf_dict_gets(a, "Next");
+ }
+}
+
static void toggle_check_box(pdf_document *doc, pdf_obj *obj)
{
pdf_obj *as;
@@ -673,6 +693,8 @@ int pdf_pass_event(pdf_document *doc, pdf_page *page, fz_ui_event *ui_event)
changed = 1;
break;
}
+
+ execute_action(doc, annot->obj);
}
break;
}
diff --git a/pdf/pdf_js.c b/pdf/pdf_js.c
index 4c2e30ab..408f7bf2 100644
--- a/pdf/pdf_js.c
+++ b/pdf/pdf_js.c
@@ -46,7 +46,7 @@ static pdf_jsimp_obj *doc_getField(void *jsctx, void *obj, int argc, pdf_jsimp_o
pdf_obj *t;
field = pdf_array_get(js->form, i);
t = pdf_dict_gets(field, "T");
- if (!strcmp(name, pdf_to_name(t)))
+ if (!strcmp(name, pdf_to_str_buf(t)))
break;
}
@@ -111,4 +111,9 @@ void pdf_drop_js(pdf_js *js)
pdf_drop_jsimp(js->imp);
fz_free(ctx, js);
}
+}
+
+void pdf_js_execute(pdf_js *js, char *code)
+{
+ pdf_jsimp_execute(js->imp, code);
} \ No newline at end of file
diff --git a/pdf/pdf_jsimp.c b/pdf/pdf_jsimp.c
index 080b1df4..c0a11c58 100644
--- a/pdf/pdf_jsimp.c
+++ b/pdf/pdf_jsimp.c
@@ -1,59 +1,335 @@
+/*
+ * This is a dummy JavaScript engine. It cheats by recognising the specific
+ * strings in calc.pdf, and hence will work only for that file. It is for
+ * testing only.
+ */
+
+
#include "fitz-internal.h"
#include "mupdf-internal.h"
+enum
+{
+ FUNC_NONE,
+ FUNC_PLUS,
+ FUNC_MINUS,
+ FUNC_MULT,
+ FUNC_DIV
+};
+
struct pdf_jsimp_s
{
- int x;
+ fz_context *ctx;
+ void *jsctx;
+ double accum;
+ double entry;
+ double multiplier;
+ double divisor;
+ int func;
+ pdf_jsimp_obj *jsthis;
+ pdf_jsimp_obj *display;
+ pdf_jsimp_obj *funcfield;
};
+/* We need only a couple of specific methods for calc.pdf */
struct pdf_jsimp_type_s
{
- int x;
+ pdf_jsimp_dtr *dtr;
+ pdf_jsimp_method *getField;
+ pdf_jsimp_getter *getValue;
+ pdf_jsimp_setter *setValue;
};
struct pdf_jsimp_obj_s
{
- int x;
+ pdf_jsimp_type *type;
+ void *obj;
};
+static double digit_button(pdf_jsimp *imp, int digit)
+{
+ imp->entry = imp->entry * imp->multiplier + digit / imp->divisor;
+
+ if (imp->divisor >= 10)
+ {
+ imp->divisor = imp->divisor * 10;
+ }
+ else
+ {
+ imp->multiplier = 10;
+ }
+
+ return imp->entry;
+}
+
+static void assign_display_value(pdf_jsimp *imp, double val)
+{
+ char valstr[256];
+ pdf_jsimp_obj *valobj;
+
+ if (imp->display == NULL)
+ {
+ pdf_jsimp_obj *str_arg = pdf_jsimp_fromString(imp, "Display");
+ pdf_jsimp_obj *doc = imp->jsthis;
+ imp->display = doc->type->getField(imp->jsctx, doc->obj, 1, &str_arg);
+ }
+
+ snprintf(valstr, sizeof(valstr), "%f", val);
+ if (imp->display && imp->display->type->setValue)
+ {
+ valobj = pdf_jsimp_fromString(imp, valstr);
+ imp->display->type->setValue(imp->jsctx, imp->display->obj, valobj);
+ }
+}
+
+static void assign_func_value(pdf_jsimp *imp, int val)
+{
+ pdf_jsimp_obj *valobj = NULL;
+
+ if (imp->funcfield == NULL)
+ {
+ pdf_jsimp_obj *str_arg = pdf_jsimp_fromString(imp, "Func");
+ pdf_jsimp_obj *doc = imp->jsthis;
+ imp->funcfield = doc->type->getField(imp->jsctx, doc->obj, 1, &str_arg);
+ }
+
+ if (imp->funcfield && imp->funcfield->type->setValue)
+ {
+ switch(val)
+ {
+ case FUNC_NONE:
+ valobj = pdf_jsimp_fromString(imp, "");
+ break;
+ case FUNC_MULT:
+ valobj = pdf_jsimp_fromString(imp, "MULT");
+ break;
+ case FUNC_DIV:
+ valobj = pdf_jsimp_fromString(imp, "DIV");
+ break;
+ case FUNC_PLUS:
+ valobj = pdf_jsimp_fromString(imp, "PLUS");
+ break;
+ case FUNC_MINUS:
+ valobj = pdf_jsimp_fromString(imp, "MINUS");
+ break;
+ }
+
+ if (valobj)
+ imp->funcfield->type->setValue(imp->jsctx, imp->funcfield->obj, valobj);
+ }
+}
+
+static void clear_entry(pdf_jsimp *imp)
+{
+ imp->entry = 0;
+ imp->multiplier = 1;
+ imp->divisor = 1;
+}
+
+static void update_result(pdf_jsimp *imp)
+{
+ switch(imp->func)
+ {
+ case FUNC_PLUS:
+ imp->accum = imp->accum + imp->entry;
+ break;
+ case FUNC_MINUS:
+ imp->accum = imp->accum - imp->entry;
+ break;
+ case FUNC_MULT:
+ imp->accum = imp->accum * imp->entry;
+ break;
+ case FUNC_DIV:
+ if (imp->entry != 0)
+ imp->accum = imp->accum / imp->entry;
+ break;
+ }
+
+ imp->func = FUNC_NONE;
+ assign_func_value(imp, FUNC_NONE);
+ clear_entry(imp);
+}
+
+static void func_button(pdf_jsimp *imp, int func)
+{
+ if (imp->func != FUNC_NONE)
+ {
+ update_result(imp);
+ }
+ else
+ {
+ if (imp->entry != 0)
+ imp->accum = imp->entry;
+
+ imp->func = func;
+ assign_func_value(imp, func);
+ clear_entry(imp);
+ }
+}
+
+static void all_cancel(pdf_jsimp *imp)
+{
+ clear_entry(imp);
+ assign_display_value(imp, 0);
+ imp->accum = 0;
+ assign_func_value(imp, FUNC_NONE);
+}
+
pdf_jsimp *pdf_new_jsimp(fz_context *ctx, void *jsctx)
{
- return NULL;
+ pdf_jsimp *imp = fz_malloc_struct(ctx, pdf_jsimp);
+
+ imp->ctx = ctx;
+ imp->jsctx = jsctx;
+ imp->accum = 0;
+ imp->entry = 0;
+ imp->divisor = 1;
+ imp->multiplier = 1;
+
+ return imp;
}
void pdf_drop_jsimp(pdf_jsimp *imp)
{
+ if (imp)
+ {
+ fz_free(imp->ctx, imp);
+ }
}
pdf_jsimp_type *pdf_jsimp_new_type(pdf_jsimp *imp, pdf_jsimp_dtr *dtr)
{
- return NULL;
+ pdf_jsimp_type *type = fz_malloc_struct(imp->ctx, pdf_jsimp_type);
+ type->dtr = dtr;
+
+ return type;
}
void pdf_jsimp_addmethod(pdf_jsimp *imp, pdf_jsimp_type *type, char *name, pdf_jsimp_method *meth)
{
+ if (!strcmp(name, "getField"))
+ {
+ type->getField = meth;
+ }
}
void pdf_jsimp_addproperty(pdf_jsimp *imp, pdf_jsimp_type *type, char *name, pdf_jsimp_getter *get, pdf_jsimp_setter *set)
{
+ if (!strcmp(name, "value"))
+ {
+ type->getValue = get;
+ type->setValue = set;
+ }
}
-pdf_jsimp_obj *pdf_jsimp_new_obj(pdf_jsimp *imp, pdf_jsimp_type *type, void *obj)
+pdf_jsimp_obj *pdf_jsimp_new_obj(pdf_jsimp *imp, pdf_jsimp_type *type, void *natobj)
{
- return NULL;
+ pdf_jsimp_obj *obj = fz_malloc_struct(imp->ctx, pdf_jsimp_obj);
+ obj->type = type;
+ obj->obj = natobj;
+
+ return obj;
}
void pdf_jsimp_set_this(pdf_jsimp *imp, pdf_jsimp_obj *obj)
{
+ imp->jsthis = obj;
}
+
pdf_jsimp_obj *pdf_jsimp_fromString(pdf_jsimp *imp, char *str)
{
- return NULL;
+ /* Represent a string object as a pdf_jsimp_obj with a NULL type */
+ pdf_jsimp_obj *obj = fz_malloc_struct(imp->ctx, pdf_jsimp_obj);
+ obj->obj = fz_strdup(imp->ctx, str);
+
+ return obj;
}
char *pdf_jsimp_toString(pdf_jsimp *imp, pdf_jsimp_obj *obj)
{
- return NULL;
+ return (char *)(obj->type ? NULL : obj->obj);
+}
+
+void pdf_jsimp_execute(pdf_jsimp *imp, char *code)
+{
+ if (!strcmp(code, "display.value = digit_button(0);"))
+ {
+ assign_display_value(imp, digit_button(imp, 0));
+ }
+ else if (!strcmp(code, "display.value = digit_button(1);\r"))
+ {
+ assign_display_value(imp, digit_button(imp, 1));
+ }
+ else if (!strcmp(code, "display.value = digit_button(2)"))
+ {
+ assign_display_value(imp, digit_button(imp, 2));
+ }
+ else if (!strcmp(code, "display.value = digit_button(3)"))
+ {
+ assign_display_value(imp, digit_button(imp, 3));
+ }
+ else if (!strcmp(code, "display.value = digit_button(4)"))
+ {
+ assign_display_value(imp, digit_button(imp, 4));
+ }
+ else if (!strcmp(code, "display.value = digit_button(5)"))
+ {
+ assign_display_value(imp, digit_button(imp, 5));
+ }
+ else if (!strcmp(code, "display.value = digit_button(6);"))
+ {
+ assign_display_value(imp, digit_button(imp, 6));
+ }
+ else if (!strcmp(code, "display.value = digit_button(7);"))
+ {
+ assign_display_value(imp, digit_button(imp, 7));
+ }
+ else if (!strcmp(code, "display.value = digit_button(8);"))
+ {
+ assign_display_value(imp, digit_button(imp, 8));
+ }
+ else if (!strcmp(code, "display.value = digit_button(9);"))
+ {
+ assign_display_value(imp, digit_button(imp, 9));
+ }
+ else if (!strcmp(code, "if (divisor == 1) {\r divisor = 10;\r multiplier = 1;\r }"))
+ {
+ if (imp->divisor == 1)
+ {
+ imp->divisor = 10;
+ imp->multiplier = 1;
+ }
+ }
+ else if (!strcmp(code, "all_cancel();"))
+ {
+ all_cancel(imp);
+ }
+ else if (!strcmp(code, "clear_entry();\rdisplay.value = 0;"))
+ {
+ clear_entry(imp);
+ assign_display_value(imp, 0);
+ }
+ else if (!strcmp(code, "func_button(\"MULT\");"))
+ {
+ func_button(imp, FUNC_MULT);
+ }
+ else if (!strcmp(code, "func_button(\"DIV\");"))
+ {
+ func_button(imp, FUNC_DIV);
+ }
+ else if (!strcmp(code, "func_button(\"PLUS\");"))
+ {
+ func_button(imp, FUNC_PLUS);
+ }
+ else if (!strcmp(code, "func_button(\"MINUS\");"))
+ {
+ func_button(imp, FUNC_MINUS);
+ }
+ else if (!strcmp(code, "update_result();\rdisplay.value = accum;"))
+ {
+ update_result(imp);
+ assign_display_value(imp, imp->accum);
+ }
} \ No newline at end of file
diff --git a/pdf/pdf_xref.c b/pdf/pdf_xref.c
index e73ce72a..82407b80 100644
--- a/pdf/pdf_xref.c
+++ b/pdf/pdf_xref.c
@@ -690,8 +690,8 @@ pdf_open_document_with_stream(fz_stream *file)
fz_try(ctx)
{
- xref->js = pdf_new_js(xref);
pdf_load_xref(xref, &xref->lexbuf.base);
+ xref->js = pdf_new_js(xref);
}
fz_catch(ctx)
{