LCOV - code coverage report
Current view: top level - snapwebsites - xslt.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1 369 0.3 %
Date: 2019-12-15 17:13:15 Functions: 2 14 14.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Snap Websites Servers -- handle calls to QXmlQuery
       2             : // Copyright (c) 2014-2019  Made to Order Software Corp.  All Rights Reserved
       3             : //
       4             : // This program is free software; you can redistribute it and/or modify
       5             : // it under the terms of the GNU General Public License as published by
       6             : // the Free Software Foundation; either version 2 of the License, or
       7             : // (at your option) any later version.
       8             : //
       9             : // This program is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             : // GNU General Public License for more details.
      13             : //
      14             : // You should have received a copy of the GNU General Public License
      15             : // along with this program; if not, write to the Free Software
      16             : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
      17             : 
      18             : 
      19             : // self
      20             : //
      21             : #include "snapwebsites/xslt.h"
      22             : 
      23             : 
      24             : // snapwebsites lib
      25             : //
      26             : #include "snapwebsites/snapwebsites.h"
      27             : #include "snapwebsites/log.h"
      28             : #include "snapwebsites/qdomreceiver.h"
      29             : #include "snapwebsites/qhtmlserializer.h"
      30             : #include "snapwebsites/qxmlmessagehandler.h"
      31             : 
      32             : 
      33             : // Qt lib
      34             : //
      35             : #include <QXmlQuery>
      36             : 
      37             : 
      38             : // last include
      39             : //
      40             : #include <snapdev/poison.h>
      41             : 
      42             : 
      43             : 
      44             : 
      45             : namespace snap
      46             : {
      47             : 
      48             : 
      49             : /** \brief Save the XSLT parser.
      50             :  *
      51             :  * This function receives a copy of the XSLT parser in the form of a string.
      52             :  * It gets saved in the class and reused by the evaluation functions
      53             :  * until changed.
      54             :  *
      55             :  * \param[in] xsl  The XSLT parser document.
      56             :  */
      57           0 : void xslt::set_xsl(QString const & xsl)
      58             : {
      59           0 :     f_xsl = xsl;
      60           0 : }
      61             : 
      62             : 
      63             : /** \brief Save the XSLT parser.
      64             :  *
      65             :  * This function receives a copy of the XSLT parser in the form of a string.
      66             :  * It gets saved in the class and reused by the evaluation functions
      67             :  * until changed.
      68             :  *
      69             :  * \note
      70             :  * At this the XML document is immediately transformed to a string. At
      71             :  * some point we may be able to use the XML document as such with
      72             :  * QXmlQuery...
      73             :  *
      74             :  * \param[in] xsl  The XSLT parser document.
      75             :  */
      76           0 : void xslt::set_xsl(QDomDocument const & xsl)
      77             : {
      78           0 :     f_xsl = xsl.toString(-1);
      79           0 : }
      80             : 
      81             : 
      82             : /** \brief Set the XSLT parser from the content of a file.
      83             :  *
      84             :  * When you have a filename you may bypass loading the file yourselves
      85             :  * and call this function.
      86             :  *
      87             :  * The loading is done using the load_file() signal.
      88             :  *
      89             :  * \warning
      90             :  * This function assumes that you have a valid running server with
      91             :  * all the plugins loaded (i.e. running in snap_child or snap_backend
      92             :  * or any plugin.)
      93             :  *
      94             :  * \exception xslt_initialization_error
      95             :  * This exception is raised if the named file cannot be loaded since
      96             :  * that means we will not be able to transform the input.
      97             :  *
      98             :  * \param[in] filename  The name of the file to load.
      99             :  */
     100           0 : void xslt::set_xsl_from_file(QString const & filename)
     101             : {
     102             :     // make sure we have access to a valid server
     103           0 :     server::pointer_t server(server::instance());
     104           0 :     if(!server)
     105             :     {
     106           0 :         throw snap_logic_exception("server pointer is nullptr");
     107             :     }
     108             : 
     109             :     // whether he file was found
     110           0 :     bool found(false);
     111             : 
     112             :     // setup the file
     113           0 :     snap::snap_child::post_file_t file;
     114           0 :     file.set_filename(filename);
     115             : 
     116             :     // try to load the data
     117           0 :     server->load_file(file, found);
     118             : 
     119             :     // if not found, we have a problem
     120           0 :     if(!found)
     121             :     {
     122           0 :         throw xslt_initialization_error(QString("xslt::set_xsl_from_file() could not load file \"%1\".").arg(filename));
     123             :     }
     124             : 
     125             :     // okay, it got loaded, save the resulting file in here
     126           0 :     f_xsl = QString::fromUtf8(file.get_data(), file.get_size());
     127           0 : }
     128             : 
     129             : 
     130             : /** \brief Set the document to be transformed.
     131             :  *
     132             :  * This function saves a copy of the specified input document in
     133             :  * this object. This is the document that is going to be transformed
     134             :  * using the XSLT script.
     135             :  *
     136             :  * In most cases this document is expected to be HTML or XHTML.
     137             :  *
     138             :  * \note
     139             :  * If you have a DOM document, you may call the other
     140             :  * set_document(QDomDocument &) to get the same effect.
     141             :  *
     142             :  * \param[in] input  The document to be parsed.
     143             :  *
     144             :  * \sa set_document(QDomDocument & doc);
     145             :  */
     146           0 : void xslt::set_document(QString const & input)
     147             : {
     148           0 :     f_doc.clear();
     149           0 :     f_input = input;
     150           0 : }
     151             : 
     152             : 
     153             : /** \brief Set the document to be transformed.
     154             :  *
     155             :  * This function saves a copy of the specified input document in
     156             :  * this object. This is the document that is going to be transformed
     157             :  * using the XSLT script.
     158             :  *
     159             :  * \note
     160             :  * If you have a string, you may call the other
     161             :  * set_document(QString &) function which is going
     162             :  * to be must faster than generating a document
     163             :  * and saving it back to a string.
     164             :  *
     165             :  * \param[in] doc  The document to be parsed.
     166             :  *
     167             :  * \sa set_document(QDomDocument & doc);
     168             :  */
     169           0 : void xslt::set_document(QDomDocument & doc)
     170             : {
     171           0 :     f_input.clear();
     172           0 :     f_doc = doc;
     173           0 : }
     174             : 
     175             : 
     176             : /** \brief Add a variable which will be used with the parser.
     177             :  *
     178             :  * This function can be used to add variables to the parser.
     179             :  * These are added in the evaluation function just before
     180             :  * the evaluation takes place.
     181             :  *
     182             :  * In most cases, though, you add your data to the input
     183             :  * XML document and not here as variables.
     184             :  *
     185             :  * \param[in] name  The name of the variable.
     186             :  * \param[in] value  The value of the variable.
     187             :  *
     188             :  * \sa clear_variables()
     189             :  */
     190           0 : void xslt::add_variable(QString const & name, QVariant const & value)
     191             : {
     192           0 :     f_variables[name] = value;
     193           0 : }
     194             : 
     195             : 
     196             : /** \brief Clear all the variables.
     197             :  *
     198             :  * This function can be used to clear all the variables of an XSLT
     199             :  * object. Any variable that were added with the add_variable()
     200             :  * function are removed.
     201             :  *
     202             :  * \sa add_variable()
     203             :  */
     204           0 : void xslt::clear_variables()
     205             : {
     206           0 :     f_variables.clear();
     207           0 : }
     208             : 
     209             : 
     210             : /** \brief Run parser and return the result as a string.
     211             :  *
     212             :  * This function runs the parser to apply the XSLT 2.0 transformations
     213             :  * against the input document and returns the result as a string.
     214             :  *
     215             :  * \return The transformation result as a string.
     216             :  */
     217           0 : QString xslt::evaluate_to_string()
     218             : {
     219           0 :     QString result;
     220           0 :     evaluate(&result, nullptr);
     221           0 :     return result;
     222             : }
     223             : 
     224             : 
     225             : /** \brief Run parser and return the result in \p output.
     226             :  *
     227             :  * This function runs the parser to apply the XSLT 2.0 transformations
     228             :  * against the input document and returns the result as an XML document
     229             :  * in the specified output object. Whether the output DOM is currently
     230             :  * empty has no bearing to the process although things may not work
     231             :  * as expected if the output is not just one document root element,
     232             :  * though.
     233             :  *
     234             :  * \param[in,out] output  The output QDomDocument where the parsing gets saved.
     235             :  *
     236             :  * \return The transformation result as a string.
     237             :  */
     238           0 : void xslt::evaluate_to_document(QDomDocument & output)
     239             : {
     240           0 :     evaluate(nullptr, &output);
     241           0 : }
     242             : 
     243             : 
     244             : /** \brief Evaluate the transformation.
     245             :  *
     246             :  * This function is the internal function that is used to evaluate the
     247             :  * output. The functions calling parameters is "complicated" and hence
     248             :  * the function was made internal and two public functions created
     249             :  * so the outside world can make easy calls instead.
     250             :  *
     251             :  * \todo
     252             :  * Look into getting the XML sitemap version to here? Actually, the
     253             :  * best would be to look into making use of XML data as input since
     254             :  * that would allow us to avoid some (many?) conversions to and from
     255             :  * string.
     256             :  *
     257             :  * \param[out] output_string  The output string if evaluate_to_string()
     258             :  *                            was called.
     259             :  * \param[in,out] output_document  The output document if
     260             :  *                                 evaluate_to_document() was called.
     261             :  */
     262           0 : void xslt::evaluate(QString * output_string, QDomDocument * output_document)
     263             : {
     264           0 :     bool first_attempt(true);
     265             : 
     266             :     for(;;)
     267             :     {
     268           0 :         QXmlQuery q(QXmlQuery::XSLT20);
     269             : 
     270           0 :         QString doc_str(f_input);
     271           0 :         if(doc_str.isEmpty())
     272             :         {
     273           0 :             if(f_doc.isNull())
     274             :             {
     275           0 :                 throw snap_logic_exception("xslt::evaluate_to_string(): f_input and f_doc are both empty.");
     276             :             }
     277             : 
     278           0 :             doc_str = f_doc.toString(-1);
     279             :         }
     280             : 
     281             :         // if it is our second attempt, then we need to transform the
     282             :         // entities to Unicode characters
     283           0 :         if(!first_attempt)
     284             :         {
     285             :             // this function is rather slow so we try to not run it
     286             :             // here since we are likely live when running this...
     287             :             // a filter will be created to run this function on
     288             :             // all fields in the database that may include "incorrect"
     289             :             // (as per QXmlQuery) HTML code.
     290             :             //
     291           0 :             doc_str = filter_entities_out(doc_str);
     292             :         }
     293             : 
     294             :         // setup our message handler
     295           0 :         QMessageHandler msg;
     296           0 :         msg.set_xsl(f_xsl);
     297           0 :         msg.set_doc(doc_str);
     298             : 
     299             : #ifdef _DEBUG
     300             : //SNAP_LOG_DEBUG("!!!! f_xsl="  )(f_xsl);
     301             : //SNAP_LOG_DEBUG("!!!! doc_str=")(doc_str);
     302             : #endif
     303             : 
     304             :         // setup the XML query object
     305           0 :         q.setMessageHandler(&msg);
     306           0 :         q.setFocus(doc_str);
     307             : 
     308             :         // set variables
     309             :         // WARNING: variables MUST be set before you call the setQuery()
     310             :         //          function since it may start making use of them
     311             :         //
     312             :         // TBD: I think variables can cause problems, although it is used by
     313             :         //      the form and editor implementations...
     314             :         //
     315           0 :         for(auto p(f_variables.begin());
     316           0 :                  p != f_variables.end();
     317             :                  ++p)
     318             :         {
     319           0 :             q.bindVariable(p.key(), p.value());
     320             :         }
     321             : 
     322             :         // setup the transformation data
     323           0 :         q.setQuery(f_xsl);
     324           0 :         if(!q.isValid())
     325             :         {
     326           0 :             if(first_attempt)
     327             :             {
     328           0 :                 goto try_again;
     329             :             }
     330           0 :             throw xslt_evaluation_error("Invalid XSLT query detected by Qt.");
     331             :         }
     332             : 
     333           0 :         if(output_document != nullptr)
     334             :         {
     335             :             // this should be faster since we keep the data in a DOM
     336           0 :             QDomReceiver receiver(q.namePool(), *output_document);
     337           0 :             q.evaluateTo(&receiver);
     338             : 
     339           0 :             if(!msg.has_entities())
     340             :             {
     341           0 :                 if(msg.had_msg())
     342             :                 {
     343             :                     // do something? but what then?
     344             :                 }
     345           0 :                 return;
     346             :             }
     347             :         }
     348           0 :         else if(output_string != nullptr)
     349             :         {
     350             :             // request the evalutation in a QBuffer
     351           0 :             QBuffer output;
     352           0 :             output.open(QBuffer::ReadWrite);
     353           0 :             QHtmlSerializer html(q.namePool(), &output);
     354           0 :             q.evaluateTo(&html);
     355             : 
     356           0 :             if(!msg.has_entities())
     357             :             {
     358           0 :                 if(!msg.had_msg())
     359             :                 {
     360           0 :                     *output_string = QString::fromUtf8(output.data());
     361             :                 }
     362             :                 else
     363             :                 {
     364             :                     // return a default so we know something went wrong
     365           0 :                     *output_string = "[QXmlParser failed to transform your data]";
     366             :                 }
     367           0 :                 return;
     368             :             }
     369             :         }
     370             :         else
     371             :         {
     372           0 :             throw xslt_evaluation_error("incorrect use of evaluate() with both output_document and output_string");
     373             :         }
     374             : 
     375             :         // if we reach here then the input data includes entities
     376           0 :         if(!first_attempt)
     377             :         {
     378           0 :             throw xslt_evaluation_error("your input document could not be converted by QXmlQuery.");
     379             :         }
     380           0 : try_again:
     381           0 :         first_attempt = false;
     382           0 :     }
     383             : 
     384             : // The following is for history record.
     385             : // I first tried to implement the transformation from XML to XML so avoid
     386             : // wasting time converting to a string first and then back to XML
     387             : // 
     388             : //     QString const doc_str(doc.toString(-1));
     389             : //     if(doc_str.isEmpty())
     390             : //     {
     391             : //         throw snap_logic_exception("somehow the memory XML document for the body XSLT is empty");
     392             : //     }
     393             : //     QXmlQuery q(QXmlQuery::XSLT20);
     394             : //     QMessageHandler msg;
     395             : //     msg.set_xsl(xsl);
     396             : //     msg.set_doc(doc_str);
     397             : //     q.setMessageHandler(&msg);
     398             : // #if 0
     399             : //     QDomNodeModel m(q.namePool(), doc);
     400             : //     QXmlNodeModelIndex x(m.fromDomNode(doc.documentElement()));
     401             : //     QXmlItem i(x);
     402             : //     q.setFocus(i);
     403             : // #else
     404             : //     q.setFocus(doc_str);
     405             : // #endif
     406             : //     q.setQuery(xsl);
     407             : //     if(!q.isValid())
     408             : //     {
     409             : //         throw layout_exception_invalid_xslt_data(QString("invalid XSLT query for BODY \"%1\" detected by Qt").arg(ipath.get_key()));
     410             : //     }
     411             : // #if 0
     412             : //     QXmlResultItems results;
     413             : //     q.evaluateTo(&results);
     414             : //     
     415             : //     QXmlItem item(results.next());
     416             : //     while(!item.isNull())
     417             : //     {
     418             : //         if(item.isNode())
     419             : //         {
     420             : //             //printf("Got a node!\n");
     421             : //             QXmlNodeModelIndex node_index(item.toNodeModelIndex());
     422             : //             QDomNode node(m.toDomNode(node_index));
     423             : //             printf("Got a node! [%s]\n", node.localName()/*ownerDocument().toString(-1)*/.toUtf8().data());
     424             : //         }
     425             : //         item = results.next();
     426             : //     }
     427             : // #elif 1
     428             : //     // this should be faster since we keep the data in a DOM
     429             : //     QDomDocument doc_output("body");
     430             : //     QDomReceiver receiver(q.namePool(), doc_output);
     431             : //     q.evaluateTo(&receiver);
     432             : // 
     433             : //     extract_js_and_css(doc, doc_output);
     434             : //     body.appendChild(doc.importNode(doc_output.documentElement(), true));
     435             : // //std::cout << "Body HTML is [" << doc_output.toString(-1) << "]\n";
     436             : // #else
     437             : //     //QDomDocument doc_body("body");
     438             : //     //doc_body.setContent(get_content_parameter(path, get_name(name_t::SNAP_NAME_CONTENT_BODY) <<-- that would be wrong now).stringValue(), true, nullptr, nullptr, nullptr);
     439             : //     //QDomElement content_tag(doc.createElement("content"));
     440             : //     //body.appendChild(content_tag);
     441             : //     //content_tag.appendChild(doc.importNode(doc_body.documentElement(), true));
     442             : // 
     443             : //     // TODO: look into getting XML as output
     444             : //     QString out;
     445             : //     q.evaluateTo(&out);
     446             : //     //QDomElement output(doc.createElement("output"));
     447             : //     //body.appendChild(output);
     448             : //     //QDomText text(doc.createTextNode(out));
     449             : //     //output.appendChild(text);
     450             : //     QDomDocument doc_output("body");
     451             : //     doc_output.setContent(out, true, nullptr, nullptr, nullptr);
     452             : //     body.appendChild(doc.importNode(doc_output.documentElement(), true));
     453             : // #endif
     454             : }
     455             : 
     456             : 
     457             : /** \brief Filter an HTML document and replace entities by their characters.
     458             :  *
     459             :  * This function goes through the entire HTML document and makes sure that
     460             :  * all entities get transformed from the HTML syntax (\&name;)
     461             :  * to the corresponding Unicode character.
     462             :  *
     463             :  * This is important because Browsers may send us HTML with entities and
     464             :  * unfortunately the QXmlQuery system does not support them. (Actually
     465             :  * the Qt XML loaders are expected to transform entities to Unicode
     466             :  * characters on the fly, but in our case only the &lt;, &gt;, and &amp;
     467             :  * are recognized.)
     468             :  *
     469             :  * \param[in] html  The HTML to be transformed.
     470             :  *
     471             :  * \return The transformed HTML.
     472             :  */
     473           0 : QString xslt::filter_entities_out(QString const & html)
     474             : {
     475           0 :     QString result;
     476             : 
     477           0 :     int pos(0);
     478             :     for(;;)
     479             :     {
     480           0 :         int amp(html.indexOf('&', pos));
     481           0 :         if(amp == -1)
     482             :         {
     483             :             // no more '&', return immediately
     484           0 :             result += html.mid(pos);
     485           0 :             return result;
     486             :         }
     487           0 :         ++amp;
     488             : 
     489             :         // TODO: check whether we find a '<', '>', or '&' before the ';'
     490           0 :         int const semi_colon(html.indexOf(';', amp));
     491           0 :         if(semi_colon == -1)
     492             :         {
     493             :             // found '&' without ';', return it as is
     494           0 :             result += html.mid(pos);
     495           0 :             return result;
     496             :         }
     497             : 
     498           0 :         if(amp >= html.length())
     499             :         {
     500             :             // this is not possible since we found a ';' after the '&'
     501           0 :             throw snap_logic_exception("xslt::filter_entities_out(): amp >= html.length() is just not possible here.");
     502             :         }
     503             : 
     504             :         // make sure that the first character represents a possible
     505             :         // entity otherwise we ignore it altogether
     506           0 :         QChar const c(html[amp]);
     507           0 :         if(c == '#')
     508             :         {
     509             :             // no need to convert numeric entities
     510           0 :             result += html.mid(pos, semi_colon + 1 - pos);
     511             :         }
     512           0 :         else if(semi_colon - amp < 100   // if the name is more than 100 characters, we probably got a problem...
     513           0 :         || (c >= 'a' && c <= 'z')
     514           0 :         || (c >= 'A' && c <= 'Z'))
     515             :         {
     516             :             // keep whatever happened before the ampersand
     517           0 :             result += html.mid(pos, amp - 1 - pos);
     518             : 
     519             :             // retrieve the entity reference name
     520           0 :             QString const entity(html.mid(amp, semi_colon - amp));
     521           0 :             result += convert_entity(entity);
     522             :         }
     523             :         else
     524             :         {
     525             :             // in this case we replace the entity with a starting &amp;
     526           0 :             result += "&amp;";
     527           0 :             result += html.mid(pos, semi_colon - pos);
     528             :         }
     529             : 
     530           0 :         pos = semi_colon + 1;
     531           0 :     }
     532             : }
     533             : 
     534             : 
     535             : /** \brief Convert the named entity to a character or even a few characters.
     536             :  *
     537             :  * This function "manually" (so very quickly) converts the named entity
     538             :  * to a name.
     539             :  *
     540             :  * If the entity is not known, then we return "&amp;<name>;" so that way
     541             :  * we can continue to parse the data and make the problematic character
     542             :  * known.
     543             :  *
     544             :  * \note
     545             :  * The total number of entities is enormous and found on this page:
     546             :  * http://www.w3.org/TR/xml-entity-names/
     547             :  *
     548             :  * \todo
     549             :  * The idea, at some point, will be to write a parser of source entity
     550             :  * files and come up with a function that checks characters one by one
     551             :  * very quickly (similar to having a switch at all levels.)
     552             :  *
     553             :  * \param[in] entity_name  The name of the entity to be converted.
     554             :  *
     555             :  * \return The corresponding Unicode character.
     556             :  */
     557           0 : QString xslt::convert_entity(QString const & entity_name)
     558             : {
     559           0 :     if(entity_name.isEmpty())
     560             :     {
     561           0 :         return "";
     562             :     }
     563             : 
     564           0 :     switch(entity_name[0].unicode())
     565             :     {
     566           0 :     case 'A':
     567           0 :         if(entity_name == "Aacute")
     568             :         {
     569           0 :             return QString("%1").arg(QChar(193));
     570             :         }
     571           0 :         if(entity_name == "Acirc")
     572             :         {
     573           0 :             return QString("%1").arg(QChar(194));
     574             :         }
     575           0 :         if(entity_name == "AElig")
     576             :         {
     577           0 :             return QString("%1").arg(QChar(198));
     578             :         }
     579           0 :         if(entity_name == "Agrave")
     580             :         {
     581           0 :             return QString("%1").arg(QChar(192));
     582             :         }
     583           0 :         if(entity_name == "Aring")
     584             :         {
     585           0 :             return QString("%1").arg(QChar(197));
     586             :         }
     587           0 :         if(entity_name == "Atilde")
     588             :         {
     589           0 :             return QString("%1").arg(QChar(195));
     590             :         }
     591           0 :         if(entity_name == "Auml")
     592             :         {
     593           0 :             return QString("%1").arg(QChar(196));
     594             :         }
     595           0 :         break;
     596             : 
     597           0 :     case 'a':
     598           0 :         if(entity_name == "aacute")
     599             :         {
     600           0 :             return QString("%1").arg(QChar(225));
     601             :         }
     602           0 :         if(entity_name == "acute")
     603             :         {
     604           0 :             return QString("%1").arg(QChar(180));
     605             :         }
     606           0 :         if(entity_name == "acirc")
     607             :         {
     608           0 :             return QString("%1").arg(QChar(226));
     609             :         }
     610           0 :         if(entity_name == "aelig")
     611             :         {
     612           0 :             return QString("%1").arg(QChar(230));
     613             :         }
     614           0 :         if(entity_name == "agrave")
     615             :         {
     616           0 :             return QString("%1").arg(QChar(224));
     617             :         }
     618           0 :         if(entity_name == "amp")
     619             :         {
     620           0 :             return "&amp;";
     621             :         }
     622           0 :         if(entity_name == "aring")
     623             :         {
     624           0 :             return QString("%1").arg(QChar(229));
     625             :         }
     626           0 :         if(entity_name == "atilde")
     627             :         {
     628           0 :             return QString("%1").arg(QChar(227));
     629             :         }
     630           0 :         if(entity_name == "auml")
     631             :         {
     632           0 :             return QString("%1").arg(QChar(228));
     633             :         }
     634           0 :         break;
     635             : 
     636           0 :     case 'b':
     637           0 :         if(entity_name == "brvbar")
     638             :         {
     639           0 :             return QString("%1").arg(QChar(166));
     640             :         }
     641           0 :         break;
     642             : 
     643           0 :     case 'C':
     644           0 :         if(entity_name == "Ccedil")
     645             :         {
     646           0 :             return QString("%1").arg(QChar(199));
     647             :         }
     648           0 :         break;
     649             : 
     650           0 :     case 'c':
     651           0 :         if(entity_name == "ccedil")
     652             :         {
     653           0 :             return QString("%1").arg(QChar(231));
     654             :         }
     655           0 :         if(entity_name == "cedil")
     656             :         {
     657           0 :             return QString("%1").arg(QChar(184));
     658             :         }
     659           0 :         if(entity_name == "cent")
     660             :         {
     661           0 :             return QString("%1").arg(QChar(162));
     662             :         }
     663           0 :         if(entity_name == "copy")
     664             :         {
     665           0 :             return QString("%1").arg(QChar(169));
     666             :         }
     667           0 :         if(entity_name == "curren")
     668             :         {
     669           0 :             return QString("%1").arg(QChar(164));
     670             :         }
     671           0 :         break;
     672             : 
     673           0 :     case 'd':
     674           0 :         if(entity_name == "deg")
     675             :         {
     676           0 :             return QString("%1").arg(QChar(176));
     677             :         }
     678           0 :         if(entity_name == "divide")
     679             :         {
     680           0 :             return QString("%1").arg(QChar(247));
     681             :         }
     682           0 :         break;
     683             : 
     684           0 :     case 'E':
     685           0 :         if(entity_name == "Eacute")
     686             :         {
     687           0 :             return QString("%1").arg(QChar(201));
     688             :         }
     689           0 :         if(entity_name == "Ecirc")
     690             :         {
     691           0 :             return QString("%1").arg(QChar(202));
     692             :         }
     693           0 :         if(entity_name == "Egrave")
     694             :         {
     695           0 :             return QString("%1").arg(QChar(200));
     696             :         }
     697           0 :         if(entity_name == "ETH")
     698             :         {
     699           0 :             return QString("%1").arg(QChar(208));
     700             :         }
     701           0 :         if(entity_name == "Euml")
     702             :         {
     703           0 :             return QString("%1").arg(QChar(203));
     704             :         }
     705           0 :         break;
     706             : 
     707           0 :     case 'e':
     708           0 :         if(entity_name == "eacute")
     709             :         {
     710           0 :             return QString("%1").arg(QChar(233));
     711             :         }
     712           0 :         if(entity_name == "ecirc")
     713             :         {
     714           0 :             return QString("%1").arg(QChar(234));
     715             :         }
     716           0 :         if(entity_name == "egrave")
     717             :         {
     718           0 :             return QString("%1").arg(QChar(232));
     719             :         }
     720           0 :         if(entity_name == "eth")
     721             :         {
     722           0 :             return QString("%1").arg(QChar(240));
     723             :         }
     724           0 :         if(entity_name == "euml")
     725             :         {
     726           0 :             return QString("%1").arg(QChar(235));
     727             :         }
     728           0 :         break;
     729             : 
     730           0 :     case 'f':
     731           0 :         if(entity_name == "frac12")
     732             :         {
     733           0 :             return QString("%1").arg(QChar(189));
     734             :         }
     735           0 :         if(entity_name == "frac14")
     736             :         {
     737           0 :             return QString("%1").arg(QChar(188));
     738             :         }
     739           0 :         if(entity_name == "frac34")
     740             :         {
     741           0 :             return QString("%1").arg(QChar(190));
     742             :         }
     743           0 :         break;
     744             : 
     745           0 :     case 'g':
     746           0 :         if(entity_name == "gt")
     747             :         {
     748           0 :             return "&gt;";
     749             :         }
     750           0 :         break;
     751             : 
     752           0 :     case 'I':
     753           0 :         if(entity_name == "Iacute")
     754             :         {
     755           0 :             return QString("%1").arg(QChar(205));
     756             :         }
     757           0 :         if(entity_name == "Icirc")
     758             :         {
     759           0 :             return QString("%1").arg(QChar(206));
     760             :         }
     761           0 :         if(entity_name == "Igrave")
     762             :         {
     763           0 :             return QString("%1").arg(QChar(204));
     764             :         }
     765           0 :         if(entity_name == "Iuml")
     766             :         {
     767           0 :             return QString("%1").arg(QChar(207));
     768             :         }
     769           0 :         break;
     770             : 
     771           0 :     case 'i':
     772           0 :         if(entity_name == "iacute")
     773             :         {
     774           0 :             return QString("%1").arg(QChar(237));
     775             :         }
     776           0 :         if(entity_name == "icirc")
     777             :         {
     778           0 :             return QString("%1").arg(QChar(238));
     779             :         }
     780           0 :         if(entity_name == "iexcl")
     781             :         {
     782           0 :             return QString("%1").arg(QChar(161));
     783             :         }
     784           0 :         if(entity_name == "igrave")
     785             :         {
     786           0 :             return QString("%1").arg(QChar(236));
     787             :         }
     788           0 :         if(entity_name == "iquest")
     789             :         {
     790           0 :             return QString("%1").arg(QChar(191));
     791             :         }
     792           0 :         if(entity_name == "iuml")
     793             :         {
     794           0 :             return QString("%1").arg(QChar(239));
     795             :         }
     796           0 :         break;
     797             : 
     798           0 :     case 'l':
     799           0 :         if(entity_name == "laquo")
     800             :         {
     801           0 :             return QString("%1").arg(QChar(171));
     802             :         }
     803           0 :         if(entity_name == "lt")
     804             :         {
     805           0 :             return "&lt;";
     806             :         }
     807           0 :         break;
     808             : 
     809           0 :     case 'm':
     810           0 :         if(entity_name == "macr")
     811             :         {
     812           0 :             return QString("%1").arg(QChar(175));
     813             :         }
     814           0 :         if(entity_name == "micro")
     815             :         {
     816           0 :             return QString("%1").arg(QChar(181));
     817             :         }
     818           0 :         if(entity_name == "middot")
     819             :         {
     820           0 :             return QString("%1").arg(QChar(183));
     821             :         }
     822           0 :         break;
     823             : 
     824           0 :     case 'N':
     825           0 :         if(entity_name == "Ntilde")
     826             :         {
     827           0 :             return QString("%1").arg(QChar(209));
     828             :         }
     829           0 :         break;
     830             : 
     831           0 :     case 'n':
     832           0 :         if(entity_name == "nbsp")
     833             :         {
     834           0 :             return QString("%1").arg(QChar(160));
     835             :         }
     836           0 :         if(entity_name == "not")
     837             :         {
     838           0 :             return QString("%1").arg(QChar(172));
     839             :         }
     840           0 :         if(entity_name == "ntilde")
     841             :         {
     842           0 :             return QString("%1").arg(QChar(241));
     843             :         }
     844           0 :         break;
     845             : 
     846           0 :     case 'O':
     847           0 :         if(entity_name == "Oacute")
     848             :         {
     849           0 :             return QString("%1").arg(QChar(211));
     850             :         }
     851           0 :         if(entity_name == "Ocirc")
     852             :         {
     853           0 :             return QString("%1").arg(QChar(212));
     854             :         }
     855           0 :         if(entity_name == "Ograve")
     856             :         {
     857           0 :             return QString("%1").arg(QChar(210));
     858             :         }
     859           0 :         if(entity_name == "Oslash")
     860             :         {
     861           0 :             return QString("%1").arg(QChar(216));
     862             :         }
     863           0 :         if(entity_name == "Otilde")
     864             :         {
     865           0 :             return QString("%1").arg(QChar(213));
     866             :         }
     867           0 :         if(entity_name == "Ouml")
     868             :         {
     869           0 :             return QString("%1").arg(QChar(214));
     870             :         }
     871           0 :         break;
     872             : 
     873           0 :     case 'o':
     874           0 :         if(entity_name == "oacute")
     875             :         {
     876           0 :             return QString("%1").arg(QChar(243));
     877             :         }
     878           0 :         if(entity_name == "ocirc")
     879             :         {
     880           0 :             return QString("%1").arg(QChar(244));
     881             :         }
     882           0 :         if(entity_name == "ograve")
     883             :         {
     884           0 :             return QString("%1").arg(QChar(242));
     885             :         }
     886           0 :         if(entity_name == "ordf")
     887             :         {
     888           0 :             return QString("%1").arg(QChar(170));
     889             :         }
     890           0 :         if(entity_name == "ordm")
     891             :         {
     892           0 :             return QString("%1").arg(QChar(186));
     893             :         }
     894           0 :         if(entity_name == "oslash")
     895             :         {
     896           0 :             return QString("%1").arg(QChar(248));
     897             :         }
     898           0 :         if(entity_name == "otilde")
     899             :         {
     900           0 :             return QString("%1").arg(QChar(245));
     901             :         }
     902           0 :         if(entity_name == "ouml")
     903             :         {
     904           0 :             return QString("%1").arg(QChar(246));
     905             :         }
     906           0 :         break;
     907             : 
     908           0 :     case 'p':
     909           0 :         if(entity_name == "para")
     910             :         {
     911           0 :             return QString("%1").arg(QChar(182));
     912             :         }
     913           0 :         if(entity_name == "plusmn")
     914             :         {
     915           0 :             return QString("%1").arg(QChar(177));
     916             :         }
     917           0 :         if(entity_name == "pound")
     918             :         {
     919           0 :             return QString("%1").arg(QChar(163));
     920             :         }
     921           0 :         break;
     922             : 
     923           0 :     case 'r':
     924           0 :         if(entity_name == "raquo")
     925             :         {
     926           0 :             return QString("%1").arg(QChar(187));
     927             :         }
     928           0 :         if(entity_name == "reg")
     929             :         {
     930           0 :             return QString("%1").arg(QChar(174));
     931             :         }
     932           0 :         break;
     933             : 
     934           0 :     case 's':
     935           0 :         if(entity_name == "sect")
     936             :         {
     937           0 :             return QString("%1").arg(QChar(167));
     938             :         }
     939           0 :         if(entity_name == "shy")
     940             :         {
     941           0 :             return QString("%1").arg(QChar(173));
     942             :         }
     943           0 :         if(entity_name == "sup1")
     944             :         {
     945           0 :             return QString("%1").arg(QChar(185));
     946             :         }
     947           0 :         if(entity_name == "sup2")
     948             :         {
     949           0 :             return QString("%1").arg(QChar(178));
     950             :         }
     951           0 :         if(entity_name == "sup3")
     952             :         {
     953           0 :             return QString("%1").arg(QChar(179));
     954             :         }
     955           0 :         if(entity_name == "szlig")
     956             :         {
     957           0 :             return QString("%1").arg(QChar(223));
     958             :         }
     959           0 :         break;
     960             : 
     961           0 :     case 'T':
     962           0 :         if(entity_name == "THORN")
     963             :         {
     964           0 :             return QString("%1").arg(QChar(222));
     965             :         }
     966           0 :         break;
     967             : 
     968           0 :     case 't':
     969           0 :         if(entity_name == "thorn")
     970             :         {
     971           0 :             return QString("%1").arg(QChar(254));
     972             :         }
     973           0 :         if(entity_name == "times")
     974             :         {
     975           0 :             return QString("%1").arg(QChar(215));
     976             :         }
     977           0 :         break;
     978             : 
     979           0 :     case 'U':
     980           0 :         if(entity_name == "Uacute")
     981             :         {
     982           0 :             return QString("%1").arg(QChar(218));
     983             :         }
     984           0 :         if(entity_name == "Ucirc")
     985             :         {
     986           0 :             return QString("%1").arg(QChar(219));
     987             :         }
     988           0 :         if(entity_name == "Ugrave")
     989             :         {
     990           0 :             return QString("%1").arg(QChar(217));
     991             :         }
     992           0 :         if(entity_name == "Uuml")
     993             :         {
     994           0 :             return QString("%1").arg(QChar(220));
     995             :         }
     996           0 :         break;
     997             : 
     998           0 :     case 'u':
     999           0 :         if(entity_name == "uacute")
    1000             :         {
    1001           0 :             return QString("%1").arg(QChar(250));
    1002             :         }
    1003           0 :         if(entity_name == "ucirc")
    1004             :         {
    1005           0 :             return QString("%1").arg(QChar(251));
    1006             :         }
    1007           0 :         if(entity_name == "ugrave")
    1008             :         {
    1009           0 :             return QString("%1").arg(QChar(249));
    1010             :         }
    1011           0 :         if(entity_name == "uml")
    1012             :         {
    1013           0 :             return QString("%1").arg(QChar(168));
    1014             :         }
    1015           0 :         if(entity_name == "uuml")
    1016             :         {
    1017           0 :             return QString("%1").arg(QChar(252));
    1018             :         }
    1019           0 :         break;
    1020             : 
    1021           0 :     case 'Y':
    1022           0 :         if(entity_name == "Yacute")
    1023             :         {
    1024           0 :             return QString("%1").arg(QChar(221));
    1025             :         }
    1026           0 :         break;
    1027             : 
    1028           0 :     case 'y':
    1029           0 :         if(entity_name == "yacute")
    1030             :         {
    1031           0 :             return QString("%1").arg(QChar(253));
    1032             :         }
    1033           0 :         if(entity_name == "yen")
    1034             :         {
    1035           0 :             return QString("%1").arg(QChar(165));
    1036             :         }
    1037           0 :         if(entity_name == "yuml")
    1038             :         {
    1039           0 :             return QString("%1").arg(QChar(255));
    1040             :         }
    1041           0 :         break;
    1042             : 
    1043             :     }
    1044             : 
    1045             :     // if we reach here then it was not found...
    1046           0 :     return QString("&amp;%1;").arg(entity_name);
    1047             : }
    1048             : 
    1049             : 
    1050           6 : } // namespace snap
    1051             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13