From 0528bc575875c579408ab90bb2c2e3af0750545d Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 18 May 2016 14:47:05 +0200 Subject: murun: Add graftObject to javascript bindings. Add some paranoid checks to pdf_graft_object to prevent user errors from crashing mupdf. --- docs/mutool/run.html | 11 +++++++++++ include/mupdf/pdf.h | 1 - include/mupdf/pdf/document.h | 11 ++++++++++- include/mupdf/pdf/graft.h | 17 ----------------- platform/win32/libmupdf.vcproj | 4 ---- source/pdf/pdf-graft.c | 27 +++++++++++++++++++++++++++ source/tools/murun.c | 39 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 87 insertions(+), 23 deletions(-) delete mode 100644 include/mupdf/pdf/graft.h diff --git a/docs/mutool/run.html b/docs/mutool/run.html index 5d5d73fd..23286f07 100644 --- a/docs/mutool/run.html +++ b/docs/mutool/run.html @@ -588,6 +588,17 @@ Do NOT mix and match objects from one document with another document!
PDFDocument#newDictionary() +

+The following functions can be used to copy objects from one document to another: + +

+
PDFDocument#graftObject(sourceDocument, object, sourceGraftMap) +
Deep copy an object into the destination document. The graft map may be null, but should be used if you +are copying several objects from the same source document using multiple calls to graftObject. +
PDFDocument#newGraftMap() +
Create a graft map for the source document, so that objects that have already been copied can be found again. +
+

All functions that take PDF objects, do automatic translation between JavaScript objects and PDF objects using a few basic rules. Null, booleans, and numbers are translated directly. diff --git a/include/mupdf/pdf.h b/include/mupdf/pdf.h index cb4bbdd5..eab70ee9 100644 --- a/include/mupdf/pdf.h +++ b/include/mupdf/pdf.h @@ -15,7 +15,6 @@ extern "C" { #include "mupdf/pdf/crypt.h" #include "mupdf/pdf/page.h" -#include "mupdf/pdf/graft.h" #include "mupdf/pdf/resource.h" #include "mupdf/pdf/cmap.h" #include "mupdf/pdf/font.h" diff --git a/include/mupdf/pdf/document.h b/include/mupdf/pdf/document.h index 6f73531c..f8ef6bfb 100644 --- a/include/mupdf/pdf/document.h +++ b/include/mupdf/pdf/document.h @@ -269,13 +269,22 @@ struct pdf_document_s */ pdf_document *pdf_create_document(fz_context *ctx); +/* + Deep copy objects between documents. +*/ +typedef struct pdf_graft_map_s pdf_graft_map; + +pdf_graft_map *pdf_new_graft_map(fz_context *ctx, pdf_document *src); +void pdf_drop_graft_map(fz_context *ctx, pdf_graft_map *map); +pdf_obj *pdf_graft_object(fz_context *ctx, pdf_document *dst, pdf_document *src, pdf_obj *obj, pdf_graft_map *map); + /* pdf_page_write: Create a device that will record the graphical operations given to it into a sequence of pdf operations, together with a set of resources. This sequence/set pair can then be used as the basis for adding a page to the document (see pdf_add_page). - + doc: The document for which these are intended. mediabox: The bbox for the created page. diff --git a/include/mupdf/pdf/graft.h b/include/mupdf/pdf/graft.h deleted file mode 100644 index 0b2d8151..00000000 --- a/include/mupdf/pdf/graft.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef MUPDF_PDF_GRAFT_H -#define MUPDF_PDF_GRAFT_H - -typedef struct pdf_graft_map_s pdf_graft_map; - -struct pdf_graft_map_s -{ - int refs; - int len; - int *dst_from_src; -}; - -pdf_graft_map *pdf_new_graft_map(fz_context *ctx, pdf_document *src); -void pdf_drop_graft_map(fz_context *ctx, pdf_graft_map *map); -pdf_obj *pdf_graft_object(fz_context *ctx, pdf_document *dst, pdf_document *src, pdf_obj *obj, pdf_graft_map *map); - -#endif diff --git a/platform/win32/libmupdf.vcproj b/platform/win32/libmupdf.vcproj index f343bd10..7da59040 100644 --- a/platform/win32/libmupdf.vcproj +++ b/platform/win32/libmupdf.vcproj @@ -1409,10 +1409,6 @@ RelativePath="..\..\include\mupdf\pdf\font.h" > - - diff --git a/source/pdf/pdf-graft.c b/source/pdf/pdf-graft.c index bbe5e17b..758addde 100644 --- a/source/pdf/pdf-graft.c +++ b/source/pdf/pdf-graft.c @@ -1,5 +1,13 @@ #include "mupdf/pdf.h" +struct pdf_graft_map_s +{ + int refs; + int len; + pdf_document *src; + int *dst_from_src; +}; + pdf_graft_map * pdf_new_graft_map(fz_context *ctx, pdf_document *src) { @@ -9,6 +17,7 @@ pdf_new_graft_map(fz_context *ctx, pdf_document *src) fz_try(ctx) { + map->src = (pdf_document*) fz_keep_document(ctx, (fz_document*)src); map->len = pdf_xref_len(ctx, src); map->dst_from_src = fz_calloc(ctx, map->len, sizeof(int)); } @@ -34,6 +43,7 @@ pdf_drop_graft_map(fz_context *ctx, pdf_graft_map *map) { if (map && --map->refs == 0) { + fz_drop_document(ctx, (fz_document*)map->src); fz_free(ctx, map->dst_from_src); fz_free(ctx, map); } @@ -50,15 +60,32 @@ pdf_graft_object(fz_context *ctx, pdf_document *dst, pdf_document *src, pdf_obj pdf_obj *ref = NULL; fz_buffer *buffer = NULL; pdf_graft_map *drop_map = NULL; + pdf_document *bound; int new_num, src_num, len, i; + /* Primitive objects are not bound to a document, so can be re-used as is. */ + if (!pdf_is_indirect(ctx, obj_ref) && !pdf_is_dict(ctx, obj_ref) && !pdf_is_array(ctx, obj_ref)) + return pdf_keep_obj(ctx, obj_ref); + if (map == NULL) drop_map = map = pdf_new_graft_map(ctx, src); + else if (src != map->src) + fz_throw(ctx, FZ_ERROR_GENERIC, "graft map does not belong to the source document"); + + bound = pdf_get_bound_document(ctx, obj_ref); + if (bound && bound != src) + fz_throw(ctx, FZ_ERROR_GENERIC, "grafted object does not belong to the source document"); if (pdf_is_indirect(ctx, obj_ref)) { src_num = pdf_to_num(ctx, obj_ref); + if (src_num < 1 || src_num >= map->len) + { + pdf_drop_graft_map(ctx, drop_map); + fz_throw(ctx, FZ_ERROR_GENERIC, "source object number out of range"); + } + /* Check if we have done this one. If yes, then drop map (if allocated) * and return our indirect ref */ if (map->dst_from_src[src_num] != 0) diff --git a/source/tools/murun.c b/source/tools/murun.c index acaa9850..0adb8bc0 100644 --- a/source/tools/murun.c +++ b/source/tools/murun.c @@ -198,6 +198,12 @@ static void ffi_gc_pdf_obj(js_State *J, void *obj) pdf_drop_obj(ctx, obj); } +static void ffi_gc_pdf_graft_map(js_State *J, void *map) +{ + fz_context *ctx = js_getcontext(J); + pdf_drop_graft_map(ctx, map); +} + static void ffi_gc_fz_page(js_State *J, void *page) { fz_context *ctx = js_getcontext(J); @@ -2711,6 +2717,33 @@ static void ffi_PDFDocument_newDictionary(js_State *J) ffi_pushobj(J, obj); } +static void ffi_PDFDocument_newGraftMap(js_State *J) +{ + fz_context *ctx = js_getcontext(J); + pdf_document *pdf = js_touserdata(J, 0, "pdf_document"); + pdf_graft_map *map; + fz_try(ctx) + map = pdf_new_graft_map(ctx, pdf); + fz_catch(ctx) + rethrow(J); + js_getregistry(J, "pdf_graft_map"); + js_newuserdata(J, "pdf_graft_map", map, ffi_gc_pdf_graft_map); +} + +static void ffi_PDFDocument_graftObject(js_State *J) +{ + fz_context *ctx = js_getcontext(J); + pdf_document *dst = js_touserdata(J, 0, "pdf_document"); + pdf_document *src = js_touserdata(J, 1, "pdf_document"); + pdf_obj *obj = js_touserdata(J, 2, "pdf_obj"); + pdf_graft_map *map = js_iscoercible(J, 3) ? js_touserdata(J, 3, "pdf_graft_map") : NULL; + fz_try(ctx) + obj = pdf_graft_object(ctx, dst, src, obj, map); + fz_catch(ctx) + rethrow(J); + ffi_pushobj(J, obj); +} + static void ffi_PDFObject_get(js_State *J) { pdf_obj *obj = js_touserdata(J, 0, "pdf_obj"); @@ -3219,6 +3252,9 @@ int murun_main(int argc, char **argv) jsB_propfun(J, "PDFDocument.newIndirect", ffi_PDFDocument_newIndirect, 2); jsB_propfun(J, "PDFDocument.newArray", ffi_PDFDocument_newArray, 1); jsB_propfun(J, "PDFDocument.newDictionary", ffi_PDFDocument_newDictionary, 1); + + jsB_propfun(J, "PDFDocument.newGraftMap", ffi_PDFDocument_newGraftMap, 0); + jsB_propfun(J, "PDFDocument.graftObject", ffi_PDFDocument_graftObject, 3); } js_setregistry(J, "pdf_document"); @@ -3244,6 +3280,9 @@ int murun_main(int argc, char **argv) } js_setregistry(J, "pdf_obj"); + js_newobject(J); + js_setregistry(J, "pdf_graft_map"); + js_pushglobal(J); { jsB_propcon(J, "pdf_document", "PDFDocument", ffi_new_PDFDocument, 1); -- cgit v1.2.3