1 /*
2 libxslt.c: this module implements the main part of the glue of the
3 * libxslt library and the Python interpreter. It provides the
4 * entry points where an automatically generated stub is either
5 * unpractical or would not match cleanly the Python model.
6 *
7 * If compiled with MERGED_MODULES, the entry point will be used to
8 * initialize both the libxml2 and the libxslt wrappers
9 *
10 * See Copyright for the status of this software.
11 *
12 * daniel@veillard.com
13 */
14 #include <Python.h>
15 /* #include "config.h" */
16 #include <libxml/xmlmemory.h>
17 #include <libxml/tree.h>
18 #include <libxml/xpath.h>
19 #include "libexslt/exslt.h"
20 #include "libxslt_wrap.h"
21 #include "libxslt-py.h"
22
23 #include <stdio.h>
24 #include <stddef.h>
25
26 #ifdef _MSC_VER
27
28 /* snprintf emulation taken from http://stackoverflow.com/a/8712996/1956010 */
29 #if _MSC_VER < 1900
30
31 #include <stdarg.h>
32
33 #define vsnprintf c99_vsnprintf
34
c99_vsnprintf(char * outBuf,size_t size,const char * format,va_list ap)35 __inline int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap)
36 {
37 int count = -1;
38
39 if (size != 0)
40 count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
41 if (count == -1)
42 count = _vscprintf(format, ap);
43
44 return count;
45 }
46
47 #endif /* _MSC_VER < 1900 */
48
49 #elif defined(XSLT_NEED_TRIO)
50 #include "trio.h"
51 #define vsnprintf trio_vsnprintf
52 #endif
53
54 /* #define DEBUG */
55 /* #define DEBUG_XPATH */
56 /* #define DEBUG_ERROR */
57 /* #define DEBUG_MEMORY */
58 /* #define DEBUG_EXTENSIONS */
59 /* #define DEBUG_EXTENSIONS */
60
61 void initlibxsltmod(void);
62
63 /************************************************************************
64 * *
65 * Per type specific glue *
66 * *
67 ************************************************************************/
68
69 PyObject *
libxslt_xsltStylesheetPtrWrap(xsltStylesheetPtr style)70 libxslt_xsltStylesheetPtrWrap(xsltStylesheetPtr style) {
71 PyObject *ret;
72
73 #ifdef DEBUG
74 printf("libxslt_xsltStylesheetPtrWrap: style = %p\n", style);
75 #endif
76 if (style == NULL) {
77 Py_INCREF(Py_None);
78 return(Py_None);
79 }
80 ret = PyCObject_FromVoidPtrAndDesc((void *) style,
81 (char *)"xsltStylesheetPtr", NULL);
82
83 return(ret);
84 }
85
86 PyObject *
libxslt_xsltTransformContextPtrWrap(xsltTransformContextPtr ctxt)87 libxslt_xsltTransformContextPtrWrap(xsltTransformContextPtr ctxt) {
88 PyObject *ret;
89
90 #ifdef DEBUG
91 printf("libxslt_xsltTransformContextPtrWrap: ctxt = %p\n", ctxt);
92 #endif
93 if (ctxt == NULL) {
94 Py_INCREF(Py_None);
95 return(Py_None);
96 }
97 ret = PyCObject_FromVoidPtrAndDesc((void *) ctxt,
98 (char *)"xsltTransformContextPtr", NULL);
99 return(ret);
100 }
101
102 PyObject *
libxslt_xsltElemPreCompPtrWrap(xsltElemPreCompPtr ctxt)103 libxslt_xsltElemPreCompPtrWrap(xsltElemPreCompPtr ctxt) {
104 PyObject *ret;
105
106 #ifdef DEBUG
107 printf("libxslt_xsltElemPreCompPtrWrap: ctxt = %p\n", ctxt);
108 #endif
109 if (ctxt == NULL) {
110 Py_INCREF(Py_None);
111 return(Py_None);
112 }
113 ret = PyCObject_FromVoidPtrAndDesc((void *) ctxt,
114 (char *)"xsltElemPreCompPtr", NULL);
115 return(ret);
116 }
117
118 PyObject *
libxslt_xsltGetTransformContextHashCode(PyObject * self ATTRIBUTE_UNUSED,PyObject * args)119 libxslt_xsltGetTransformContextHashCode(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
120 PyObject *py_tctxt;
121 PyObject *ret;
122 long hash_code;
123 xsltTransformContextPtr tctxt;
124
125 if (!PyArg_ParseTuple(args, (char *)"O:getTransformContextHashCode",
126 &py_tctxt))
127 return NULL;
128
129 tctxt = (xsltTransformContextPtr) PytransformCtxt_Get(py_tctxt);
130 hash_code = (ptrdiff_t) tctxt;
131
132 ret = PyInt_FromLong(hash_code);
133 return ret;
134 }
135
136 PyObject *
libxslt_xsltCompareTransformContextsEqual(PyObject * self ATTRIBUTE_UNUSED,PyObject * args)137 libxslt_xsltCompareTransformContextsEqual(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
138
139 PyObject *py_tctxt1, *py_tctxt2;
140 xsltTransformContextPtr tctxt1, tctxt2;
141
142 if (!PyArg_ParseTuple(args, (char *)"OO:compareTransformContextsEqual",
143 &py_tctxt1, &py_tctxt2))
144 return NULL;
145
146 tctxt1 = (xsltTransformContextPtr) PytransformCtxt_Get(py_tctxt1);
147 tctxt2 = (xsltTransformContextPtr) PytransformCtxt_Get(py_tctxt2);
148
149 if ( tctxt1 == tctxt2 )
150 return Py_BuildValue((char *)"i", 1);
151 else
152 return Py_BuildValue((char *)"i", 0);
153 }
154
155 PyObject *
libxslt_xsltGetStylesheetHashCode(PyObject * self ATTRIBUTE_UNUSED,PyObject * args)156 libxslt_xsltGetStylesheetHashCode(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
157 PyObject *py_style;
158 PyObject *ret;
159 long hash_code;
160 xsltStylesheetPtr style;
161
162 if (!PyArg_ParseTuple(args, (char *)"O:getStylesheetHashCode",
163 &py_style))
164 return NULL;
165
166 style = (xsltStylesheetPtr) Pystylesheet_Get(py_style);
167 hash_code = (ptrdiff_t) style;
168
169 ret = PyInt_FromLong(hash_code);
170 return ret;
171 }
172
173
174 PyObject *
libxslt_xsltCompareStylesheetsEqual(PyObject * self ATTRIBUTE_UNUSED,PyObject * args)175 libxslt_xsltCompareStylesheetsEqual(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
176
177 PyObject *py_style1, *py_style2;
178 xsltStylesheetPtr style1, style2;
179
180 if (!PyArg_ParseTuple(args, (char *)"OO:compareStylesheetsEqual",
181 &py_style1, &py_style2))
182 return NULL;
183
184 style1 = (xsltStylesheetPtr) Pystylesheet_Get(py_style1);
185 style2 = (xsltStylesheetPtr) Pystylesheet_Get(py_style2);
186
187 if ( style1 == style2 )
188 return Py_BuildValue((char *)"i", 1);
189 else
190 return Py_BuildValue((char *)"i", 0);
191 }
192
193 /************************************************************************
194 * *
195 * Extending the API *
196 * *
197 ************************************************************************/
198
199 static xmlHashTablePtr libxslt_extModuleFunctions = NULL;
200 static xmlHashTablePtr libxslt_extModuleElements = NULL;
201 static xmlHashTablePtr libxslt_extModuleElementPreComp = NULL;
202
203 static void
deallocateCallback(void * payload,const xmlChar * name ATTRIBUTE_UNUSED)204 deallocateCallback(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
205 PyObject *function = (PyObject *) payload;
206
207 #ifdef DEBUG_EXTENSIONS
208 printf("deallocateCallback(%s) called\n", name);
209 #endif
210
211 Py_XDECREF(function);
212 }
213
214 static void
deallocateClasse(void * payload,const xmlChar * name ATTRIBUTE_UNUSED)215 deallocateClasse(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
216 PyObject *class = (PyObject *) payload;
217
218 #ifdef DEBUG_EXTENSIONS
219 printf("deallocateClasse(%s) called\n", name);
220 #endif
221
222 Py_XDECREF(class);
223 }
224
225
226 /**
227 * libxslt_xsltElementPreCompCallback
228 * @style: the stylesheet
229 * @inst: the instruction in the stylesheet
230 *
231 * Callback for preprocessing of a custom element
232 */
233 static xsltElemPreCompPtr
libxslt_xsltElementPreCompCallback(xsltStylesheetPtr style,xmlNodePtr inst,xsltTransformFunction function)234 libxslt_xsltElementPreCompCallback(xsltStylesheetPtr style, xmlNodePtr inst,
235 xsltTransformFunction function) {
236 xsltElemPreCompPtr ret;
237 const xmlChar *name;
238 PyObject *args;
239 PyObject *result;
240 PyObject *pyobj_element_f;
241 PyObject *pyobj_precomp_f;
242
243 const xmlChar *ns_uri;
244
245
246 #ifdef DEBUG_EXTENSIONS
247 printf("libxslt_xsltElementPreCompCallback called\n");
248 #endif
249
250 if (style == NULL) {
251 xsltTransformError(NULL, NULL, inst,
252 "libxslt_xsltElementPreCompCallback: no transformation context\n");
253 return (NULL);
254 }
255
256 if (inst == NULL) {
257 xsltTransformError(NULL, style, inst,
258 "libxslt_xsltElementPreCompCallback: no instruction\n");
259 if (style != NULL) style->errors++;
260 return (NULL);
261 }
262
263 if (style == NULL)
264 return (NULL);
265
266 if (inst != NULL && inst->ns != NULL) {
267 name = inst->name;
268 ns_uri = inst->ns->href;
269 } else {
270 xsltTransformError(NULL, style, inst,
271 "libxslt_xsltElementPreCompCallback: internal error bad parameter\n");
272 printf("libxslt_xsltElementPreCompCallback: internal error bad parameter\n");
273 if (style != NULL) style->errors++;
274 return (NULL);
275 }
276
277 /*
278 * Find the functions, they should be there it was there at lookup
279 */
280 pyobj_precomp_f = xmlHashLookup2(libxslt_extModuleElementPreComp,
281 name, ns_uri);
282 if (pyobj_precomp_f == NULL) {
283 xsltTransformError(NULL, style, inst,
284 "libxslt_xsltElementPreCompCallback: internal error, could not find precompile python function!\n");
285 if (style != NULL) style->errors++;
286 return (NULL);
287 }
288
289 pyobj_element_f = xmlHashLookup2(libxslt_extModuleElements,
290 name, ns_uri);
291 if (pyobj_element_f == NULL) {
292 xsltTransformError(NULL, style, inst,
293 "libxslt_xsltElementPreCompCallback: internal error, could not find element python function!\n");
294 if (style != NULL) style->errors++;
295 return (NULL);
296 }
297
298 args = Py_BuildValue((char *)"(OOO)",
299 libxslt_xsltStylesheetPtrWrap(style),
300 libxml_xmlNodePtrWrap(inst),
301 pyobj_element_f);
302
303 Py_INCREF(pyobj_precomp_f); /* Protect refcount against reentrant manipulation of callback hash */
304 result = PyEval_CallObject(pyobj_precomp_f, args);
305 Py_DECREF(pyobj_precomp_f);
306 Py_DECREF(args);
307
308 /* FIXME allow callbacks to return meaningful information to modify compile process */
309 /* If error, do we need to check the result and throw exception? */
310
311 Py_XDECREF(result);
312
313 ret = xsltNewElemPreComp (style, inst, function);
314 return (ret);
315 }
316
317
318 static void
libxslt_xsltElementTransformCallback(xsltTransformContextPtr ctxt,xmlNodePtr node,xmlNodePtr inst,xsltElemPreCompPtr comp)319 libxslt_xsltElementTransformCallback(xsltTransformContextPtr ctxt,
320 xmlNodePtr node,
321 xmlNodePtr inst,
322 xsltElemPreCompPtr comp)
323 {
324 PyObject *args, *result;
325 PyObject *func = NULL;
326 const xmlChar *name;
327 const xmlChar *ns_uri;
328
329 if (ctxt == NULL)
330 return;
331
332 if (inst != NULL && inst->name != NULL && inst->ns != NULL && inst->ns->href != NULL) {
333 name = inst->name;
334 ns_uri = inst->ns->href;
335 } else {
336 printf("libxslt_xsltElementTransformCallback: internal error bad parameter\n");
337 return;
338 }
339
340 #ifdef DEBUG_EXTENSIONS
341 printf("libxslt_xsltElementTransformCallback called name %s URI %s\n", name, ns_uri);
342 #endif
343
344 /*
345 * Find the function, it should be there it was there at lookup
346 */
347 func = xmlHashLookup2(libxslt_extModuleElements,
348 name, ns_uri);
349 if (func == NULL) {
350 printf("libxslt_xsltElementTransformCallback: internal error %s not found !\n",
351 name);
352 return;
353 }
354
355 args = Py_BuildValue((char *)"OOOO",
356 libxslt_xsltTransformContextPtrWrap(ctxt),
357 libxml_xmlNodePtrWrap(node),
358 libxml_xmlNodePtrWrap(inst),
359 libxslt_xsltElemPreCompPtrWrap(comp));
360
361 Py_INCREF(func); /* Protect refcount against reentrant manipulation of callback hash */
362 result = PyEval_CallObject(func, args);
363 Py_DECREF(func);
364 Py_DECREF(args);
365
366 /* FIXME Check result of callobject and set exception if fail */
367
368 Py_XDECREF(result);
369 }
370
371 PyObject *
libxslt_xsltRegisterExtModuleElement(PyObject * self ATTRIBUTE_UNUSED,PyObject * args)372 libxslt_xsltRegisterExtModuleElement(PyObject *self ATTRIBUTE_UNUSED,
373 PyObject *args) {
374 PyObject *py_retval;
375 int ret = 0;
376 xmlChar *name;
377 xmlChar *ns_uri;
378 PyObject *pyobj_element_f;
379 PyObject *pyobj_precomp_f;
380
381 if (!PyArg_ParseTuple(args, (char *)"szOO:registerExtModuleElement",
382 &name, &ns_uri, &pyobj_precomp_f, &pyobj_element_f))
383 return(NULL);
384
385 #ifdef DEBUG_EXTENSIONS
386 printf("libxslt_xsltRegisterExtModuleElement called: %s %s\n",
387 name, ns_uri);
388 #endif
389
390 if ((name == NULL) || (pyobj_element_f == NULL) || (pyobj_precomp_f == NULL)) {
391 py_retval = libxml_intWrap(-1);
392 return(py_retval);
393 }
394
395 #ifdef DEBUG_EXTENSIONS
396 printf("libxslt_xsltRegisterExtModuleElement(%s, %s) called\n",
397 name, ns_uri);
398 #endif
399
400 if (libxslt_extModuleElements == NULL)
401 libxslt_extModuleElements = xmlHashCreate(10);
402
403 if (libxslt_extModuleElementPreComp == NULL)
404 libxslt_extModuleElementPreComp = xmlHashCreate(10);
405
406 if (libxslt_extModuleElements == NULL || libxslt_extModuleElementPreComp == NULL) {
407 py_retval = libxml_intWrap(-1);
408 return(py_retval);
409 }
410
411 ret = xmlHashAddEntry2(libxslt_extModuleElements, name, ns_uri, pyobj_element_f);
412 if (ret != 0) {
413 py_retval = libxml_intWrap(-1);
414 return(py_retval);
415 }
416 Py_XINCREF(pyobj_element_f);
417
418 ret = xmlHashAddEntry2(libxslt_extModuleElementPreComp, name, ns_uri, pyobj_precomp_f);
419 if (ret != 0) {
420 xmlHashRemoveEntry2(libxslt_extModuleElements, name, ns_uri, deallocateCallback);
421 py_retval = libxml_intWrap(-1);
422 return(py_retval);
423 }
424 Py_XINCREF(pyobj_precomp_f);
425
426 ret = xsltRegisterExtModuleElement(name, ns_uri,
427 libxslt_xsltElementPreCompCallback,
428 libxslt_xsltElementTransformCallback);
429 py_retval = libxml_intWrap((int) ret);
430 return(py_retval);
431 }
432 static void
libxslt_xmlXPathFuncCallback(xmlXPathParserContextPtr ctxt,int nargs)433 libxslt_xmlXPathFuncCallback(xmlXPathParserContextPtr ctxt, int nargs) {
434 PyObject *list, *cur, *result;
435 xmlXPathObjectPtr obj;
436 xmlXPathContextPtr rctxt;
437 PyObject *current_function = NULL;
438 const xmlChar *name;
439 const xmlChar *ns_uri;
440 int i;
441
442 if (ctxt == NULL)
443 return;
444 rctxt = ctxt->context;
445 if (rctxt == NULL)
446 return;
447 name = rctxt->function;
448 ns_uri = rctxt->functionURI;
449 #ifdef DEBUG_XPATH
450 printf("libxslt_xmlXPathFuncCallback called name %s URI %s\n", name, ns_uri);
451 #endif
452
453 /*
454 * Find the function, it should be there it was there at lookup
455 */
456 current_function = xmlHashLookup2(libxslt_extModuleFunctions,
457 name, ns_uri);
458 if (current_function == NULL) {
459 printf("libxslt_xmlXPathFuncCallback: internal error %s not found !\n",
460 name);
461 return;
462 }
463
464 list = PyTuple_New(nargs + 1);
465 PyTuple_SetItem(list, 0, libxml_xmlXPathParserContextPtrWrap(ctxt));
466 for (i = nargs - 1;i >= 0;i--) {
467 obj = valuePop(ctxt);
468 cur = libxml_xmlXPathObjectPtrWrap(obj);
469 PyTuple_SetItem(list, i + 1, cur);
470 }
471
472 Py_INCREF(current_function);
473 result = PyEval_CallObject(current_function, list);
474 Py_DECREF(current_function);
475 Py_DECREF(list);
476
477 /* Check for null in case of exception */
478 if (result != NULL) {
479 obj = libxml_xmlXPathObjectPtrConvert(result);
480 valuePush(ctxt, obj);
481 }
482 }
483
484 PyObject *
libxslt_xsltRegisterExtModuleFunction(PyObject * self ATTRIBUTE_UNUSED,PyObject * args)485 libxslt_xsltRegisterExtModuleFunction(PyObject *self ATTRIBUTE_UNUSED,
486 PyObject *args) {
487 PyObject *py_retval;
488 int ret = 0;
489 xmlChar *name;
490 xmlChar *ns_uri;
491 PyObject *pyobj_f;
492
493 if (!PyArg_ParseTuple(args, (char *)"szO:registerExtModuleFunction",
494 &name, &ns_uri, &pyobj_f))
495 return(NULL);
496
497 if ((name == NULL) || (pyobj_f == NULL)) {
498 py_retval = libxml_intWrap(-1);
499 return(py_retval);
500 }
501
502 #ifdef DEBUG_XPATH
503 printf("libxslt_xsltRegisterExtModuleFunction(%s, %s) called\n",
504 name, ns_uri);
505 #endif
506
507 if (libxslt_extModuleFunctions == NULL)
508 libxslt_extModuleFunctions = xmlHashCreate(10);
509 if (libxslt_extModuleFunctions == NULL) {
510 py_retval = libxml_intWrap(-1);
511 return(py_retval);
512 }
513 ret = xmlHashAddEntry2(libxslt_extModuleFunctions, name, ns_uri, pyobj_f);
514 if (ret != 0) {
515 py_retval = libxml_intWrap(-1);
516 return(py_retval);
517 }
518 Py_XINCREF(pyobj_f);
519
520 ret = xsltRegisterExtModuleFunction(name, ns_uri,
521 libxslt_xmlXPathFuncCallback);
522 py_retval = libxml_intWrap((int) ret);
523 return(py_retval);
524 }
525
526
527 /************************************************************************
528 * *
529 * Document loading front-ends *
530 * *
531 ************************************************************************/
532
533 static PyObject *pythonDocLoaderObject = NULL;
534
535 static xmlDocPtr
pythonDocLoaderFuncWrapper(const xmlChar * URI,xmlDictPtr dict,int options,void * ctxt ATTRIBUTE_UNUSED,xsltLoadType type ATTRIBUTE_UNUSED)536 pythonDocLoaderFuncWrapper(const xmlChar * URI, xmlDictPtr dict, int options,
537 void *ctxt ATTRIBUTE_UNUSED,
538 xsltLoadType type ATTRIBUTE_UNUSED)
539 {
540 xmlParserCtxtPtr pctxt;
541 xmlDocPtr doc=NULL;
542
543 pctxt = xmlNewParserCtxt();
544 if (pctxt == NULL)
545 return(NULL);
546 if ((dict != NULL) && (pctxt->dict != NULL)) {
547 xmlDictFree(pctxt->dict);
548 pctxt->dict = NULL;
549 }
550 if (dict != NULL) {
551 pctxt->dict = dict;
552 xmlDictReference(pctxt->dict);
553 #ifdef WITH_XSLT_DEBUG
554 xsltGenericDebug(xsltGenericDebugContext,
555 "Reusing dictionary for document\n");
556 #endif
557 }
558 xmlCtxtUseOptions(pctxt, options);
559
560 /*
561 * Now pass to python the URI, the xsltParserContext and the context
562 * (either a transformContext or a stylesheet) and get back an xmlDocPtr
563 */
564 if (pythonDocLoaderObject != NULL) {
565 PyObject *ctxtobj, *pctxtobj, *result;
566 pctxtobj = libxml_xmlParserCtxtPtrWrap(pctxt);
567
568 if (type == XSLT_LOAD_DOCUMENT) {
569 ctxtobj = libxslt_xsltTransformContextPtrWrap(ctxt);
570 result = PyObject_CallFunction(pythonDocLoaderObject,
571 (char *) "(sOOi)", URI, pctxtobj, ctxtobj, 0);
572 }
573 else {
574 ctxtobj = libxslt_xsltStylesheetPtrWrap(ctxt);
575 result = PyObject_CallFunction(pythonDocLoaderObject,
576 (char *) "(sOOi)", URI, pctxtobj, ctxtobj, 1);
577 }
578
579 Py_XDECREF(pctxtobj);
580
581 if (result != NULL) {
582 /*
583 * The return value should be the document
584 * Should we test it somehow before getting the C object from it?
585 */
586 PyObject *py_doc = PyObject_GetAttrString(result, (char *) "_o");
587 doc = (xmlDocPtr) PyxmlNode_Get(py_doc);
588 /* do we have to DECCREF the result?? */
589 }
590 }
591
592 if (! pctxt->wellFormed) {
593 if (doc != NULL) {
594 xmlFreeDoc(doc);
595 doc = NULL;
596 }
597 if (pctxt->myDoc != NULL) {
598 xmlFreeDoc(pctxt->myDoc);
599 pctxt->myDoc = NULL;
600 }
601 }
602 /*
603 * xmlFreeParserCtxt(pctxt);
604 * libc complains about double free-ing with this line
605 */
606
607 return(doc);
608 }
609
610
611 PyObject *
libxslt_xsltSetLoaderFunc(PyObject * self ATTRIBUTE_UNUSED,PyObject * args)612 libxslt_xsltSetLoaderFunc(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
613 PyObject *py_retval;
614 PyObject *loader;
615
616 if (!PyArg_ParseTuple(args, (char *)"O:libxslt_xsltSetLoaderFunc",
617 &loader))
618 return(NULL);
619
620 pythonDocLoaderObject = loader;
621 xsltSetLoaderFunc(pythonDocLoaderFuncWrapper);
622
623 py_retval = PyInt_FromLong(0);
624 return(py_retval);
625 }
626
627 PyObject *
libxslt_xsltGetLoaderFunc(void)628 libxslt_xsltGetLoaderFunc(void) {
629 PyObject *py_retval;
630
631 py_retval = pythonDocLoaderObject;
632 return(py_retval);
633 }
634
635
636 /************************************************************************
637 * *
638 * Some customized front-ends *
639 * *
640 ************************************************************************/
641
642 PyObject *
libxslt_xsltNewTransformContext(PyObject * self ATTRIBUTE_UNUSED,PyObject * args)643 libxslt_xsltNewTransformContext(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
644 PyObject *py_retval;
645 PyObject *pyobj_style;
646 PyObject *pyobj_doc;
647 xsltStylesheetPtr style;
648 xmlDocPtr doc;
649 xsltTransformContextPtr c_retval;
650
651 if (!PyArg_ParseTuple(args, (char *) "OO:xsltNewTransformContext",
652 &pyobj_style, &pyobj_doc))
653 return(NULL);
654
655 style = (xsltStylesheetPtr) Pystylesheet_Get(pyobj_style);
656 doc = (xmlDocPtr) PyxmlNode_Get(pyobj_doc);
657
658 c_retval = xsltNewTransformContext(style, doc);
659 py_retval = libxslt_xsltTransformContextPtrWrap((xsltTransformContextPtr) c_retval);
660 return (py_retval);
661 }
662
663 PyObject *
libxslt_xsltFreeTransformContext(PyObject * self ATTRIBUTE_UNUSED,PyObject * args)664 libxslt_xsltFreeTransformContext(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
665 PyObject *py_tctxt;
666 xsltTransformContextPtr tctxt;
667
668 if (!PyArg_ParseTuple(args, (char *) "O:xsltFreeTransformContext", &py_tctxt))
669 return(NULL);
670
671 tctxt = (xsltTransformContextPtr) PytransformCtxt_Get(py_tctxt);
672 xsltFreeTransformContext(tctxt);
673
674 /* Return None */
675 Py_INCREF(Py_None);
676 return(Py_None);
677 }
678
679 PyObject *
libxslt_xsltApplyStylesheetUser(PyObject * self ATTRIBUTE_UNUSED,PyObject * args)680 libxslt_xsltApplyStylesheetUser(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
681 PyObject *py_retval;
682 xmlDocPtr c_retval;
683 xsltStylesheetPtr style;
684 PyObject *pyobj_style;
685 xmlDocPtr doc;
686 xsltTransformContextPtr transformCtxt;
687 PyObject *pyobj_doc;
688 PyObject *pyobj_params;
689 PyObject *pyobj_transformCtxt;
690 const char **params = NULL;
691 int len = 0, i, j;
692 ssize_t ppos = 0;
693 PyObject *name;
694 PyObject *value;
695
696 if (!PyArg_ParseTuple(args, (char *) "OOOO:xsltApplyStylesheetUser",
697 &pyobj_style, &pyobj_doc, &pyobj_params, &pyobj_transformCtxt))
698 return(NULL);
699
700 if (pyobj_params != Py_None) {
701 if (PyDict_Check(pyobj_params)) {
702 len = PyDict_Size(pyobj_params);
703 if (len > 0) {
704 params = (const char **) xmlMalloc((len + 1) * 2 *
705 sizeof(char *));
706 if (params == NULL) {
707 printf("libxslt_xsltApplyStylesheet: out of memory\n");
708 Py_INCREF(Py_None);
709 return(Py_None);
710 }
711 j = 0;
712 while (PyDict_Next(pyobj_params, &ppos, &name, &value)) {
713 const char *tmp;
714 int size;
715
716 tmp = PyString_AS_STRING(name);
717 size = PyString_GET_SIZE(name);
718 params[j * 2] = (char *) xmlCharStrndup(tmp, size);
719 if (PyString_Check(value)) {
720 tmp = PyString_AS_STRING(value);
721 size = PyString_GET_SIZE(value);
722 params[(j * 2) + 1] = (char *)
723 xmlCharStrndup(tmp, size);
724 } else {
725 params[(j * 2) + 1] = NULL;
726 }
727 j = j + 1;
728 }
729 params[j * 2] = NULL;
730 params[(j * 2) + 1] = NULL;
731 }
732 } else {
733 printf("libxslt_xsltApplyStylesheet: parameters not a dict\n");
734 Py_INCREF(Py_None);
735 return(Py_None);
736 }
737 }
738 style = (xsltStylesheetPtr) Pystylesheet_Get(pyobj_style);
739 doc = (xmlDocPtr) PyxmlNode_Get(pyobj_doc);
740 transformCtxt = (xsltTransformContextPtr) PytransformCtxt_Get(pyobj_transformCtxt);
741
742 c_retval = xsltApplyStylesheetUser(style, doc, params, NULL, NULL, transformCtxt);
743 py_retval = libxml_xmlDocPtrWrap((xmlDocPtr) c_retval);
744 if (params != NULL) {
745 if (len > 0) {
746 for (i = 0;i < 2 * len;i++) {
747 if (params[i] != NULL)
748 xmlFree((char *)params[i]);
749 }
750 xmlFree(params);
751 }
752 }
753 return(py_retval);
754 }
755
756 PyObject *
libxslt_xsltApplyStylesheet(PyObject * self ATTRIBUTE_UNUSED,PyObject * args)757 libxslt_xsltApplyStylesheet(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
758 PyObject *py_retval;
759 xmlDocPtr c_retval;
760 xsltStylesheetPtr style;
761 PyObject *pyobj_style;
762 xmlDocPtr doc;
763 PyObject *pyobj_doc;
764 PyObject *pyobj_params;
765 const char **params = NULL;
766 int len = 0, i, j, params_size;
767 ssize_t ppos = 0;
768 PyObject *name;
769 PyObject *value;
770
771 if (!PyArg_ParseTuple(args, (char *) "OOO:xsltApplyStylesheet",
772 &pyobj_style, &pyobj_doc, &pyobj_params))
773 return(NULL);
774
775 if (pyobj_params != Py_None) {
776 if (PyDict_Check(pyobj_params)) {
777 len = PyDict_Size(pyobj_params);
778 if (len > 0) {
779 params_size = (len + 1) * 2 * sizeof(char *);
780 params = (const char **) xmlMalloc(params_size);
781 if (params == NULL) {
782 printf("libxslt_xsltApplyStylesheet: out of memory\n");
783 Py_INCREF(Py_None);
784 return(Py_None);
785 }
786 memset(params, 0, params_size);
787 j = 0;
788 while (PyDict_Next(pyobj_params, &ppos, &name, &value)) {
789 const char *tmp;
790 int size;
791
792 tmp = PyString_AS_STRING(name);
793 size = PyString_GET_SIZE(name);
794 params[j * 2] = (char *) xmlCharStrndup(tmp, size);
795 if (PyString_Check(value)) {
796 tmp = PyString_AS_STRING(value);
797 size = PyString_GET_SIZE(value);
798 params[(j * 2) + 1] = (char *)
799 xmlCharStrndup(tmp, size);
800 } else {
801 params[(j * 2) + 1] = NULL;
802 }
803 j = j + 1;
804 }
805 params[j * 2] = NULL;
806 params[(j * 2) + 1] = NULL;
807 }
808 } else {
809 printf("libxslt_xsltApplyStylesheet: parameters not a dict\n");
810 Py_INCREF(Py_None);
811 return(Py_None);
812 }
813 }
814 style = (xsltStylesheetPtr) Pystylesheet_Get(pyobj_style);
815 doc = (xmlDocPtr) PyxmlNode_Get(pyobj_doc);
816
817 c_retval = xsltApplyStylesheet(style, doc, params);
818 py_retval = libxml_xmlDocPtrWrap((xmlDocPtr) c_retval);
819 if (params != NULL) {
820 if (len > 0) {
821 for (i = 0;i < 2 * len;i++) {
822 if (params[i] != NULL)
823 xmlFree((char *)params[i]);
824 }
825 xmlFree(params);
826 }
827 }
828 return(py_retval);
829 }
830
831 PyObject *
libxslt_xsltSaveResultToString(PyObject * self ATTRIBUTE_UNUSED,PyObject * args)832 libxslt_xsltSaveResultToString(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
833 PyObject *py_retval; /* our final return value, a python string */
834 xmlChar *buffer;
835 int size = 0;
836 int emitted = 0;
837 xmlDocPtr result;
838 PyObject *pyobj_result;
839 xsltStylesheetPtr style;
840 PyObject *pyobj_style;
841
842 if (!PyArg_ParseTuple(args, (char *)"OO:xsltSaveResultToString", &pyobj_style, &pyobj_result))
843 goto FAIL;
844 result = (xmlDocPtr) PyxmlNode_Get(pyobj_result);
845 style = (xsltStylesheetPtr) Pystylesheet_Get(pyobj_style);
846
847
848 /* FIXME: We should probably add more restrictive error checking
849 * and raise an error instead of "just" returning NULL.
850 * FIXME: Documentation and code for xsltSaveResultToString diff
851 * -> emmitted will never be positive non-null.
852 */
853 emitted = xsltSaveResultToString(&buffer, &size, result, style);
854 if(!buffer || emitted < 0)
855 goto FAIL;
856 /* We haven't tested the aberrant case of a transformation that
857 * renders to an empty string. For now we try to play it safe.
858 */
859 if(size)
860 {
861 buffer[size] = '\0';
862 py_retval = PyString_FromString((char *) buffer);
863 xmlFree(buffer);
864 }
865 else
866 py_retval = PyString_FromString("");
867 return(py_retval);
868 FAIL:
869 return(0);
870 }
871
872
873 /************************************************************************
874 * *
875 * Error message callback *
876 * *
877 ************************************************************************/
878
879 static PyObject *libxslt_xsltPythonErrorFuncHandler = NULL;
880 static PyObject *libxslt_xsltPythonErrorFuncCtxt = NULL;
881
882 static void LIBXSLT_ATTR_FORMAT(2,3)
libxslt_xsltErrorFuncHandler(void * ctx ATTRIBUTE_UNUSED,const char * msg,...)883 libxslt_xsltErrorFuncHandler(void *ctx ATTRIBUTE_UNUSED, const char *msg,
884 ...)
885 {
886 int size;
887 int chars;
888 char *larger;
889 va_list ap;
890 char *str;
891 PyObject *list;
892 PyObject *message;
893 PyObject *result;
894
895 #ifdef DEBUG_ERROR
896 printf("libxslt_xsltErrorFuncHandler(%p, %s, ...) called\n", ctx, msg);
897 #endif
898
899
900 if (libxslt_xsltPythonErrorFuncHandler == NULL) {
901 va_start(ap, msg);
902 vfprintf(stderr, msg, ap);
903 va_end(ap);
904 } else {
905 str = (char *) xmlMalloc(150);
906 if (str == NULL)
907 return;
908
909 size = 150;
910
911 while (1) {
912 va_start(ap, msg);
913 chars = vsnprintf(str, size, msg, ap);
914 va_end(ap);
915 if ((chars > -1) && (chars < size))
916 break;
917 if (chars > -1)
918 size += chars + 1;
919 else
920 size += 100;
921 if ((larger = (char *) xmlRealloc(str, size)) == NULL) {
922 xmlFree(str);
923 return;
924 }
925 str = larger;
926 }
927
928 list = PyTuple_New(2);
929 PyTuple_SetItem(list, 0, libxslt_xsltPythonErrorFuncCtxt);
930 Py_XINCREF(libxslt_xsltPythonErrorFuncCtxt);
931 message = libxml_charPtrWrap(str);
932 PyTuple_SetItem(list, 1, message);
933 result = PyEval_CallObject(libxslt_xsltPythonErrorFuncHandler, list);
934 Py_XDECREF(list);
935 Py_XDECREF(result);
936 }
937 }
938
939 static void
libxslt_xsltErrorInitialize(void)940 libxslt_xsltErrorInitialize(void)
941 {
942 #ifdef DEBUG_ERROR
943 printf("libxslt_xsltErrorInitialize() called\n");
944 #endif
945 xmlSetGenericErrorFunc(NULL, libxslt_xsltErrorFuncHandler);
946 xsltSetGenericErrorFunc(NULL, libxslt_xsltErrorFuncHandler);
947 }
948
949 PyObject *
libxslt_xsltRegisterErrorHandler(PyObject * self ATTRIBUTE_UNUSED,PyObject * args)950 libxslt_xsltRegisterErrorHandler(PyObject * self ATTRIBUTE_UNUSED,
951 PyObject * args)
952 {
953 PyObject *py_retval;
954 PyObject *pyobj_f;
955 PyObject *pyobj_ctx;
956
957 if (!PyArg_ParseTuple
958 (args, (char *) "OO:xmlRegisterErrorHandler", &pyobj_f,
959 &pyobj_ctx))
960 return (NULL);
961
962 #ifdef DEBUG_ERROR
963 printf("libxml_registerXPathFunction(%p, %p) called\n", pyobj_ctx,
964 pyobj_f);
965 #endif
966
967 if (libxslt_xsltPythonErrorFuncHandler != NULL) {
968 Py_XDECREF(libxslt_xsltPythonErrorFuncHandler);
969 }
970 if (libxslt_xsltPythonErrorFuncCtxt != NULL) {
971 Py_XDECREF(libxslt_xsltPythonErrorFuncCtxt);
972 }
973
974 Py_XINCREF(pyobj_ctx);
975 Py_XINCREF(pyobj_f);
976
977 /* TODO: check f is a function ! */
978 libxslt_xsltPythonErrorFuncHandler = pyobj_f;
979 libxslt_xsltPythonErrorFuncCtxt = pyobj_ctx;
980
981 py_retval = libxml_intWrap(1);
982 return (py_retval);
983 }
984
985 /************************************************************************
986 * *
987 * Extension classes *
988 * *
989 ************************************************************************/
990
991 static xmlHashTablePtr libxslt_extModuleClasses = NULL;
992
993 static void *
libxslt_xsltPythonExtModuleStyleInit(xsltStylesheetPtr style,const xmlChar * URI)994 libxslt_xsltPythonExtModuleStyleInit(xsltStylesheetPtr style,
995 const xmlChar * URI) {
996 PyObject *result = NULL;
997 PyObject *class = NULL;
998
999 #ifdef DEBUG_EXTENSIONS
1000 printf("libxslt_xsltPythonExtModuleStyleInit(%p, %s) called\n",
1001 style, URI);
1002 #endif
1003
1004 if ((style == NULL) || (URI == NULL))
1005 return(NULL);
1006
1007 /*
1008 * Find the function, it should be there it was there at lookup
1009 */
1010 class = xmlHashLookup(libxslt_extModuleClasses, URI);
1011 if (class == NULL) {
1012 fprintf(stderr, "libxslt_xsltPythonExtModuleStyleInit: internal error %s not found !\n", URI);
1013 return(NULL);
1014 }
1015
1016 if (PyObject_HasAttrString(class, (char *) "_styleInit")) {
1017 result = PyObject_CallMethod(class, (char *) "_styleInit",
1018 (char *) "Os", libxslt_xsltStylesheetPtrWrap(style), URI);
1019 }
1020 return((void *)result);
1021 }
1022 static void
libxslt_xsltPythonExtModuleStyleShutdown(xsltStylesheetPtr style,const xmlChar * URI,void * data)1023 libxslt_xsltPythonExtModuleStyleShutdown(xsltStylesheetPtr style,
1024 const xmlChar * URI, void *data) {
1025 PyObject *class = NULL;
1026 PyObject *result;
1027
1028 #ifdef DEBUG_EXTENSIONS
1029 printf("libxslt_xsltPythonExtModuleStyleShutdown(%p, %s, %p) called\n",
1030 style, URI, data);
1031 #endif
1032
1033 if ((style == NULL) || (URI == NULL))
1034 return;
1035
1036 /*
1037 * Find the function, it should be there it was there at lookup
1038 */
1039 class = xmlHashLookup(libxslt_extModuleClasses, URI);
1040 if (class == NULL) {
1041 fprintf(stderr, "libxslt_xsltPythonExtModuleStyleShutdown: internal error %s not found !\n", URI);
1042 return;
1043 }
1044
1045 if (PyObject_HasAttrString(class, (char *) "_styleShutdown")) {
1046 result = PyObject_CallMethod(class, (char *) "_styleShutdown",
1047 (char *) "OsO", libxslt_xsltStylesheetPtrWrap(style),
1048 URI, (PyObject *) data);
1049 Py_XDECREF(result);
1050 Py_XDECREF((PyObject *)data);
1051 }
1052 }
1053
1054 static void *
libxslt_xsltPythonExtModuleCtxtInit(xsltTransformContextPtr ctxt,const xmlChar * URI)1055 libxslt_xsltPythonExtModuleCtxtInit(xsltTransformContextPtr ctxt,
1056 const xmlChar * URI) {
1057 PyObject *result = NULL;
1058 PyObject *class = NULL;
1059
1060 #ifdef DEBUG_EXTENSIONS
1061 printf("libxslt_xsltPythonExtModuleCtxtInit(%p, %s) called\n",
1062 ctxt, URI);
1063 #endif
1064
1065 if ((ctxt == NULL) || (URI == NULL))
1066 return(NULL);
1067
1068 /*
1069 * Find the function, it should be there it was there at lookup
1070 */
1071 class = xmlHashLookup(libxslt_extModuleClasses, URI);
1072 if (class == NULL) {
1073 fprintf(stderr, "libxslt_xsltPythonExtModuleCtxtInit: internal error %s not found !\n", URI);
1074 return(NULL);
1075 }
1076
1077 if (PyObject_HasAttrString(class, (char *) "_ctxtInit")) {
1078 result = PyObject_CallMethod(class, (char *) "_ctxtInit",
1079 (char *) "Os", libxslt_xsltTransformContextPtrWrap(ctxt),
1080 URI);
1081 }
1082 return((void *)result);
1083 }
1084 static void
libxslt_xsltPythonExtModuleCtxtShutdown(xsltTransformContextPtr ctxt,const xmlChar * URI,void * data)1085 libxslt_xsltPythonExtModuleCtxtShutdown(xsltTransformContextPtr ctxt,
1086 const xmlChar * URI, void *data) {
1087 PyObject *class = NULL;
1088 PyObject *result;
1089
1090 #ifdef DEBUG_EXTENSIONS
1091 printf("libxslt_xsltPythonExtModuleCtxtShutdown(%p, %s, %p) called\n",
1092 ctxt, URI, data);
1093 #endif
1094
1095 if ((ctxt == NULL) || (URI == NULL))
1096 return;
1097
1098 /*
1099 * Find the function, it should be there it was there at lookup
1100 */
1101 class = xmlHashLookup(libxslt_extModuleClasses, URI);
1102 if (class == NULL) {
1103 fprintf(stderr, "libxslt_xsltPythonExtModuleCtxtShutdown: internal error %s not found !\n", URI);
1104 return;
1105 }
1106
1107 if (PyObject_HasAttrString(class, (char *) "_ctxtShutdown")) {
1108 result = PyObject_CallMethod(class, (char *) "_ctxtShutdown",
1109 (char *) "OsO", libxslt_xsltTransformContextPtrWrap(ctxt),
1110 URI, (PyObject *) data);
1111 Py_XDECREF(result);
1112 Py_XDECREF((PyObject *)data);
1113 }
1114 }
1115
1116 PyObject *
libxslt_xsltRegisterExtensionClass(PyObject * self ATTRIBUTE_UNUSED,PyObject * args)1117 libxslt_xsltRegisterExtensionClass(PyObject *self ATTRIBUTE_UNUSED,
1118 PyObject *args) {
1119 PyObject *py_retval;
1120 int ret = 0;
1121 xmlChar *ns_uri;
1122 PyObject *pyobj_c;
1123
1124 if (!PyArg_ParseTuple(args, (char *)"zO:registerExtensionClass",
1125 &ns_uri, &pyobj_c))
1126 return(NULL);
1127
1128 if ((ns_uri == NULL) || (pyobj_c == NULL)) {
1129 py_retval = libxml_intWrap(-1);
1130 return(py_retval);
1131 }
1132
1133 #ifdef DEBUG_EXTENSIONS
1134 printf("libxslt_xsltRegisterExtensionClass(%s) called\n", ns_uri);
1135 #endif
1136
1137 if (libxslt_extModuleClasses == NULL)
1138 libxslt_extModuleClasses = xmlHashCreate(10);
1139 if (libxslt_extModuleClasses == NULL) {
1140 py_retval = libxml_intWrap(-1);
1141 return(py_retval);
1142 }
1143 ret = xmlHashAddEntry(libxslt_extModuleClasses, ns_uri, pyobj_c);
1144 if (ret != 0) {
1145 py_retval = libxml_intWrap(-1);
1146 return(py_retval);
1147 }
1148 Py_XINCREF(pyobj_c);
1149
1150 ret = xsltRegisterExtModuleFull(ns_uri,
1151 libxslt_xsltPythonExtModuleCtxtInit,
1152 libxslt_xsltPythonExtModuleCtxtShutdown,
1153 libxslt_xsltPythonExtModuleStyleInit,
1154 libxslt_xsltPythonExtModuleStyleShutdown);
1155 py_retval = libxml_intWrap((int) ret);
1156 if (ret < 0) {
1157 Py_XDECREF(pyobj_c);
1158 }
1159 return(py_retval);
1160 }
1161
1162 /************************************************************************
1163 * *
1164 * Integrated cleanup *
1165 * *
1166 ************************************************************************/
1167
1168 PyObject *
libxslt_xsltPythonCleanup(PyObject * self ATTRIBUTE_UNUSED,PyObject * args ATTRIBUTE_UNUSED)1169 libxslt_xsltPythonCleanup(PyObject *self ATTRIBUTE_UNUSED,
1170 PyObject *args ATTRIBUTE_UNUSED) {
1171
1172 if (libxslt_extModuleFunctions != NULL) {
1173 xmlHashFree(libxslt_extModuleFunctions, deallocateCallback);
1174 }
1175 if (libxslt_extModuleElements != NULL) {
1176 xmlHashFree(libxslt_extModuleElements, deallocateCallback);
1177 }
1178 if (libxslt_extModuleElementPreComp != NULL) {
1179 xmlHashFree(libxslt_extModuleElementPreComp, deallocateCallback);
1180 }
1181 if (libxslt_extModuleClasses != NULL) {
1182 xmlHashFree(libxslt_extModuleClasses, deallocateClasse);
1183 }
1184 xsltCleanupGlobals();
1185 Py_INCREF(Py_None);
1186 return(Py_None);
1187 }
1188
1189 /************************************************************************
1190 * *
1191 * The registration stuff *
1192 * *
1193 ************************************************************************/
1194 static PyMethodDef libxsltMethods[] = {
1195 #include "libxslt-export.c"
1196 { NULL, NULL, 0, NULL }
1197 };
1198
1199 #ifdef MERGED_MODULES
1200 extern void initlibxml2mod(void);
1201 #endif
1202
initlibxsltmod(void)1203 void initlibxsltmod(void) {
1204 static int initialized = 0;
1205
1206 #ifdef MERGED_MODULES
1207 initlibxml2mod();
1208 #endif
1209
1210 if (initialized != 0)
1211 return;
1212 Py_InitModule((char *)"libxsltmod", libxsltMethods);
1213 initialized = 1;
1214 /*
1215 * Specific XSLT initializations
1216 */
1217 libxslt_xsltErrorInitialize();
1218 xmlInitMemory();
1219 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
1220 xmlDefaultSAXHandler.cdataBlock = NULL;
1221 /*
1222 * Register the EXSLT extensions and the test module
1223 */
1224 exsltRegisterAll();
1225 }
1226
1227
1228