LCOV - code coverage report
Current view: top level - snapwebsites - qhtmlserializer.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 132 0.0 %
Date: 2019-12-15 17:13:15 Functions: 0 16 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Snap Websites Servers -- generate HTML from the output of an XML Query
       2             : // Copyright (c) 2011-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             : // The importance of having an HTML specific serializer comes from
      19             : // the fact that XML defines empty tags as <div/> which are not
      20             : // supported by most browsers. This serializer generates <div></div>
      21             : // which works in all browsers. It is sad that such things are as
      22             : // they are, but browsers have to be compatible with many old websites
      23             : // which include such bad syntax.
      24             : //
      25             : // Also unfortunate, Qt does not provide such a class.
      26             : 
      27             : 
      28             : // self
      29             : //
      30             : #include "snapwebsites/qhtmlserializer.h"
      31             : 
      32             : 
      33             : // C++ lib
      34             : //
      35             : #include <stdexcept>
      36             : 
      37             : 
      38             : // last include
      39             : //
      40             : #include <snapdev/poison.h>
      41             : 
      42             : 
      43             : 
      44             : 
      45             : 
      46           0 : QHtmlSerializer::QHtmlSerializer(QXmlNamePool namepool, QBuffer *output, bool const is_html)
      47             :     : f_namepool(namepool)
      48             :     , f_output(output)
      49             :     , f_status(html_serializer_status_t::HTML_SERIALIZER_STATUS_READY)
      50           0 :     , f_is_html(is_html)
      51             : {
      52           0 : }
      53             : 
      54             : 
      55           0 : QHtmlSerializer::~QHtmlSerializer()
      56             : {
      57           0 : }
      58             : 
      59             : 
      60             : #pragma GCC diagnostic push
      61             : #pragma GCC diagnostic ignored "-Wunused-parameter"
      62           0 : void QHtmlSerializer::atomicValue(const QVariant& value)
      63             : {
      64           0 : }
      65             : #pragma GCC diagnostic pop
      66             : 
      67             : 
      68           0 : void QHtmlSerializer::attribute(const QXmlName& name, const QStringRef& value)
      69             : {
      70           0 :     f_output->write(" ");
      71           0 :     if(!name.prefix(f_namepool).isEmpty())
      72             :     {
      73           0 :         f_output->write(name.prefix(f_namepool).toUtf8());
      74           0 :         f_output->write(":");
      75             :     }
      76           0 :     f_output->write(name.localName(f_namepool).toUtf8());
      77           0 :     f_output->write("=\"");
      78           0 :     QString v(value.toString());
      79           0 :     v.replace('&', "&amp;")
      80           0 :      .replace('\"', "&quot;")
      81           0 :      .replace('<', "&lt;")
      82           0 :      .replace('>', "&gt;");
      83           0 :     f_output->write(v.simplified().toUtf8());
      84           0 :     f_output->write("\"");
      85           0 : }
      86             : 
      87             : 
      88           0 : void QHtmlSerializer::characters(const QStringRef& value)
      89             : {
      90           0 :     closeElement();
      91             : 
      92           0 :     QString v(value.toString());
      93           0 :     v.replace('&', "&amp;")
      94           0 :      .replace('<', "&lt;")
      95           0 :      .replace('>', "&gt;");
      96           0 :     f_output->write(v.toUtf8());
      97           0 : }
      98             : 
      99             : 
     100           0 : void QHtmlSerializer::comment(const QString& value)
     101             : {
     102           0 :     closeElement();
     103             : 
     104             :     // TBD -- I would think that value cannot include "--"
     105             :     //        because it has to be a valid comment;
     106             :     //        also, we want to have a way to remove all
     107             :     //        "useless" comments from the output
     108           0 :     f_output->write("<!--");
     109           0 :     f_output->write(value.toUtf8());
     110           0 :     f_output->write("-->");
     111           0 : }
     112             : 
     113             : 
     114           0 : void QHtmlSerializer::endDocument()
     115             : {
     116             :     // we are done
     117           0 : }
     118             : 
     119             : 
     120           0 : void QHtmlSerializer::endElement()
     121             : {
     122             :     // here is the magic necessary for proper HTML, all tags
     123             :     // are always closed with </name> except it is marked as
     124             :     // an empty tag
     125           0 :     QString element(f_element_stack.back());
     126           0 :     f_element_stack.pop_back();
     127             : 
     128           0 :     QString e(element.toLower());
     129           0 :     bool is_empty(false);
     130           0 :     if(f_is_html) switch(e[0].unicode())
     131             :     {
     132           0 :     case 'a':
     133           0 :         is_empty = e == "area";
     134           0 :         break;
     135             : 
     136           0 :     case 'b':
     137           0 :         is_empty = e == "br" || e == "base" || e == "basefont";
     138           0 :         break;
     139             : 
     140           0 :     case 'c':
     141           0 :         is_empty = e == "col";
     142           0 :         break;
     143             : 
     144           0 :     case 'f':
     145           0 :         is_empty = e == "frame";
     146           0 :         break;
     147             : 
     148           0 :     case 'h':
     149           0 :         is_empty = e == "hr";
     150           0 :         break;
     151             : 
     152           0 :     case 'i':
     153           0 :         is_empty = e == "img" || e == "input" || e == "isindex";
     154           0 :         break;
     155             : 
     156           0 :     case 'l':
     157           0 :         is_empty = e == "link";
     158           0 :         break;
     159             : 
     160           0 :     case 'm':
     161           0 :         is_empty = e == "meta";
     162           0 :         break;
     163             : 
     164           0 :     case 'p':
     165           0 :         is_empty = e == "param";
     166           0 :         break;
     167             : 
     168           0 :     default:
     169           0 :         is_empty = false;
     170           0 :         break;
     171             : 
     172             :     }
     173           0 :     if(is_empty)
     174             :     {
     175           0 :         if(f_status != html_serializer_status_t::HTML_SERIALIZER_STATUS_ELEMENT_OPEN)
     176             :         {
     177           0 :             throw std::runtime_error(QString("data was written inside empty HTML tag \"%1\"").arg(e).toUtf8().data());
     178             :         }
     179           0 :         f_status = html_serializer_status_t::HTML_SERIALIZER_STATUS_READY;
     180             : 
     181             :         // close empty tag
     182             :         // (note that the / is not required, but we want to keep it
     183             :         // XML compatible)
     184           0 :         f_output->write("/>");
     185             :     }
     186             :     else
     187             :     {
     188           0 :         closeElement();
     189             : 
     190             :         // close the element
     191           0 :         f_output->write("</");
     192           0 :         f_output->write(element.toUtf8());
     193           0 :         f_output->write(">");
     194             :     }
     195           0 : }
     196             : 
     197             : 
     198           0 : void QHtmlSerializer::endOfSequence()
     199             : {
     200             :     // nothing to do here
     201           0 : }
     202             : 
     203             : 
     204           0 : void QHtmlSerializer::namespaceBinding(const QXmlName& name)
     205             : {
     206           0 :     QString uri(name.namespaceUri(f_namepool));
     207           0 :     if(!uri.isEmpty())
     208             :     {
     209             :         // prefix is saved as a suffix in an attribute name
     210           0 :         f_output->write(" xmlns");
     211           0 :         if(!name.prefix(f_namepool).isEmpty())
     212             :         {
     213           0 :             f_output->write(":");
     214           0 :             f_output->write(name.prefix(f_namepool).toUtf8());
     215             :         }
     216           0 :         f_output->write("=\"");
     217           0 :         uri.replace('\"', "&quot;")
     218           0 :            .replace('<', "&lt;")
     219           0 :            .replace('>', "&gt;")
     220           0 :            .replace('&', "&amp;");
     221           0 :         f_output->write(uri.toUtf8());
     222           0 :         f_output->write("\"");
     223             :     }
     224           0 : }
     225             : 
     226             : 
     227           0 : void QHtmlSerializer::processingInstruction(const QXmlName& target, const QString& value )
     228             : {
     229           0 :     closeElement();
     230             : 
     231             :     // prefix is saved as a suffix in a processing instruction
     232           0 :     f_output->write("<?");
     233           0 :     f_output->write(target.localName(f_namepool).toUtf8());
     234           0 :     QString prefix(target.prefix(f_namepool));
     235           0 :     if(!prefix.isEmpty())
     236             :     {
     237           0 :         f_output->write(":");
     238           0 :         f_output->write(prefix.toUtf8());
     239             :     }
     240           0 :     f_output->write(value.toUtf8());
     241           0 :     f_output->write("?>");
     242           0 : }
     243             : 
     244             : 
     245           0 : void QHtmlSerializer::startDocument()
     246             : {
     247             :     // should we create docs here?
     248           0 : }
     249             : 
     250             : 
     251           0 : void QHtmlSerializer::startElement(const QXmlName& name)
     252             : {
     253           0 :     closeElement();
     254             : 
     255           0 :     f_output->write("<");
     256           0 :     QString element(name.prefix(f_namepool));
     257           0 :     if(!element.isEmpty())
     258             :     {
     259           0 :         element += ":";
     260             :     }
     261           0 :     element += name.localName(f_namepool);
     262           0 :     f_output->write(element.toUtf8());
     263           0 :     f_status = html_serializer_status_t::HTML_SERIALIZER_STATUS_ELEMENT_OPEN;
     264           0 :     f_element_stack.push_back(element);
     265           0 : }
     266             : 
     267             : 
     268           0 : void QHtmlSerializer::startOfSequence()
     269             : {
     270             :     // nothing to do here
     271           0 : }
     272             : 
     273             : 
     274           0 : void QHtmlSerializer::closeElement()
     275             : {
     276           0 :     if(f_status == html_serializer_status_t::HTML_SERIALIZER_STATUS_ELEMENT_OPEN)
     277             :     {
     278           0 :         f_status = html_serializer_status_t::HTML_SERIALIZER_STATUS_READY;
     279           0 :         f_output->write(">");
     280             :     }
     281           0 : }
     282             : 
     283             : 
     284             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13