Skip to content

Commit 62c87cc

Browse files
src/: cope with use of explicit in MuPDF C++ API.
This will automatically cope with a future change to the MuPDF C++ bindings. The C++ bindings will use `explicit` on constructors of wrapper classes that take a pointer to the underlying wrapped C struct. This will avoids incorrect behaviour where the destructor will drop without a prior keep - we get a build error instead of a runtime segv. The fix in PyMuPDF is to have src/extra.i use a new macro PDF_NAME2() which returns a mupdf::PdfObj instead of a pdf_obj*. No fix is required in Python code because SWIG seems to ignore `explicit` and generates code that explicitly calls the appropriate constructor if (for example) Python code passes a pdf_obj* to a function requiring a PdfObj.
1 parent 66e5b1e commit 62c87cc

File tree

2 files changed

+47
-34
lines changed

2 files changed

+47
-34
lines changed

src/__init__.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18004,7 +18004,16 @@ def final():
1800418004

1800518005
def PDF_NAME(x):
1800618006
assert isinstance(x, str)
18007-
return getattr(mupdf, f'PDF_ENUM_NAME_{x}')
18007+
ret = getattr(mupdf, f'PDF_ENUM_NAME_{x}')
18008+
# Note that we return a (swig proxy for) pdf_obj*, not a mupdf.PdfObj. In
18009+
# the C++ API, the constructor PdfObj::PdfObj(pdf_obj*) is marked as
18010+
# explicit, but this seems to be ignored by SWIG. If SWIG started to
18011+
# generate code that respected `explicit`, we would need to do `return
18012+
# mupdf.PdfObj(ret)`.
18013+
#
18014+
# [Compare with extra.i, where we define our own PDF_NAME2() macro that
18015+
# returns a mupdf::PdfObj.]
18016+
return ret
1800818017

1800918018

1801018019
def UpdateFontInfo(doc: Document, info: typing.Sequence):

src/extra.i

Lines changed: 37 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ catch(...) {
112112
#define MUPDF_VERSION_GE(major, minor, patch) \
113113
MUPDF_VERSION_INT >= MAKE_MUPDF_VERSION_INT(major, minor, patch)
114114

115+
/* Define a wrapper for PDF_NAME that returns a mupdf::PdfObj instead of a
116+
pdf_obj*. This avoids implicit construction of a mupdf::PdfObj, which is
117+
deliberately prohibited (with `explicit` on constructors) by recent MuPDF. */
118+
#define PDF_NAME2(X) mupdf::PdfObj(PDF_NAME(X))
115119

116120
/* Returns equivalent of `repr(x)`. */
117121
static std::string repr(PyObject* x)
@@ -311,7 +315,7 @@ static void page_merge(
311315

312316
// make new page dict in dest doc
313317
mupdf::PdfObj page_dict = mupdf::pdf_new_dict(doc_des, 4);
314-
mupdf::pdf_dict_put(page_dict, PDF_NAME(Type), PDF_NAME(Page));
318+
mupdf::pdf_dict_put(page_dict, PDF_NAME2(Type), PDF_NAME2(Page));
315319

316320
for (int i = 0; i < known_page_objs_num; ++i)
317321
{
@@ -331,25 +335,25 @@ static void page_merge(
331335
// If selected, remove dict keys P (parent) and Popup
332336
if (copy_annots)
333337
{
334-
mupdf::PdfObj old_annots = mupdf::pdf_dict_get(page_ref, PDF_NAME(Annots));
338+
mupdf::PdfObj old_annots = mupdf::pdf_dict_get(page_ref, PDF_NAME2(Annots));
335339
int n = mupdf::pdf_array_len(old_annots);
336340
if (n > 0)
337341
{
338-
mupdf::PdfObj new_annots = mupdf::pdf_dict_put_array(page_dict, PDF_NAME(Annots), n);
342+
mupdf::PdfObj new_annots = mupdf::pdf_dict_put_array(page_dict, PDF_NAME2(Annots), n);
339343
for (int i = 0; i < n; i++)
340344
{
341345
mupdf::PdfObj o = mupdf::pdf_array_get(old_annots, i);
342346
if (!o.m_internal || !mupdf::pdf_is_dict(o)) // skip non-dict items
343347
{
344348
continue; // skip invalid/null/non-dict items
345349
}
346-
if (mupdf::pdf_dict_get(o, PDF_NAME(IRT)).m_internal) continue;
347-
mupdf::PdfObj subtype = mupdf::pdf_dict_get(o, PDF_NAME(Subtype));
348-
if (mupdf::pdf_name_eq(subtype, PDF_NAME(Link))) continue;
349-
if (mupdf::pdf_name_eq(subtype, PDF_NAME(Popup))) continue;
350-
if (mupdf::pdf_name_eq(subtype, PDF_NAME(Widget))) continue;
351-
mupdf::pdf_dict_del(o, PDF_NAME(Popup));
352-
mupdf::pdf_dict_del(o, PDF_NAME(P));
350+
if (mupdf::pdf_dict_get(o, PDF_NAME2(IRT)).m_internal) continue;
351+
mupdf::PdfObj subtype = mupdf::pdf_dict_get(o, PDF_NAME2(Subtype));
352+
if (mupdf::pdf_name_eq(subtype, PDF_NAME2(Link))) continue;
353+
if (mupdf::pdf_name_eq(subtype, PDF_NAME2(Popup))) continue;
354+
if (mupdf::pdf_name_eq(subtype, PDF_NAME2(Widget))) continue;
355+
mupdf::pdf_dict_del(o, PDF_NAME2(Popup));
356+
mupdf::pdf_dict_del(o, PDF_NAME2(P));
353357
mupdf::PdfObj copy_o = mupdf::pdf_graft_mapped_object(graft_map, o);
354358
mupdf::PdfObj annot = mupdf::pdf_new_indirect(
355359
doc_des,
@@ -363,7 +367,7 @@ static void page_merge(
363367
// rotate the page
364368
if (rotate != -1)
365369
{
366-
mupdf::pdf_dict_put_int(page_dict, PDF_NAME(Rotate), rotate);
370+
mupdf::pdf_dict_put_int(page_dict, PDF_NAME2(Rotate), rotate);
367371
}
368372
// Now add the page dictionary to dest PDF
369373
mupdf::PdfObj ref = mupdf::pdf_add_object(doc_des, page_dict);
@@ -533,7 +537,7 @@ static void _newPage(mupdf::FzDocument& self, int pno=-1, float width=595, float
533537
static std::vector< std::string> JM_get_annot_id_list(mupdf::PdfPage& page)
534538
{
535539
std::vector< std::string> names;
536-
mupdf::PdfObj annots = mupdf::pdf_dict_get(page.obj(), PDF_NAME(Annots));
540+
mupdf::PdfObj annots = mupdf::pdf_dict_get(page.obj(), PDF_NAME2(Annots));
537541
if (!annots.m_internal) return names;
538542
int n = mupdf::pdf_array_len(annots);
539543
for (int i = 0; i < n; i++)
@@ -602,7 +606,7 @@ static const char* Tools_parse_da(mupdf::PdfAnnot& this_annot)
602606
mupdf::PdfDocument pdf = mupdf::pdf_get_bound_document(this_annot_obj);
603607
try
604608
{
605-
mupdf::PdfObj da = mupdf::pdf_dict_get_inheritable(this_annot_obj, PDF_NAME(DA));
609+
mupdf::PdfObj da = mupdf::pdf_dict_get_inheritable(this_annot_obj, PDF_NAME2(DA));
606610
if (!da.m_internal)
607611
{
608612
mupdf::PdfObj trailer = mupdf::pdf_trailer(pdf);
@@ -661,9 +665,9 @@ static PyObject* Annot_getAP(mupdf::PdfAnnot& annot)
661665
void Tools_update_da(mupdf::PdfAnnot& this_annot, const char* da_str)
662666
{
663667
mupdf::PdfObj this_annot_obj = mupdf::pdf_annot_obj(this_annot);
664-
mupdf::pdf_dict_put_text_string(this_annot_obj, PDF_NAME(DA), da_str);
665-
mupdf::pdf_dict_del(this_annot_obj, PDF_NAME(DS)); /* not supported */
666-
mupdf::pdf_dict_del(this_annot_obj, PDF_NAME(RC)); /* not supported */
668+
mupdf::pdf_dict_put_text_string(this_annot_obj, PDF_NAME2(DA), da_str);
669+
mupdf::pdf_dict_del(this_annot_obj, PDF_NAME2(DS)); /* not supported */
670+
mupdf::pdf_dict_del(this_annot_obj, PDF_NAME2(RC)); /* not supported */
667671
}
668672

669673
static int
@@ -813,21 +817,21 @@ static PyObject* JM_outline_xrefs(mupdf::PdfObj obj, PyObject* xrefs)
813817
int nxr = mupdf::pdf_to_num(thisobj);
814818
newxref = PyLong_FromLong((long) nxr);
815819
if (PySequence_Contains(xrefs, newxref)
816-
or mupdf::pdf_dict_get(thisobj, PDF_NAME(Type)).m_internal
820+
or mupdf::pdf_dict_get(thisobj, PDF_NAME2(Type)).m_internal
817821
)
818822
{
819823
// circular ref or top of chain: terminate
820824
Py_DECREF(newxref);
821825
break;
822826
}
823827
s_list_append_drop(xrefs, newxref);
824-
mupdf::PdfObj first = mupdf::pdf_dict_get(thisobj, PDF_NAME(First)); // try go down
828+
mupdf::PdfObj first = mupdf::pdf_dict_get(thisobj, PDF_NAME2(First)); // try go down
825829
if (mupdf::pdf_is_dict(first))
826830
{
827831
xrefs = JM_outline_xrefs(first, xrefs);
828832
}
829-
thisobj = mupdf::pdf_dict_get(thisobj, PDF_NAME(Next)); // try go next
830-
mupdf::PdfObj parent = mupdf::pdf_dict_get(thisobj, PDF_NAME(Parent)); // get parent
833+
thisobj = mupdf::pdf_dict_get(thisobj, PDF_NAME2(Next)); // try go next
834+
mupdf::PdfObj parent = mupdf::pdf_dict_get(thisobj, PDF_NAME2(Parent)); // get parent
831835
if (!mupdf::pdf_is_dict(thisobj))
832836
{
833837
thisobj = parent;
@@ -938,13 +942,13 @@ static void Document_extend_toc_items(mupdf::PdfDocument& pdf, PyObject* items)
938942
Py_ssize_t n;
939943
Py_ssize_t m;
940944

941-
root = mupdf::pdf_dict_get(mupdf::pdf_trailer(pdf), PDF_NAME(Root));
945+
root = mupdf::pdf_dict_get(mupdf::pdf_trailer(pdf), PDF_NAME2(Root));
942946
if (!root.m_internal) goto end;
943947

944-
olroot = mupdf::pdf_dict_get(root, PDF_NAME(Outlines));
948+
olroot = mupdf::pdf_dict_get(root, PDF_NAME2(Outlines));
945949
if (!olroot.m_internal) goto end;
946950

947-
first = mupdf::pdf_dict_get(olroot, PDF_NAME(First));
951+
first = mupdf::pdf_dict_get(olroot, PDF_NAME2(First));
948952
if (!first.m_internal) goto end;
949953

950954
xrefs = PyList_New(0); // pre-allocate an empty list
@@ -970,7 +974,7 @@ static void Document_extend_toc_items(mupdf::PdfDocument& pdf, PyObject* items)
970974
}
971975
PyDict_SetItem(itemdict, dictkey_xref, PySequence_ITEM(xrefs, i));
972976
mupdf::PdfObj bm = mupdf::pdf_load_object(pdf, xref);
973-
int flags = mupdf::pdf_to_int(mupdf::pdf_dict_get(bm, PDF_NAME(F)));
977+
int flags = mupdf::pdf_to_int(mupdf::pdf_dict_get(bm, PDF_NAME2(F)));
974978
if (flags == 1)
975979
{
976980
PyDict_SetItem(itemdict, italic, Py_True);
@@ -984,7 +988,7 @@ static void Document_extend_toc_items(mupdf::PdfDocument& pdf, PyObject* items)
984988
PyDict_SetItem(itemdict, italic, Py_True);
985989
PyDict_SetItem(itemdict, bold, Py_True);
986990
}
987-
int count = mupdf::pdf_to_int(mupdf::pdf_dict_get(bm, PDF_NAME(Count)));
991+
int count = mupdf::pdf_to_int(mupdf::pdf_dict_get(bm, PDF_NAME2(Count)));
988992
if (count < 0)
989993
{
990994
PyDict_SetItem(itemdict, collapse, Py_True);
@@ -993,7 +997,7 @@ static void Document_extend_toc_items(mupdf::PdfDocument& pdf, PyObject* items)
993997
{
994998
PyDict_SetItem(itemdict, collapse, Py_False);
995999
}
996-
mupdf::PdfObj col = mupdf::pdf_dict_get(bm, PDF_NAME(C));
1000+
mupdf::PdfObj col = mupdf::pdf_dict_get(bm, PDF_NAME2(C));
9971001
if (mupdf::pdf_is_array(col) && mupdf::pdf_array_len(col) == 3)
9981002
{
9991003
PyObject* color = PyTuple_New(3);
@@ -1003,7 +1007,7 @@ static void Document_extend_toc_items(mupdf::PdfDocument& pdf, PyObject* items)
10031007
dict_setitem_drop(itemdict, dictkey_color, color);
10041008
}
10051009
float z=0;
1006-
mupdf::PdfObj obj = mupdf::pdf_dict_get(bm, PDF_NAME(Dest));
1010+
mupdf::PdfObj obj = mupdf::pdf_dict_get(bm, PDF_NAME2(Dest));
10071011
if (!obj.m_internal || !mupdf::pdf_is_array(obj))
10081012
{
10091013
obj = mupdf::pdf_dict_getl(&bm, PDF_NAME(A), PDF_NAME(D), nullptr);
@@ -1164,7 +1168,7 @@ static int JM_page_rotation(mupdf::PdfPage& page)
11641168
{
11651169
int rotate = 0;
11661170
rotate = mupdf::pdf_to_int(
1167-
mupdf::pdf_dict_get_inheritable(page.obj(), PDF_NAME(Rotate))
1171+
mupdf::pdf_dict_get_inheritable(page.obj(), PDF_NAME2(Rotate))
11681172
);
11691173
rotate = JM_norm_rotation(rotate);
11701174
return rotate;
@@ -1177,7 +1181,7 @@ static int JM_page_rotation(mupdf::PdfPage& page)
11771181
static mupdf::FzRect JM_mediabox(mupdf::PdfObj& page_obj)
11781182
{
11791183
mupdf::FzRect mediabox = mupdf::pdf_to_rect(
1180-
mupdf::pdf_dict_get_inheritable(page_obj, PDF_NAME(MediaBox))
1184+
mupdf::pdf_dict_get_inheritable(page_obj, PDF_NAME2(MediaBox))
11811185
);
11821186
if (mupdf::fz_is_empty_rect(mediabox) || mupdf::fz_is_infinite_rect(mediabox))
11831187
{
@@ -1209,7 +1213,7 @@ mupdf::FzRect JM_cropbox(mupdf::PdfObj& page_obj)
12091213
{
12101214
mupdf::FzRect mediabox = JM_mediabox(page_obj);
12111215
mupdf::FzRect cropbox = mupdf::pdf_to_rect(
1212-
mupdf::pdf_dict_get_inheritable(page_obj, PDF_NAME(CropBox))
1216+
mupdf::pdf_dict_get_inheritable(page_obj, PDF_NAME2(CropBox))
12131217
);
12141218
if (mupdf::fz_is_infinite_rect(cropbox) || mupdf::fz_is_empty_rect(cropbox))
12151219
{
@@ -1463,11 +1467,11 @@ PyObject* Page_addAnnot_FromString(mupdf::PdfPage& page, PyObject* linklist)
14631467
{
14641468
throw std::runtime_error(MSG_IS_NO_PDF);
14651469
}
1466-
if (!mupdf::pdf_dict_get(page.obj(), PDF_NAME(Annots)).m_internal)
1470+
if (!mupdf::pdf_dict_get(page.obj(), PDF_NAME2(Annots)).m_internal)
14671471
{
1468-
mupdf::pdf_dict_put_array(page.obj(), PDF_NAME(Annots), lcount);
1472+
mupdf::pdf_dict_put_array(page.obj(), PDF_NAME2(Annots), lcount);
14691473
}
1470-
mupdf::PdfObj annots = mupdf::pdf_dict_get(page.obj(), PDF_NAME(Annots));
1474+
mupdf::PdfObj annots = mupdf::pdf_dict_get(page.obj(), PDF_NAME2(Annots));
14711475
mupdf::PdfDocument doc = page.doc();
14721476
//printf("lcount=%i\n", lcount);
14731477
fz_context* ctx = mupdf::internal_context_get();

0 commit comments

Comments
 (0)