1 /*
2  * Copyright (C) 2001-2003 Peter J Jones (pjones@pmade.org)
3  * All Rights Reserved
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in
13  *    the documentation and/or other materials provided with the
14  *    distribution.
15  * 3. Neither the name of the Author nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR
23  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 /*
34  * $Id: stylesheet.cpp 543412 2017-08-09 18:22:55Z satskyse $
35  * NOTE: This file was modified from its original version 0.6.0
36  *       to fit the NCBI C++ Toolkit build framework and
37  *       API and functionality requirements.
38  */
39 
40 /** @file
41  * This file contains the implementation of the xslt::stylesheet class.
42 **/
43 
44 // xmlwrapp includes
45 #include <misc/xmlwrapp/stylesheet.hpp>
46 #include <misc/xmlwrapp/document.hpp>
47 #include <misc/xmlwrapp/exception.hpp>
48 #include <misc/xmlwrapp/xslt_exception.hpp>
49 
50 #include "utility.hpp"
51 #include "document_impl.hpp"
52 
53 // libxslt includes
54 #include <libxslt/xslt.h>
55 #include <libxslt/xsltInternals.h>
56 #include <libxslt/transform.h>
57 #include <libxslt/xsltutils.h>
58 #include <libxslt/extensions.h>
59 #include <libxml/xpath.h>
60 #include <libxml/xpathInternals.h>
61 
62 // standard includes
63 #include <stdexcept>
64 #include <memory>
65 #include <string>
66 #include <vector>
67 #include <map>
68 #include <string.h>
69 
70 #include "extension_function_impl.hpp"
71 #include "extension_element_impl.hpp"
72 
73 #include "stylesheet_impl.hpp"
74 #include "https_input_impl.hpp"
75 
76 
77 namespace xslt {
78     namespace impl {
is_xml_output_method(xsltStylesheetPtr ss)79         bool is_xml_output_method (xsltStylesheetPtr ss)
80         {
81             if (ss->method == NULL)
82                 return true;
83             return strcmp(reinterpret_cast<const char *>(ss->method),
84                           "xml") == 0;
85         }
86 
destroy_stylesheet(xsltStylesheetPtr ss)87         void destroy_stylesheet (xsltStylesheetPtr ss)
88         {
89             if (ss->_private == NULL)
90                 xsltFreeStylesheet(ss);
91             else {
92                 stylesheet_refcount * ss_rc =
93                         static_cast<stylesheet_refcount *>(ss->_private);
94                 if (ss_rc->dec_ref() == 0) {
95                     delete ss_rc;
96                     xsltFreeStylesheet(ss);
97                 }
98             }
99         }
100 
save_to_string(xmlDocPtr doc,xsltStylesheetPtr ss,std::string & s)101         void save_to_string(xmlDocPtr           doc,
102                             xsltStylesheetPtr   ss,
103                             std::string &       s)
104         {
105             xmlChar *   xml_string;
106             int         xml_string_length;
107 
108             if (xsltSaveResultToString(&xml_string,
109                                        &xml_string_length, doc, ss) >= 0)
110             {
111                 xml::impl::xmlchar_helper   helper(xml_string);
112                 if (xml_string_length)
113                     s.assign(helper.get(), xml_string_length);
114             }
115         }
116 
117         bool
save_to_file(xmlDocPtr doc,xsltStylesheetPtr ss,const char * filename,int)118         save_to_file(xmlDocPtr          doc,
119                      xsltStylesheetPtr  ss,
120                      const char *       filename,
121                      int                /* compression_level */)
122         {
123             return xsltSaveResultToFilename(filename, doc, ss, 0) >= 0;
124         }
125     } // End of impl namespace
126 } // End of xslt namespace
127 
128 
clear_nodes(void)129 void xslt::impl::stylesheet_impl::clear_nodes (void)
130 {
131     for (std::vector<xmlNodePtr>::const_iterator k = nodes_to_free_.begin();
132          k != nodes_to_free_.end(); ++k)
133         xmlFreeNode(*k);
134     nodes_to_free_.clear();
135 }
136 
137 
138 extern "C" {
139 
140     // XSLT extension function callback
xslt_ext_func_cb(void * c,int arg_num)141     void xslt_ext_func_cb(void *c, int arg_num)
142     {
143         xmlXPathParserContext *     ctxt =
144                     reinterpret_cast<xmlXPathParserContext *>(c);
145         xsltTransformContextPtr     xslt_ctxt =
146                     xsltXPathGetTransformContext(ctxt);
147         xslt::impl::stylesheet_impl *   s_impl =
148                     reinterpret_cast<xslt::impl::stylesheet_impl *>(
149                                                         xslt_ctxt->_private);
150         xmlNodePtr                  current_node = ctxt->context->node;
151         xmlDocPtr                   current_doc = ctxt->context->doc;
152 
153         // Search for a registered extension function
154         ext_func_key                key;
155         key.first = reinterpret_cast<const char *>(ctxt->context->function);
156         if (ctxt->context->functionURI != NULL)
157             key.second = reinterpret_cast<const char *>(
158                                         ctxt->context->functionURI);
159 
160         ext_funcs_map_type::iterator  found = s_impl->ext_functions_.find(key);
161         if (found == s_impl->ext_functions_.end())
162             return; // No extension function were found
163 
164         // The corresponding extension function has been found.
165         // Prepare parameters and call it
166         std::vector<xslt::xpath_object>     args;
167         xml::node                           node;
168         xml::document                       doc;
169 
170         // Prepare arguments for the extension function call. Arguments are
171         // coming in the reverse order.
172         args.reserve(arg_num);
173         for (int  k = 0; k < arg_num; ++k) {
174             xmlXPathObjectPtr   current_arg = valuePop(ctxt);
175 
176             args.insert(args.begin(),
177                     xslt::xpath_object(reinterpret_cast<void*>(current_arg)));
178             args[0].set_from_xslt();
179         }
180 
181 
182         // Wrap libxml2 data with xmlwrapp and make sure that xmlwrapp does NOT
183         // have ownership on the node and the document.
184         node.set_node_data(current_node);
185         doc.set_doc_data(current_doc);
186         doc.pimpl_->set_ownership(false);
187 
188         // Set the context to make error reporting and setting retval
189         // working properly
190         found->second.first->pimpl_->xpath_parser_ctxt = ctxt;
191 
192         // Make a call
193         try {
194             found->second.first->execute(args, node, doc);
195         } catch (const std::exception &  ex) {
196             std::string     error("Exception in the user extension function '" +
197                                   key.first + "': " + std::string(ex.what()));
198             found->second.first->report_error(error.c_str());
199         } catch (...) {
200             std::string     error("Unknown exception in the user "
201                                   "extension function '" + key.first + "'");
202             found->second.first->report_error(error.c_str());
203         }
204 
205         // Clear the context
206         found->second.first->pimpl_->xpath_parser_ctxt = NULL;
207 
208         return;
209     }
210 
211     // XSLT extension element callback
xslt_ext_element_cb(void * c,void * input_node_,void * instruction_node_,void * compiled_stylesheet_info)212     void xslt_ext_element_cb(void *c, void *input_node_,
213                              void *instruction_node_,
214                              void *compiled_stylesheet_info)
215     {
216         xsltTransformContextPtr     xslt_ctxt =
217                     reinterpret_cast<xsltTransformContextPtr>(c);
218         xmlNodePtr                  instruction_node =
219                     reinterpret_cast<xmlNodePtr>(instruction_node_);
220         xslt::impl::stylesheet_impl *   s_impl =
221                     reinterpret_cast<xslt::impl::stylesheet_impl *>(
222                                                         xslt_ctxt->_private);
223 
224         ext_elem_key                key;
225         key.first = reinterpret_cast<const char *>(instruction_node->name);
226         if (instruction_node->ns != NULL && instruction_node->ns->href != NULL)
227             key.second =
228                 reinterpret_cast<const char *>(instruction_node->ns->href);
229 
230         ext_elems_map_type::iterator    found = s_impl->ext_elements_.find(key);
231         if (found == s_impl->ext_elements_.end())
232             return; // No extension element were found
233 
234         // The corresponding extension element has been found.
235         // Prepare the parameters.
236         xmlNodePtr                  input_node =
237                                 reinterpret_cast<xmlNodePtr>(input_node_);
238 
239         xml::node                   inp_node;
240         xml::node                   instr_node;
241         xml::node                   insert_node;
242         xml::document               doc;
243 
244         // Wrap libxml2 data with xmlwrapp and make sure that xmlwrapp does NOT
245         // have ownership on the nodes and the document.
246         inp_node.set_node_data(input_node);
247         instr_node.set_node_data(instruction_node);
248         insert_node.set_node_data(xslt_ctxt->insert);
249         doc.set_doc_data(xslt_ctxt->xpathCtxt->doc);
250         doc.pimpl_->set_ownership(false);
251 
252         // Set the context to make error reporting working properly
253         found->second.first->pimpl_->xslt_ctxt = xslt_ctxt;
254         found->second.first->pimpl_->instruction_node = instruction_node;
255 
256         // Make a call
257         try {
258             found->second.first->process(inp_node, instr_node,
259                                          insert_node, doc);
260         } catch (const std::exception &  ex) {
261             std::string     error("Exception in the user extension element '" +
262                                   key.first + "': " +
263                                   std::string(ex.what()));
264             found->second.first->report_error(error.c_str());
265         } catch (...) {
266             std::string     error("Unknown error in the user "
267                                   "extension element '" +
268                                   key.first + "'");
269             found->second.first->report_error(error.c_str());
270         }
271 
272         // Clear the context
273         found->second.first->pimpl_->xslt_ctxt = NULL;
274         found->second.first->pimpl_->instruction_node = NULL;
275 
276         return;
277     }
278 
279 } // extern "C"
280 
281 
282 namespace
283 {
284 
make_vector_param(std::vector<const char * > & v,const xslt::stylesheet::param_type & p)285 void make_vector_param(std::vector<const char*> &v,
286                        const xslt::stylesheet::param_type &p)
287 {
288     v.reserve(p.size());
289 
290     xslt::stylesheet::param_type::const_iterator i = p.begin(), end = p.end();
291     for (; i != end; ++i)
292     {
293         v.push_back(i->first.c_str());
294         v.push_back(i->second.c_str());
295     }
296 
297     v.push_back(static_cast<const char*>(0));
298 }
299 
300 
301 extern "C"
302 {
303 
error_cb(void * c,const char * message,...)304 static void error_cb(void *c, const char *message, ...)
305 {
306     xsltTransformContextPtr ctxt = static_cast<xsltTransformContextPtr>(c);
307     xslt::impl::stylesheet_impl *s_impl =
308                     static_cast<xslt::impl::stylesheet_impl*>(ctxt->_private);
309 
310     // tell the processor to stop when it gets a chance:
311     if ( ctxt->state == XSLT_STATE_OK )
312         ctxt->state = XSLT_STATE_STOPPED;
313 
314     // concatenate all error messages:
315     if ( s_impl->errors_occured_ )
316         s_impl->error_.append("\n");
317     s_impl->errors_occured_ = true;
318 
319     std::string formatted;
320 
321     va_list ap;
322     va_start(ap, message);
323     xml::impl::printf2string(formatted, message, ap);
324     va_end(ap);
325 
326     s_impl->error_.append(formatted);
327 
328     if (s_impl->messages_ != NULL) {
329         // Need to insert the error information into the user provided container
330         int             line = 0;
331         std::string     filename;
332 
333         // Supposedly the current served node
334         xmlNodePtr      node = ctxt->inst;
335         if (node != NULL) {
336             if ((node->type == XML_DOCUMENT_NODE) ||
337                 (node->type == XML_HTML_DOCUMENT_NODE)) {
338                 xmlDocPtr   d = (xmlDocPtr) node;
339                 if (d->URL != NULL)
340                     filename = reinterpret_cast<const char *>(d->URL);
341             } else {
342                 line = xmlGetLineNo(node);
343                 if (node->doc != NULL)
344                     if (node->doc->URL != NULL)
345                         filename = reinterpret_cast<const char*>(node->doc->URL);
346             }
347         }
348 
349         s_impl->messages_->get_messages().push_back(
350                                         xml::error_message(
351                                             formatted,
352                                             xml::error_message::type_error,
353                                             line, filename));
354     }
355 }
356 
357 } // extern "C"
358 
359 
360 
apply_stylesheet(xslt::impl::stylesheet_impl * s_impl,xmlDocPtr doc,const xslt::stylesheet::param_type * p=NULL,xml::error_messages * messages_=NULL)361 xmlDocPtr apply_stylesheet(xslt::impl::stylesheet_impl *s_impl,
362                            xmlDocPtr doc,
363                            const xslt::stylesheet::param_type *p = NULL,
364                            xml::error_messages *  messages_ = NULL
365                            )
366 {
367     xsltStylesheetPtr style = s_impl->ss_;
368 
369     std::vector<const char*> v;
370     if (p)
371         make_vector_param(v, *p);
372 
373     xsltTransformContextPtr ctxt = xsltNewTransformContext(style, doc);
374     ctxt->_private = s_impl;
375     xsltSetTransformErrorFunc(ctxt, ctxt, error_cb);
376 
377     // Register extension functions
378     for (ext_funcs_map_type::iterator k = s_impl->ext_functions_.begin();
379          k != s_impl->ext_functions_.end(); ++k) {
380         if (xsltRegisterExtFunction(
381                 ctxt,
382                 reinterpret_cast<const xmlChar*>(k->first.first.c_str()),
383                 reinterpret_cast<const xmlChar*>(k->first.second.c_str()),
384                 reinterpret_cast<xmlXPathFunction>(xslt_ext_func_cb)) != 0) {
385             xsltFreeTransformContext(ctxt);
386             throw xslt::exception("Error registering extension function " +
387                                   k->first.first);
388         }
389     }
390 
391     // Register extension elements
392     for (ext_elems_map_type::iterator k = s_impl->ext_elements_.begin();
393          k != s_impl->ext_elements_.end(); ++k) {
394         if (xsltRegisterExtElement(
395                 ctxt,
396                 reinterpret_cast<const xmlChar*>(k->first.first.c_str()),
397                 reinterpret_cast<const xmlChar*>(k->first.second.c_str()),
398                 reinterpret_cast<xsltTransformFunction>
399                                                 (xslt_ext_element_cb)) != 0) {
400             xsltFreeTransformContext(ctxt);
401             throw xslt::exception("Error registering extension element " +
402                                   k->first.first);
403         }
404     }
405 
406     // clear the error flag before applying the stylesheet
407     s_impl->errors_occured_ = false;
408     s_impl->messages_ = messages_;
409 
410     // Wierd way to collect https warnings: via tls in the custom IO handler
411     // See https_input_impl.*
412     if (s_impl->messages_)
413         xml::impl::clear_https_messages();
414     xmlDocPtr result =
415         xsltApplyStylesheetUser(style, doc, p ? &v[0] : 0, NULL, NULL, ctxt);
416     if (s_impl->messages_)
417         xml::impl::collect_https_messages(*s_impl->messages_);
418 
419     // This is a part of a hack of leak-less handling nodeset return values
420     // from XSLT extension functions. XSLT frees nodes in a nodeset too early
421     // so the boolval is not set to 1 to free them automatically. Instead the
422     // nodes are memorized in a vector. These nodes are freed here, i.e. when
423     // the transformation is completed.
424     // See extension_function.cpp and xpath_object.cpp as well.
425     s_impl->clear_nodes();
426 
427     xsltFreeTransformContext(ctxt);
428 
429     // it's possible there was an error that didn't prevent creation of some
430     // (incorrect) document
431     if ( result && s_impl->errors_occured_ )
432     {
433         xmlFreeDoc(result);
434         return NULL;
435     }
436 
437     if ( !result )
438     {
439         // set generic error message if nothing more specific is known
440         if ( s_impl->error_.empty() )
441             s_impl->error_ = "unknown XSLT transformation error";
442         return NULL;
443     }
444 
445     return result;
446 }
447 
448 } // end of anonymous namespace
449 
450 
attach_refcount(void)451 void xslt::stylesheet::attach_refcount(void)
452 {
453     impl::stylesheet_refcount *  refcount;
454     try {
455         refcount = new impl::stylesheet_refcount;
456     } catch (...) {
457         xsltFreeStylesheet(pimpl_->ss_);
458         throw;
459     }
460     refcount->inc_ref();
461     pimpl_->ss_->_private = refcount;
462 }
463 
464 
stylesheet(const char * filename)465 xslt::stylesheet::stylesheet(const char *filename)
466 {
467     if (!filename)
468         throw xslt::exception("invalid file name");
469 
470     std::unique_ptr<impl::stylesheet_impl>
471                     ap(pimpl_ = new impl::stylesheet_impl);
472     xml::error_messages msgs;
473     xml::document       doc(filename, &msgs, xml::type_warnings_not_errors);
474     xmlDocPtr           xmldoc = static_cast<xmlDocPtr>(doc.get_doc_data());
475 
476     if ( (pimpl_->ss_ = xsltParseStylesheetDoc(xmldoc)) == 0)
477     {
478         // TODO error_ can't get set yet. Need changes from libxslt first
479         if (pimpl_->error_.empty())
480             pimpl_->error_ = "unknown XSLT parser error";
481 
482         msgs.get_messages().push_back(xml::error_message(
483                                             pimpl_->error_,
484                                             xml::error_message::type_error,
485                                             0, filename));
486         throw xml::parser_exception(msgs);
487     }
488 
489     attach_refcount();
490 
491     // if we got this far, the xmldoc we gave to xsltParseStylesheetDoc is
492     // now owned by the stylesheet and will be cleaned up in our destructor.
493     doc.release_doc_data();
494     ap.release();
495 }
496 
497 
stylesheet(const xml::document & doc)498 xslt::stylesheet::stylesheet(const xml::document &  doc)
499 {
500     xml::document           doc_copy(doc);  /* NCBI_FAKE_WARNING */
501     xmlDocPtr               xmldoc = static_cast<xmlDocPtr>(
502                                                 doc_copy.get_doc_data());
503     std::unique_ptr<impl::stylesheet_impl>
504                             ap(pimpl_ = new impl::stylesheet_impl);
505 
506     if ( (pimpl_->ss_ = xsltParseStylesheetDoc(xmldoc)) == 0)
507     {
508         // TODO error_ can't get set yet. Need changes from libxslt first
509         if (pimpl_->error_.empty())
510             pimpl_->error_ = "unknown XSLT parser error";
511 
512         xml::error_messages     messages;
513         messages.get_messages().push_back(xml::error_message(
514                                             pimpl_->error_,
515                                             xml::error_message::type_error,
516                                             0, ""));
517         throw xml::parser_exception(messages);
518     }
519 
520     attach_refcount();
521 
522     // if we got this far, the xmldoc we gave to xsltParseStylesheetDoc is
523     // now owned by the stylesheet and will be cleaned up in our destructor.
524     doc_copy.release_doc_data();
525     ap.release();
526 }
527 
528 
stylesheet(const char * data,size_t size)529 xslt::stylesheet::stylesheet (const char* data, size_t size)
530 {
531     std::unique_ptr<impl::stylesheet_impl>
532                             ap(pimpl_ = new impl::stylesheet_impl);
533     xml::error_messages     msgs;
534     xml::document           doc(data, size, &msgs,
535                                 xml::type_warnings_not_errors);
536     xmlDocPtr               xmldoc = static_cast<xmlDocPtr>(doc.get_doc_data());
537 
538     if ( (pimpl_->ss_ = xsltParseStylesheetDoc(xmldoc)) == 0)
539     {
540         // TODO error_ can't get set yet. Need changes from libxslt first
541         if (pimpl_->error_.empty())
542             pimpl_->error_ = "unknown XSLT parser error";
543 
544         msgs.get_messages().push_back(xml::error_message(
545                                             pimpl_->error_,
546                                             xml::error_message::type_error,
547                                             0, ""));
548         throw xml::parser_exception(msgs);
549     }
550 
551     attach_refcount();
552 
553     // if we got this far, the xmldoc we gave to xsltParseStylesheetDoc is
554     // now owned by the stylesheet and will be cleaned up in our destructor.
555     doc.release_doc_data();
556     ap.release();
557 }
558 
559 
stylesheet(std::istream & stream)560 xslt::stylesheet::stylesheet (std::istream & stream)
561 {
562     std::unique_ptr<impl::stylesheet_impl>
563                             ap(pimpl_ = new impl::stylesheet_impl);
564     xml::error_messages     msgs;
565     xml::document           doc(stream, &msgs, xml::type_warnings_not_errors);
566     xmlDocPtr               xmldoc = static_cast<xmlDocPtr>(doc.get_doc_data());
567 
568     if ( (pimpl_->ss_ = xsltParseStylesheetDoc(xmldoc)) == 0)
569     {
570         // TODO error_ can't get set yet. Need changes from libxslt first
571         if (pimpl_->error_.empty())
572             pimpl_->error_ = "unknown XSLT parser error";
573 
574         msgs.get_messages().push_back(xml::error_message(
575                                             pimpl_->error_,
576                                             xml::error_message::type_error,
577                                             0, ""));
578         throw xml::parser_exception(msgs);
579     }
580 
581     attach_refcount();
582 
583     // if we got this far, the xmldoc we gave to xsltParseStylesheetDoc is
584     // now owned by the stylesheet and will be cleaned up in our destructor.
585     doc.release_doc_data();
586     ap.release();
587 }
588 
589 
590 void
register_extension_function(extension_function * ef,const char * name,const char * uri,xml::ownership_type ownership)591 xslt::stylesheet::register_extension_function (extension_function *  ef,
592                                                const char *          name,
593                                                const char *          uri,
594                                                xml::ownership_type   ownership)
595 {
596     if (name == NULL) {
597         if (ownership == xml::type_own)
598             delete ef;
599         throw xslt::exception("Extension function name is uninitialised");
600     }
601 
602     if (uri == NULL) {
603         if (ownership == xml::type_own)
604             delete ef;
605         throw xslt::exception("Extension function URI is uninitialised");
606     }
607 
608     ext_func_key                    key = std::pair<std::string,
609                                                     std::string>(name, uri);
610     ext_funcs_map_type::iterator    found(pimpl_->ext_functions_.find(key));
611 
612     if (found != pimpl_->ext_functions_.end()) {
613         if (found->second.second == xml::type_own)
614             delete found->second.first;
615     }
616 
617     pimpl_->ext_functions_[ key ] = std::pair<extension_function *,
618                                           xml::ownership_type>(ef, ownership);
619     return;
620 }
621 
622 
623 void
register_extension_element(extension_element * ee,const char * name,const char * uri,xml::ownership_type ownership)624 xslt::stylesheet::register_extension_element (extension_element *  ee,
625                                               const char *          name,
626                                               const char *          uri,
627                                               xml::ownership_type   ownership)
628 {
629     if (name == NULL) {
630         if (ownership == xml::type_own)
631             delete ee;
632         throw xslt::exception("Extension element name is uninitialised");
633     }
634 
635     if (uri == NULL) {
636         if (ownership == xml::type_own)
637             delete ee;
638         throw xslt::exception("Extension element URI is uninitialised");
639     }
640 
641     ext_elem_key                    key = std::pair<std::string,
642                                                     std::string>(name, uri);
643     ext_elems_map_type::iterator    found(pimpl_->ext_elements_.find(key));
644 
645     if (found != pimpl_->ext_elements_.end()) {
646         if (found->second.second == xml::type_own)
647             delete found->second.first;
648     }
649 
650     pimpl_->ext_elements_[ key ] = std::pair<extension_element *,
651                                         xml::ownership_type>(ee, ownership);
652     return;
653 }
654 
655 
destroy(void)656 void xslt::stylesheet::destroy(void)
657 {
658     if (pimpl_ != NULL) {
659         // Delete extension functions we owe
660         for (ext_funcs_map_type::iterator k = pimpl_->ext_functions_.begin();
661              k != pimpl_->ext_functions_.end(); ++k) {
662             if (k->second.second == xml::type_own)
663                 delete k->second.first;
664         }
665 
666         // Delete extension elements we owe
667         for (ext_elems_map_type::iterator k = pimpl_->ext_elements_.begin();
668              k != pimpl_->ext_elements_.end(); ++k) {
669             if (k->second.second == xml::type_own)
670                 delete k->second.first;
671         }
672 
673         if (pimpl_->ss_)
674             xslt::impl::destroy_stylesheet(pimpl_->ss_);
675         delete pimpl_;
676     }
677 }
678 
679 
~stylesheet()680 xslt::stylesheet::~stylesheet()
681 {
682     destroy();
683 }
684 
685 
stylesheet(stylesheet && other)686 xslt::stylesheet::stylesheet (stylesheet &&  other) :
687     pimpl_(other.pimpl_)
688 {
689     other.pimpl_ = NULL;
690 }
691 
692 
operator =(stylesheet && other)693 xslt::stylesheet & xslt::stylesheet::operator= (stylesheet &&  other)
694 {
695     if (this != &other) {
696         destroy();
697         pimpl_ = other.pimpl_;
698         other.pimpl_ = NULL;
699     }
700     return *this;
701 }
702 
703 
apply(const xml::document & doc,xml::error_messages * messages_)704 xml::document_proxy xslt::stylesheet::apply (const xml::document &doc,
705                                              xml::error_messages *  messages_)
706 {
707     xmlDocPtr input = static_cast<xmlDocPtr>(doc.get_doc_data_read_only());
708     xmlDocPtr xmldoc = apply_stylesheet(pimpl_, input, NULL, messages_);
709 
710     if ( !xmldoc )
711         throw xslt::exception(pimpl_->error_);
712 
713     return xml::document_proxy(xmldoc, pimpl_->ss_);
714 }
715 
716 
apply(const xml::document & doc,const param_type & with_params,xml::error_messages * messages_)717 xml::document_proxy xslt::stylesheet::apply (const xml::document &doc,
718                                              const param_type &with_params,
719                                              xml::error_messages *  messages_ )
720 {
721     xmlDocPtr input = static_cast<xmlDocPtr>(doc.get_doc_data_read_only());
722     xmlDocPtr xmldoc = apply_stylesheet(pimpl_, input, &with_params, messages_);
723 
724     if ( !xmldoc )
725         throw xslt::exception(pimpl_->error_);
726 
727     return xml::document_proxy(xmldoc, pimpl_->ss_);
728 }
729 
730