1 /*  $Id: html.cpp 435421 2014-05-15 19:29:47Z ucko $
2  * ===========================================================================
3  *
4  *                            PUBLIC DOMAIN NOTICE
5  *               National Center for Biotechnology Information
6  *
7  *  This software/database is a "United States Government Work" under the
8  *  terms of the United States Copyright Act.  It was written as part of
9  *  the author's official duties as a United States Government employee and
10  *  thus cannot be copyrighted.  This software/database is freely available
11  *  to the public for use. The National Library of Medicine and the U.S.
12  *  Government have not placed any restriction on its use or reproduction.
13  *
14  *  Although all reasonable efforts have been taken to ensure the accuracy
15  *  and reliability of the software and data, the NLM and the U.S.
16  *  Government do not and cannot warrant the performance or results that
17  *  may be obtained by using this software or data. The NLM and the U.S.
18  *  Government disclaim all warranties, express or implied, including
19  *  warranties of performance, merchantability or fitness for any particular
20  *  purpose.
21  *
22  *  Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors:  Lewis Geer, Eugene Vasilchenko, Vladimir Ivanov
27  *
28  */
29 
30 #include <ncbi_pch.hpp>
31 #include <html/html.hpp>
32 #include <html/htmlhelper.hpp>
33 #include <html/indentstream.hpp>
34 #include <html/html_exception.hpp>
35 #include <html/error_codes.hpp>
36 #include <errno.h>
37 #include <string.h>
38 
39 
40 #define NCBI_USE_ERRCODE_X   Html_Lib
41 
42 
43 BEGIN_NCBI_SCOPE
44 
45 
46 /// Tag delimiters
47 const char* kTagStart = "<@";   ///< Tag start
48 const char* kTagEnd   = "@>";   ///< Tag end
49 const SIZE_TYPE kTagStartLen = 2;
50 
51 
52 #define INIT_STREAM_WRITE  \
53     errno = 0
54 
55 #define CHECK_STREAM_WRITE(out)                                               \
56     if ( !out ) {                                                             \
57         int x_errno = errno;                                                  \
58         string x_err("write to stream failed");                               \
59         if (x_errno != 0) {                                                   \
60             const char* x_strerror = strerror(x_errno);                       \
61             if ( !x_strerror ) {                                              \
62                 x_strerror = "Error code is out of range";                    \
63             }                                                                 \
64             string x_strerrno = NStr::IntToString(x_errno);                   \
65             x_err += " {errno=" + x_strerrno + ',' + x_strerror + '}';        \
66         }                                                                     \
67         NCBI_THROW(CHTMLException, eWrite, x_err);                            \
68     }
69 
70 
s_GenerateNodeInternalName(const string & basename,const string & v1,const string & v2=kEmptyStr)71 static string s_GenerateNodeInternalName(const string& basename,
72                                          const string& v1,
73                                          const string& v2 = kEmptyStr)
74 {
75     string name(basename);
76     if ( !v1.empty() ) {
77         name += "(\"" + v1.substr(0,10) + "\"";
78         if ( !v2.empty() ) {
79             name += "|\"" + v2.substr(0,10) + "\"";
80         }
81         name += ")";
82     }
83     return name;
84 }
85 
86 
s_Find(const string & s,const char * target,SIZE_TYPE start=0)87 static SIZE_TYPE s_Find(const string& s, const char* target,
88                         SIZE_TYPE start = 0)
89 {
90     // Return s.find(target);
91     // Some implementations of string::find call memcmp at every
92     // possible position, which is way too slow.
93     if ( start >= s.size() ) {
94         return NPOS;
95     }
96     const char* cstr = s.c_str();
97     const char* p    = strstr(cstr + start, target);
98     return p ? p - cstr : NPOS;
99 }
100 
101 
102 // CHTMLNode
103 
~CHTMLNode(void)104 CHTMLNode::~CHTMLNode(void)
105 {
106     return;
107 }
108 
GetEventHandlerName(const EHTML_EH_Attribute name) const109 string CHTMLNode::GetEventHandlerName(const EHTML_EH_Attribute name) const
110 {
111     switch (name) {
112         case eHTML_EH_Blur:
113             return "onblur";
114         case eHTML_EH_Change:
115             return "onchange";
116         case eHTML_EH_Click:
117             return "onclick";
118         case eHTML_EH_DblClick:
119             return "ondblclick";
120         case eHTML_EH_Focus:
121             return "onfocus";
122         case eHTML_EH_Load:
123             return "onload";
124         case eHTML_EH_Unload:
125             return "onunload";
126         case eHTML_EH_MouseDown:
127             return "onmousedown";
128         case eHTML_EH_MouseUp:
129             return "onmouseup";
130         case eHTML_EH_MouseMove:
131             return "onmousemove";
132         case eHTML_EH_MouseOver:
133             return "onmouseover";
134         case eHTML_EH_MouseOut:
135             return "onmouseout";
136         case eHTML_EH_Select:
137             return "onselect";
138         case eHTML_EH_Submit:
139             return "onsubmit";
140         case eHTML_EH_KeyDown:
141             return "onkeydown";
142         case eHTML_EH_KeyPress:
143             return "onkeypress";
144         case eHTML_EH_KeyUp:
145             return "onkeyup";
146     }
147     _TROUBLE;
148     return kEmptyStr;
149 }
150 
151 
SetEventHandler(const EHTML_EH_Attribute event,const string & value)152 void CHTMLNode::SetEventHandler(const EHTML_EH_Attribute event,
153                                 const string& value)
154 {
155     if ( value.empty() ) {
156         return;
157     }
158     SetAttribute(GetEventHandlerName(event), value);
159 }
160 
161 
162 // <@XXX@> mapping tag node
163 
CHTMLTagNode(const char * name)164 CHTMLTagNode::CHTMLTagNode(const char* name)
165     : CParent(name)
166 {
167     return;
168 }
169 
CHTMLTagNode(const string & name)170 CHTMLTagNode::CHTMLTagNode(const string& name)
171     : CParent(name)
172 {
173     return;
174 }
175 
~CHTMLTagNode(void)176 CHTMLTagNode::~CHTMLTagNode(void)
177 {
178     return;
179 }
180 
PrintChildren(CNcbiOstream & out,TMode mode)181 CNcbiOstream& CHTMLTagNode::PrintChildren(CNcbiOstream& out, TMode mode)
182 {
183     CNodeRef node = MapTagAll(GetName(), mode);
184     if ( node ) {
185         node->Print(out, mode);
186     }
187     return out;
188 }
189 
190 
191 // Dual text node.
192 
CHTMLDualNode(const char * html,const char * plain)193 CHTMLDualNode::CHTMLDualNode(const char* html, const char* plain)
194     : CParent(s_GenerateNodeInternalName("dualnode", html, plain))
195 {
196     AppendChild(new CHTMLText(html));
197     m_Plain = plain;
198 }
199 
CHTMLDualNode(CNCBINode * child,const char * plain)200 CHTMLDualNode::CHTMLDualNode(CNCBINode* child, const char* plain)
201     : CParent(s_GenerateNodeInternalName("dualnode", "[node]", plain))
202 {
203     AppendChild(child);
204     m_Plain = plain;
205 }
206 
~CHTMLDualNode(void)207 CHTMLDualNode::~CHTMLDualNode(void)
208 {
209     return;
210 }
211 
PrintChildren(CNcbiOstream & out,TMode mode)212 CNcbiOstream& CHTMLDualNode::PrintChildren(CNcbiOstream& out, TMode mode)
213 {
214     switch (mode) {
215         case ePlainText:
216             INIT_STREAM_WRITE;
217             out << m_Plain;
218             CHECK_STREAM_WRITE(out);
219             break;
220         case eHTML:
221         case eXHTML:
222             CParent::PrintChildren(out, mode);
223             break;
224     }
225     return out;
226 }
227 
228 
229 // plain text node
230 
CHTMLPlainText(EEncodeMode encode_mode,const string & text)231 CHTMLPlainText::CHTMLPlainText(EEncodeMode encode_mode, const string& text) :
232         CNCBINode(s_GenerateNodeInternalName("plaintext", text)),
233     m_Text(text), m_EncodeMode(encode_mode)
234 {
235 }
236 
CHTMLPlainText(const char * text,bool noEncode)237 CHTMLPlainText::CHTMLPlainText(const char* text, bool noEncode)
238     : CNCBINode(s_GenerateNodeInternalName("plaintext", text)),
239         m_Text(text)
240 {
241     SetNoEncode(noEncode);
242 }
243 
CHTMLPlainText(const string & text,bool noEncode)244 CHTMLPlainText::CHTMLPlainText(const string& text, bool noEncode)
245     : CNCBINode(s_GenerateNodeInternalName("plaintext", text)),
246         m_Text(text)
247 {
248     SetNoEncode(noEncode);
249 }
250 
~CHTMLPlainText(void)251 CHTMLPlainText::~CHTMLPlainText(void)
252 {
253 }
254 
255 
PrintBegin(CNcbiOstream & out,TMode mode)256 CNcbiOstream& CHTMLPlainText::PrintBegin(CNcbiOstream& out, TMode mode)
257 {
258     string str(GetText());
259     switch (mode) {
260         case ePlainText:
261             if (m_EncodeMode == eJSONEncode)
262                 str = NStr::JsonEncode(str);
263             break;
264         case eHTML:
265         case eXHTML:
266             switch (m_EncodeMode) {
267             case eJSONEncode:
268                 str = NStr::JsonEncode(str);
269             case eNoEncode:
270                 break;
271             case eHTMLEncode:
272                 str = CHTMLHelper::HTMLEncode(str);
273             }
274             break;
275     }
276     INIT_STREAM_WRITE;
277     out << str;
278     CHECK_STREAM_WRITE(out);
279     return out;
280 }
281 
282 
283 // text node
284 
CHTMLText(const string & text,TFlags flags)285 CHTMLText::CHTMLText(const string& text, TFlags flags)
286     : CParent(s_GenerateNodeInternalName("htmltext", text)),
287       m_Text(text), m_Flags(flags)
288 {
289     return;
290 }
291 
CHTMLText(const char * text,TFlags flags)292 CHTMLText::CHTMLText(const char* text, TFlags flags)
293     : CParent(s_GenerateNodeInternalName("htmltext", text)),
294       m_Text(text), m_Flags(flags)
295 {
296     return;
297 }
298 
~CHTMLText(void)299 CHTMLText::~CHTMLText(void)
300 {
301     return;
302 }
303 
PrintString(CNcbiOstream & out,TMode mode,const string & s) const304 CNcbiOstream& CHTMLText::PrintString(CNcbiOstream& out, TMode mode,
305                                      const string& s) const
306 {
307     TFlags flags = 0;
308     switch (mode) {
309         case ePlainText:
310             if ( m_Flags & fStripTextMode )
311                 flags |= fStrip;
312             if ( m_Flags & fEncodeTextMode )
313                 flags |= fEncode;
314             break;
315         case eHTML:
316         case eXHTML:
317             if ( m_Flags & fStripHtmlMode )
318                 flags |= fStrip;
319             if ( m_Flags & fEncodeHtmlMode )
320                 flags |= fEncode;
321             break;
322     }
323     string str;
324     const string *pstr = &str;
325     switch (flags) {
326         case fStrip:
327             str = CHTMLHelper::StripHTML(s);
328             break;
329         case fEncode:
330             str = CHTMLHelper::HTMLEncode(s);
331             break;
332         case fStrip | fEncode:
333             str = CHTMLHelper::HTMLEncode(CHTMLHelper::StripHTML(s));
334             break;
335         default:
336             pstr = &s;
337     }
338     INIT_STREAM_WRITE;
339     out.write(pstr->data(), pstr->size());
340     CHECK_STREAM_WRITE(out);
341     return out;
342 }
343 
344 
345 #define PRINT_TMP_STR \
346     if ( enable_buffering ) { \
347         pstr->write(tmp.data(), tmp.size()); \
348     } else { \
349         PrintString(out, mode, tmp); \
350     }
351 
PrintBegin(CNcbiOstream & out,TMode mode)352 CNcbiOstream& CHTMLText::PrintBegin(CNcbiOstream& out, TMode mode)
353 {
354     const string& text = GetText();
355     SIZE_TYPE tagStart = s_Find(text, kTagStart);
356     if ( tagStart == NPOS ) {
357         return PrintString(out, mode, text);
358     }
359 
360     // Check flag to enabe output buffering
361     bool enable_buffering = !(m_Flags & fDisableBuffering);
362     CNcbiOstrstream *pstr = 0;
363     if ( enable_buffering ) {
364         pstr = new CNcbiOstrstream;
365     }
366 
367     // Printout string before the first start mapping tag
368     string tmp = text.substr(0, tagStart);
369     PRINT_TMP_STR;
370 
371     // Map all tags
372     SIZE_TYPE last = tagStart;
373     do {
374         SIZE_TYPE tagNameStart = tagStart + kTagStartLen;
375         SIZE_TYPE tagNameEnd = s_Find(text, kTagEnd, tagNameStart);
376         if ( tagNameEnd == NPOS ) {
377             // tag not closed
378             NCBI_THROW(CHTMLException, eTextUnclosedTag, "tag not closed");
379         }
380         else {
381             // tag found
382             if ( last != tagStart ) {
383                 tmp = text.substr(last, tagStart - last);
384                 PRINT_TMP_STR;
385             }
386             string name = text.substr(tagNameStart,tagNameEnd-tagNameStart);
387             // Resolve and repeat tag
388             for (;;) {
389                 CNodeRef tag = MapTagAll(name, mode);
390                 if ( tag ) {
391                     if ( enable_buffering ) {
392                         tag->Print(*pstr, mode);
393                     } else {
394                         tag->Print(out, mode);
395                     }
396                     if ( tag->NeedRepeatTag() ) {
397                         RepeatTag(false);
398                         continue;
399                     }
400                 }
401                 break;
402             }
403             last = tagNameEnd + kTagStartLen;
404             tagStart = s_Find(text, kTagStart, last);
405         }
406     } while ( tagStart != NPOS );
407 
408     if ( last != text.size() ) {
409         tmp = text.substr(last);
410         PRINT_TMP_STR;
411     }
412     if ( enable_buffering ) {
413         PrintString(out, mode, CNcbiOstrstreamToString(*pstr));
414         delete pstr;
415     }
416     return out;
417 }
418 
419 
~CHTMLOpenElement(void)420 CHTMLOpenElement::~CHTMLOpenElement(void)
421 {
422     return;
423 }
424 
x_PrintBegin(CNcbiOstream & out,TMode mode)425 CNcbiOstream& CHTMLOpenElement::x_PrintBegin(CNcbiOstream& out, TMode mode)
426 {
427     switch (mode) {
428         case ePlainText:
429             break;
430         case eHTML:
431         case eXHTML:
432             out << '<' << m_Name;
433             if ( HaveAttributes() ) {
434                 for ( TAttributes::const_iterator i = Attributes().begin();
435                     i != Attributes().end(); ++i ) {
436                     INIT_STREAM_WRITE;
437                     out << ' ' << i->first;
438                     CHECK_STREAM_WRITE(out);
439 
440                     if ( (mode == eXHTML)  ||
441                          !i->second.IsOptional()  ||
442                          !i->second.GetValue().empty() ) {
443                         string attr = i->second.GetValue();
444                         out << "=\"";
445                         if ( attr.empty() ) {
446                             // For XHTML attribute minimization is forbidden
447                             if ((mode == eXHTML) &&  i->second.IsOptional()) {
448                                 out << i->first;
449                             }
450                         } else {
451                             if ( attr.find_first_of("\"&") != NPOS ) {
452                                 // Escape attributes
453                                 attr = CHTMLHelper::HTMLAttributeEncode(attr,
454                                             CHTMLHelper::fSkipEntities |
455     /* NOTE:
456         temporary use fCheckPreencoded flag here to clean up redundant
457         HTMLEncode() calls from NCBI code.
458     */
459                                             CHTMLHelper::fCheckPreencoded);
460                             }
461                             // Check tags inside attribute value
462                             if (s_Find(attr, kTagStart) == NPOS) {
463                                 out << attr;
464                             } else {
465                                 CHTMLText tmp(attr);
466                                 tmp.Print(out, mode);
467                             }
468                         }
469                         out << '"';
470                     }
471                 }
472             }
473             break;
474     }
475     return out;
476 }
477 
478 
PrintBegin(CNcbiOstream & out,TMode mode)479 CNcbiOstream& CHTMLOpenElement::PrintBegin(CNcbiOstream& out, TMode mode)
480 {
481     x_PrintBegin(out, mode);
482     switch (mode) {
483         case ePlainText:
484             break;
485         case eHTML:
486         case eXHTML:
487             INIT_STREAM_WRITE;
488             out << '>';
489             CHECK_STREAM_WRITE(out);
490             break;
491     }
492     return out;
493 }
494 
495 
~CHTMLSingleElement(void)496 CHTMLSingleElement::~CHTMLSingleElement(void)
497 {
498     return;
499 }
500 
501 
PrintBegin(CNcbiOstream & out,TMode mode)502 CNcbiOstream& CHTMLSingleElement::PrintBegin(CNcbiOstream& out, TMode mode)
503 {
504     switch (mode) {
505         case ePlainText:
506         case eHTML:
507             CParent::PrintBegin(out, mode);
508             break;
509         case eXHTML:
510             x_PrintBegin(out, mode);
511             INIT_STREAM_WRITE;
512             out << " />";
513             CHECK_STREAM_WRITE(out);
514             break;
515     }
516     return out;
517 }
518 
519 
~CHTMLInlineElement(void)520 CHTMLInlineElement::~CHTMLInlineElement(void)
521 {
522     return;
523 }
524 
525 
PrintEnd(CNcbiOstream & out,TMode mode)526 CNcbiOstream& CHTMLInlineElement::PrintEnd(CNcbiOstream& out, TMode mode)
527 {
528     switch (mode) {
529         case ePlainText:
530             break;
531         case eHTML:
532         case eXHTML:
533             INIT_STREAM_WRITE;
534             out << "</" << m_Name << '>';
535             CHECK_STREAM_WRITE(out);
536             break;
537     }
538     return out;
539 }
540 
541 
~CHTMLElement(void)542 CHTMLElement::~CHTMLElement(void)
543 {
544     return;
545 }
546 
547 
PrintEnd(CNcbiOstream & out,TMode mode)548 CNcbiOstream& CHTMLElement::PrintEnd(CNcbiOstream& out, TMode mode)
549 {
550     CParent::PrintEnd(out, mode);
551     switch (mode) {
552         case ePlainText:
553             break;
554         case eHTML:
555         case eXHTML:
556             const TMode* previous = mode.GetPreviousContext();
557             INIT_STREAM_WRITE;
558             if ( previous ) {
559                 CNCBINode* parent = previous->GetNode();
560                 if ( parent && parent->HaveChildren() &&
561                     parent->Children().size() > 1 )
562                     // separate child nodes by newline
563                     out << CHTMLHelper::GetNL();
564             } else {
565                 out << CHTMLHelper::GetNL();
566             }
567             CHECK_STREAM_WRITE(out);
568             break;
569     }
570     return out;
571 }
572 
573 
~CHTMLBlockElement(void)574 CHTMLBlockElement::~CHTMLBlockElement(void)
575 {
576     return;
577 }
578 
579 
PrintEnd(CNcbiOstream & out,TMode mode)580 CNcbiOstream& CHTMLBlockElement::PrintEnd(CNcbiOstream& out, TMode mode)
581 {
582     CParent::PrintEnd(out, mode);
583     switch (mode) {
584         case ePlainText:
585             {{
586             // Add a newline iff no node on the path to the last descendant
587             // is also a block element. We only need one break.
588             CNCBINode* node = this;
589             while (node->HaveChildren()) {
590                 node = node->Children().back();
591                 if (dynamic_cast<CHTMLBlockElement*>(node)) {
592                     return out;
593                 }
594             }
595             INIT_STREAM_WRITE;
596             out << CHTMLHelper::GetNL();
597             CHECK_STREAM_WRITE(out);
598             }}
599             break;
600         case eHTML:
601         case eXHTML:
602             break;
603     }
604     return out;
605 }
606 
607 
608 // HTML comment.
609 
610 const char CHTMLComment::sm_TagName[] = "comment";
611 
~CHTMLComment(void)612 CHTMLComment::~CHTMLComment(void)
613 {
614     return;
615 }
616 
Print(CNcbiOstream & out,TMode mode)617 CNcbiOstream& CHTMLComment::Print(CNcbiOstream& out, TMode mode)
618 {
619     switch (mode) {
620         case ePlainText:
621             break;
622         case eHTML:
623         case eXHTML:
624             CParent::Print(out, mode);
625             break;
626     }
627     return out;
628 }
629 
PrintBegin(CNcbiOstream & out,TMode mode)630 CNcbiOstream& CHTMLComment::PrintBegin(CNcbiOstream& out, TMode mode)
631 {
632     switch (mode) {
633         case ePlainText:
634             break;
635         case eHTML:
636         case eXHTML:
637             INIT_STREAM_WRITE;
638             out << "<!--";
639             CHECK_STREAM_WRITE(out);
640             break;
641     }
642     return out;
643 }
644 
PrintEnd(CNcbiOstream & out,TMode mode)645 CNcbiOstream& CHTMLComment::PrintEnd(CNcbiOstream& out, TMode mode)
646 {
647     switch (mode) {
648         case ePlainText:
649             break;
650         case eHTML:
651         case eXHTML:
652             INIT_STREAM_WRITE;
653             out << "-->";
654             CHECK_STREAM_WRITE(out);
655             break;
656     }
657     return out;
658 }
659 
~CHTMLListElement(void)660 CHTMLListElement::~CHTMLListElement(void)
661 {
662     return;
663 }
664 
SetType(const char * type)665 CHTMLListElement* CHTMLListElement::SetType(const char* type)
666 {
667     SetAttribute("type", type);
668     return this;
669 }
670 
SetType(const string & type)671 CHTMLListElement* CHTMLListElement::SetType(const string& type)
672 {
673     SetAttribute("type", type);
674     return this;
675 }
676 
SetCompact(void)677 CHTMLListElement* CHTMLListElement::SetCompact(void)
678 {
679     SetAttribute("compact");
680     return this;
681 }
682 
PrintChildren(CNcbiOstream & out,TMode mode)683 CNcbiOstream& CHTMLListElement::PrintChildren(CNcbiOstream& out, TMode mode)
684 {
685     switch (mode) {
686         case ePlainText:
687             {{
688                 CIndentingOstream out2(out);
689                 CHTMLElement::PrintChildren(out2, mode);
690             }}
691             break;
692         case eHTML:
693         case eXHTML:
694             CHTMLElement::PrintChildren(out, mode);
695             break;
696     }
697     return out;
698 }
699 
700 
701 // Special char.
702 
CHTMLSpecialChar(const char * html,const char * plain,int count)703 CHTMLSpecialChar::CHTMLSpecialChar(const char* html, const char* plain,
704                                    int count)
705     : CParent("", plain)
706 {
707     m_Name  = s_GenerateNodeInternalName("specialchar", html);
708     m_Html  = html;
709     m_Count = count;
710 }
711 
712 
~CHTMLSpecialChar(void)713 CHTMLSpecialChar::~CHTMLSpecialChar(void)
714 {
715     return;
716 }
717 
718 
PrintChildren(CNcbiOstream & out,TMode mode)719 CNcbiOstream& CHTMLSpecialChar::PrintChildren(CNcbiOstream& out, TMode mode)
720 {
721     switch (mode) {
722         case ePlainText:
723             for ( int i = 0; i < m_Count; i++ ) {
724                 INIT_STREAM_WRITE;
725                 out << m_Plain;
726                 CHECK_STREAM_WRITE(out);
727             }
728             break;
729         case eHTML:
730         case eXHTML:
731             for ( int i = 0; i < m_Count; i++ ) {
732                 INIT_STREAM_WRITE;
733                 out << "&" << m_Html << ";";
734                 CHECK_STREAM_WRITE(out);
735             }
736             break;
737     }
738     return out;
739 }
740 
741 
742 // <html> tag.
743 
744 const char CHTML_html::sm_TagName[] = "html";
745 
~CHTML_html(void)746 CHTML_html::~CHTML_html(void)
747 {
748     return;
749 }
750 
Init(void)751 void CHTML_html::Init(void)
752 {
753     return;
754 }
755 
CHTML_tr(void)756 CHTML_tr::CHTML_tr(void)
757     : CParent("tr"), m_Parent(0)
758 {
759     return;
760 }
761 
CHTML_tr(CNCBINode * node)762 CHTML_tr::CHTML_tr(CNCBINode* node)
763     : CParent("tr", node), m_Parent(0)
764 {
765     return;
766 }
767 
CHTML_tr(const string & text)768 CHTML_tr::CHTML_tr(const string& text)
769     : CParent("tr", text), m_Parent(0)
770 {
771     return;
772 }
773 
DoAppendChild(CNCBINode * node)774 void CHTML_tr::DoAppendChild(CNCBINode* node)
775 {
776     CHTML_tc* cell = dynamic_cast<CHTML_tc*>(node);
777     if ( cell ) {
778         // Adding new cell
779         _ASSERT(!cell->m_Parent);
780         ResetTableCache();
781         cell->m_Parent = this;
782     }
783     CParent::DoAppendChild(node);
784 }
785 
AppendCell(CHTML_tc * cell)786 void CHTML_tr::AppendCell(CHTML_tc* cell)
787 {
788     _ASSERT(!cell->m_Parent);
789     cell->m_Parent = this;
790     CParent::DoAppendChild(cell);
791 }
792 
ResetTableCache(void)793 void CHTML_tr::ResetTableCache(void)
794 {
795     if ( m_Parent )
796         m_Parent->ResetTableCache();
797 }
798 
PrintEnd(CNcbiOstream & out,TMode mode)799 CNcbiOstream& CHTML_tr::PrintEnd(CNcbiOstream& out, TMode mode)
800 {
801     CParent::PrintEnd(out, mode);
802     switch (mode) {
803         case ePlainText:
804             if ( m_Parent ) {
805                 INIT_STREAM_WRITE;
806                 out << CHTMLHelper::GetNL();
807                 if (m_Parent->m_IsRowSep == CHTML_table::ePrintRowSep) {
808                     out << string(GetTextLength(mode), m_Parent->m_RowSepChar)
809                         << CHTMLHelper::GetNL();
810                 }
811                 CHECK_STREAM_WRITE(out);
812             }
813             break;
814         case eHTML:
815         case eXHTML:
816             break;
817     }
818     return out;
819 }
820 
PrintChildren(CNcbiOstream & out,TMode mode)821 CNcbiOstream& CHTML_tr::PrintChildren(CNcbiOstream& out, TMode mode)
822 {
823     if ( !HaveChildren() ) {
824         return out;
825     }
826     switch (mode) {
827         case ePlainText:
828             break;
829         case eHTML:
830         case eXHTML:
831             return CParent::PrintChildren(out, mode);
832     }
833     out << m_Parent->m_ColSepL;
834     NON_CONST_ITERATE ( TChildren, i, Children() ) {
835         if ( i != Children().begin() ) {
836             INIT_STREAM_WRITE;
837             out << m_Parent->m_ColSepM;
838             CHECK_STREAM_WRITE(out);
839         }
840         Node(i)->Print(out, mode);
841     }
842     INIT_STREAM_WRITE;
843     out << m_Parent->m_ColSepR;
844     CHECK_STREAM_WRITE(out);
845 
846     return out;
847 }
848 
GetTextLength(TMode mode)849 SIZE_TYPE CHTML_tr::GetTextLength(TMode mode)
850 {
851     if ( !HaveChildren() ) {
852         return 0;
853     }
854     CNcbiOstrstream sout;
855     SIZE_TYPE cols = 0;
856 
857     NON_CONST_ITERATE ( TChildren, i, Children() ) {
858         Node(i)->Print(sout, mode);
859         cols++;
860     }
861     SIZE_TYPE textlen = (SIZE_TYPE)GetOssSize(sout);
862 
863     switch (mode) {
864         case ePlainText:
865             textlen += m_Parent->m_ColSepL.length() +
866                 m_Parent->m_ColSepR.length();
867             if ( cols ) {
868                 textlen += m_Parent->m_ColSepM.length() * (cols - 1);
869             }
870             break;
871         case eHTML:
872         case eXHTML:
873             break;
874     }
875     return textlen;
876 }
877 
~CHTML_tc(void)878 CHTML_tc::~CHTML_tc(void)
879 {
880     return;
881 }
882 
SetRowSpan(TIndex span)883 CHTML_tc* CHTML_tc::SetRowSpan(TIndex span)
884 {
885     SetAttribute("rowspan", span);
886     return this;
887 }
888 
SetColSpan(TIndex span)889 CHTML_tc* CHTML_tc::SetColSpan(TIndex span)
890 {
891     SetAttribute("colspan", span);
892     return this;
893 }
894 
895 static
x_GetSpan(const CHTML_tc * node,const string & attributeName)896 CHTML_table::TIndex x_GetSpan(const CHTML_tc* node,
897                               const string& attributeName)
898 {
899     if ( !node->HaveAttribute(attributeName) ) {
900         return 1;
901     }
902     const string& value = node->GetAttribute(attributeName);
903 
904     try {
905         CHTML_table::TIndex span = NStr::StringToUInt(value);
906         if ( span > 0 ) {
907             return span;
908         }
909     }
910     catch ( exception& ) {
911         // Error will be posted later
912     }
913     ERR_POST_X(1, "Bad attribute: " << attributeName << "=\"" << value << "\"");
914     return 1;
915 }
916 
DoSetAttribute(const string & name,const string & value,bool optional)917 void CHTML_tc::DoSetAttribute(const string& name,
918                               const string& value, bool optional)
919 {
920     if (name == "rowspan"  ||  name == "colspan") {
921         // Changing cell size
922         ResetTableCache();
923     }
924     CParent::DoSetAttribute(name, value, optional);
925 }
926 
ResetTableCache(void)927 void CHTML_tc::ResetTableCache(void)
928 {
929     if ( m_Parent ) {
930         m_Parent->ResetTableCache();
931     }
932 }
933 
SetUsed()934 void CHTML_tc_Cache::SetUsed()
935 {
936     if ( IsUsed() ) {
937         NCBI_THROW(CHTMLException, eTableCellUse, "overlapped table cells");
938     }
939     m_Used = true;
940 }
941 
SetCellNode(CHTML_tc * cellNode)942 void CHTML_tc_Cache::SetCellNode(CHTML_tc* cellNode)
943 {
944     SetUsed();
945     m_Node = cellNode;
946 }
947 
948 static
x_NextSize(CHTML_table::TIndex size,CHTML_table::TIndex limit)949 CHTML_table::TIndex x_NextSize(CHTML_table::TIndex size,
950                                CHTML_table::TIndex limit)
951 {
952     do {
953         if ( size == 0 )
954             size = 2;
955         else
956             size *= 2;
957     } while ( size < limit );
958     return size;
959 }
960 
GetCellCache(TIndex col)961 CHTML_tc_Cache& CHTML_tr_Cache::GetCellCache(TIndex col)
962 {
963     TIndex count = GetCellCount();
964     if ( col >= count ) {
965         TIndex newCount = col + 1;
966         TIndex size = m_CellsSize;
967         if ( newCount > size ) {
968             TIndex newSize = x_NextSize(size, newCount);
969             CHTML_tc_Cache* newCells = new CHTML_tc_Cache[newSize];
970             for ( TIndex i = 0; i < count; ++i )
971                 newCells[i] = m_Cells[i];
972             delete[] m_Cells;
973             m_Cells = newCells;
974             m_CellsSize = newSize;
975         }
976         m_CellCount = newCount;
977     }
978     return m_Cells[col];
979 }
980 
SetUsedCells(TIndex colBegin,TIndex colEnd)981 void CHTML_tr_Cache::SetUsedCells(TIndex colBegin, TIndex colEnd)
982 {
983     for ( TIndex col = colBegin; col < colEnd; ++col ) {
984         GetCellCache(col).SetUsed();
985     }
986 }
987 
AppendCell(CHTML_tr * rowNode,TIndex col,CHTML_tc * cellNode,TIndex colSpan)988 void CHTML_tr_Cache::AppendCell(CHTML_tr* rowNode, TIndex col,
989                                 CHTML_tc* cellNode, TIndex colSpan)
990 {
991     _ASSERT(m_FilledCellCount <= col);
992     for ( TIndex i = m_FilledCellCount; i < col; ++i ) {
993         CHTML_tc_Cache& cellCache = GetCellCache(i);
994         if ( !cellCache.IsUsed() ) {
995             CHTML_tc* cell;
996             cell = new CHTML_td;
997             rowNode->AppendCell(cell);
998             cellCache.SetCellNode(cell);
999         }
1000     }
1001     CHTML_tc_Cache& cellCache = GetCellCache(col);
1002     _ASSERT(!cellCache.IsUsed());
1003     _ASSERT(x_GetSpan(cellNode, "colspan") == colSpan);
1004     rowNode->AppendCell(cellNode);
1005     cellCache.SetCellNode(cellNode);
1006     if ( colSpan != 1 ) {
1007         SetUsedCells(col + 1, col + colSpan);
1008     }
1009     m_FilledCellCount = col + colSpan;
1010 }
1011 
SetUsedCells(CHTML_tc * cellNode,TIndex colBegin,TIndex colEnd)1012 void CHTML_tr_Cache::SetUsedCells(CHTML_tc* cellNode,
1013                                   TIndex colBegin, TIndex colEnd)
1014 {
1015     GetCellCache(colBegin).SetCellNode(cellNode);
1016     SetUsedCells(colBegin + 1, colEnd);
1017     m_FilledCellCount = colEnd;
1018 }
1019 
1020 
~CHTML_table_Cache(void)1021 CHTML_table_Cache::~CHTML_table_Cache(void)
1022 {
1023     for ( TIndex i = 0; i < GetRowCount(); ++i ) {
1024         delete m_Rows[i];
1025     }
1026     delete[] m_Rows;
1027 }
1028 
1029 
GetRowCache(TIndex row)1030 CHTML_tr_Cache& CHTML_table_Cache::GetRowCache(TIndex row)
1031 {
1032     TIndex count = GetRowCount();
1033     if ( row >= count ) {
1034         TIndex newCount = row + 1;
1035         TIndex size = m_RowsSize;
1036         if ( newCount > size ) {
1037             TIndex newSize = x_NextSize(size, newCount);
1038             CHTML_tr_Cache** newRows = new CHTML_tr_Cache*[newSize];
1039             for ( TIndex i = 0; i < count; ++i )
1040                 newRows[i] = m_Rows[i];
1041             delete[] m_Rows;
1042             m_Rows = newRows;
1043             m_RowsSize = newSize;
1044         }
1045         for ( TIndex i = count; i < newCount; ++i )
1046             m_Rows[i] = new CHTML_tr_Cache;
1047         m_RowCount = newCount;
1048     }
1049     return *m_Rows[row];
1050 }
1051 
InitRow(TIndex row,CHTML_tr * rowNode)1052 void CHTML_table_Cache::InitRow(TIndex row, CHTML_tr* rowNode)
1053 {
1054     CHTML_tr_Cache& rowCache = GetRowCache(row);
1055     m_Rows[row]->SetRowNode(rowNode);
1056     m_FilledRowCount = row + 1;
1057 
1058     // Scan all children (which should be <TH> or <TD> tags)
1059     if ( rowNode->HaveChildren() ) {
1060         // Beginning with column 0
1061         TIndex col = 0;
1062         for ( CNCBINode::TChildren::iterator iCol = rowNode->ChildBegin(),
1063               iColEnd = rowNode->ChildEnd();
1064               iCol != iColEnd; ++iCol ) {
1065             CHTML_tc* cellNode =
1066                 dynamic_cast<CHTML_tc*>(rowNode->Node(iCol));
1067 
1068             if ( !cellNode ) {
1069                 continue;
1070             }
1071 
1072             // Skip all used cells
1073             while ( rowCache.GetCellCache(col).IsUsed() ) {
1074                 ++col;
1075             }
1076 
1077             // Determine current cell size
1078             TIndex rowSpan = x_GetSpan(cellNode, "rowspan");
1079             TIndex colSpan = x_GetSpan(cellNode, "colspan");
1080 
1081             // End of new cell in columns
1082             rowCache.SetUsedCells(cellNode, col, col + colSpan);
1083             if ( rowSpan > 1 ) {
1084                 SetUsedCells(row + 1, row + rowSpan, col, col + colSpan);
1085             }
1086 
1087             // Skip this cell's columns
1088             col += colSpan;
1089         }
1090     }
1091 }
1092 
CHTML_table_Cache(CHTML_table * table)1093 CHTML_table_Cache::CHTML_table_Cache(CHTML_table* table)
1094     : m_Node(table),
1095       m_RowCount(0), m_RowsSize(0), m_Rows(0), m_FilledRowCount(0)
1096 {
1097     // Scan all children (which should be <TR> tags)
1098     if ( table->HaveChildren() ) {
1099         // Beginning with row 0
1100         TIndex row = 0;
1101         for ( CNCBINode::TChildren::iterator iRow = table->ChildBegin(),
1102               iRowEnd = table->ChildEnd(); iRow != iRowEnd; ++iRow ) {
1103             CHTML_tr* rowNode = dynamic_cast<CHTML_tr*>(table->Node(iRow));
1104             if ( !rowNode ) {
1105                 continue;
1106             }
1107             InitRow(row, rowNode);
1108             ++row;
1109         }
1110     }
1111 }
1112 
GetRowNode(TIndex row)1113 CHTML_tr* CHTML_table_Cache::GetRowNode(TIndex row)
1114 {
1115     GetRowCache(row);
1116     while ( row >= m_FilledRowCount ) {
1117         CHTML_tr* rowNode = new CHTML_tr;
1118         m_Node->AppendRow(rowNode);
1119         m_Rows[m_FilledRowCount++]->SetRowNode(rowNode);
1120     }
1121     return m_Rows[row]->GetRowNode();
1122 }
1123 
SetUsedCells(TIndex rowBegin,TIndex rowEnd,TIndex colBegin,TIndex colEnd)1124 void CHTML_table_Cache::SetUsedCells(TIndex rowBegin, TIndex rowEnd,
1125                                      TIndex colBegin, TIndex colEnd)
1126 {
1127     for ( TIndex row = rowBegin; row < rowEnd; ++row ) {
1128         GetRowCache(row).SetUsedCells(colBegin, colEnd);
1129     }
1130 }
1131 
GetCellNode(TIndex row,TIndex col,CHTML_table::ECellType type)1132 CHTML_tc* CHTML_table_Cache::GetCellNode(TIndex row, TIndex col,
1133                                          CHTML_table::ECellType type)
1134 {
1135     CHTML_tr_Cache& rowCache = GetRowCache(row);
1136     if ( col < rowCache.GetCellCount() ) {
1137         CHTML_tc_Cache& cellCache = rowCache.GetCellCache(col);
1138         if ( cellCache.IsNode() ) {
1139             CHTML_tc* cell = cellCache.GetCellNode();
1140             switch ( type ) {
1141             case CHTML_table::eHeaderCell:
1142                 if ( !dynamic_cast<CHTML_th*>(cell) )
1143                     NCBI_THROW(CHTMLException, eTableCellType,
1144                                "wrong cell type: TH expected");
1145                 break;
1146             case CHTML_table::eDataCell:
1147                 if ( !dynamic_cast<CHTML_td*>(cell) )
1148                     NCBI_THROW(CHTMLException, eTableCellType,
1149                                "wrong cell type: TD expected");
1150                 break;
1151             default:
1152                 break;
1153             }
1154             return cell;
1155         }
1156         if ( cellCache.IsUsed() )
1157             NCBI_THROW(CHTMLException, eTableCellUse,
1158                        "invalid use of big table cell");
1159     }
1160     CHTML_tc* cell;
1161     if ( type == CHTML_table::eHeaderCell ) {
1162         cell = new CHTML_th;
1163     } else {
1164         cell = new CHTML_td;
1165     }
1166     rowCache.AppendCell(GetRowNode(row), col, cell, 1);
1167     return cell;
1168 }
1169 
GetCellNode(TIndex row,TIndex col,CHTML_table::ECellType type,TIndex rowSpan,TIndex colSpan)1170 CHTML_tc* CHTML_table_Cache::GetCellNode(TIndex row, TIndex col,
1171                                          CHTML_table::ECellType type,
1172                                          TIndex rowSpan, TIndex colSpan)
1173 {
1174     CHTML_tr_Cache& rowCache = GetRowCache(row);
1175     if ( col < rowCache.GetCellCount() ) {
1176         CHTML_tc_Cache& cellCache = rowCache.GetCellCache(col);
1177         if ( cellCache.IsNode() ) {
1178             CHTML_tc* cell = cellCache.GetCellNode();
1179             switch ( type ) {
1180             case CHTML_table::eHeaderCell:
1181                 if ( !dynamic_cast<CHTML_th*>(cell) )
1182                     NCBI_THROW(CHTMLException, eTableCellType,
1183                                "wrong cell type: TH expected");
1184                 break;
1185             case CHTML_table::eDataCell:
1186                 if ( !dynamic_cast<CHTML_td*>(cell) )
1187                     NCBI_THROW(CHTMLException, eTableCellType,
1188                                "wrong cell type: TD expected");
1189                 break;
1190             default:
1191                 break;
1192             }
1193             if ( x_GetSpan(cell, "rowspan") != rowSpan ||
1194                  x_GetSpan(cell, "colspan") != colSpan )
1195                 NCBI_THROW(CHTMLException, eTableCellUse,
1196                            "cannot change table cell size");
1197             return cell;
1198         }
1199         if ( cellCache.IsUsed() )
1200             NCBI_THROW(CHTMLException, eTableCellUse,
1201                        "invalid use of big table cell");
1202     }
1203 
1204     CHTML_tc* cell;
1205     if ( type == CHTML_table::eHeaderCell ) {
1206         cell = new CHTML_th;
1207     } else {
1208         cell = new CHTML_td;
1209     }
1210     if ( colSpan != 1 ) {
1211         cell->SetColSpan(colSpan);
1212     }
1213     if ( rowSpan != 1 ) {
1214         cell->SetRowSpan(rowSpan);
1215     }
1216     rowCache.AppendCell(GetRowNode(row), col, cell, colSpan);
1217     if ( rowSpan != 1 ) {
1218         SetUsedCells(row + 1, row + rowSpan, col, col + colSpan);
1219     }
1220     return cell;
1221 }
1222 
CHTML_table(void)1223 CHTML_table::CHTML_table(void)
1224     : CParent("table"),
1225       m_CurrentRow(TIndex(-1)), m_CurrentCol(TIndex(-1)),
1226       m_ColSepL(kEmptyStr), m_ColSepM(" "), m_ColSepR(kEmptyStr),
1227       m_RowSepChar('-'), m_IsRowSep(eSkipRowSep)
1228 {
1229     return;
1230 }
1231 
~CHTML_table(void)1232 CHTML_table::~CHTML_table(void)
1233 {
1234     return;
1235 }
1236 
GetCache(void) const1237 CHTML_table_Cache& CHTML_table::GetCache(void) const
1238 {
1239     CHTML_table_Cache* cache = m_Cache.get();
1240     if ( !cache ) {
1241         m_Cache.reset(cache =
1242                       new CHTML_table_Cache(const_cast<CHTML_table*>(this)));
1243     }
1244     return *cache;
1245 }
1246 
DoAppendChild(CNCBINode * node)1247 void CHTML_table::DoAppendChild(CNCBINode* node)
1248 {
1249     CHTML_tr* row = dynamic_cast<CHTML_tr*>(node);
1250     if ( row ) {
1251         // Adding new row
1252         _ASSERT(!row->m_Parent);
1253         ResetTableCache();
1254         row->m_Parent = this;
1255     }
1256     CParent::DoAppendChild(node);
1257 }
1258 
AppendRow(CHTML_tr * row)1259 void CHTML_table::AppendRow(CHTML_tr* row)
1260 {
1261     _ASSERT(!row->m_Parent);
1262     row->m_Parent = this;
1263     CParent::DoAppendChild(row);
1264 }
1265 
Row(TIndex row)1266 CHTML_tr* CHTML_table::Row(TIndex row)
1267 {
1268     return GetCache().GetRowNode(row);
1269 }
1270 
Cell(TIndex row,TIndex col,ECellType type)1271 CHTML_tc* CHTML_table::Cell(TIndex row, TIndex col, ECellType type)
1272 {
1273     m_CurrentRow = (row == TIndex(-1)) ? 0 : row;
1274     m_CurrentCol = (col == TIndex(-1)) ? 0 : col;
1275     return GetCache().GetCellNode(m_CurrentRow, m_CurrentCol, type);
1276 }
1277 
Cell(TIndex row,TIndex col,ECellType type,TIndex rowSpan,TIndex colSpan)1278 CHTML_tc* CHTML_table::Cell(TIndex row, TIndex col, ECellType type,
1279                             TIndex rowSpan, TIndex colSpan)
1280 {
1281     m_CurrentRow = (row == TIndex(-1)) ? 0 : row;
1282     m_CurrentCol = (col == TIndex(-1)) ? 0 : col;
1283     return GetCache().GetCellNode(m_CurrentRow, m_CurrentCol,
1284                                   type, rowSpan, colSpan);
1285 }
1286 
CheckTable(void) const1287 void CHTML_table::CheckTable(void) const
1288 {
1289     GetCache();
1290 }
1291 
CalculateNumberOfColumns(void) const1292 CHTML_table::TIndex CHTML_table::CalculateNumberOfColumns(void) const
1293 {
1294     CHTML_table_Cache& cache = GetCache();
1295     TIndex columns = 0;
1296     for ( TIndex i = 0; i < cache.GetRowCount(); ++i ) {
1297         columns = max(columns, cache.GetRowCache(i).GetCellCount());
1298     }
1299     return columns;
1300 }
1301 
CalculateNumberOfRows(void) const1302 CHTML_table::TIndex CHTML_table::CalculateNumberOfRows(void) const
1303 {
1304     return GetCache().GetRowCount();
1305 }
1306 
PrintBegin(CNcbiOstream & out,TMode mode)1307 CNcbiOstream& CHTML_table::PrintBegin(CNcbiOstream& out, TMode mode)
1308 {
1309     switch (mode) {
1310     case ePlainText:
1311         INIT_STREAM_WRITE;
1312         out << CHTMLHelper::GetNL();
1313         CHECK_STREAM_WRITE(out);
1314         if ( m_IsRowSep == ePrintRowSep ) {
1315             SIZE_TYPE seplen = 0;
1316             // Find length of first non-empty row
1317             NON_CONST_ITERATE ( TChildren, i, Children() ) {
1318                 if ( (seplen =
1319                       dynamic_cast<CHTML_tr*>(&**i)->GetTextLength(mode)) >0) {
1320                     break;
1321                 }
1322             }
1323             if ( !seplen ) {
1324                 seplen = 1;
1325             }
1326             INIT_STREAM_WRITE;
1327             out << string(seplen, m_RowSepChar) << CHTMLHelper::GetNL();
1328             CHECK_STREAM_WRITE(out);
1329         }
1330         break;
1331     case eHTML:
1332     case eXHTML:
1333         // Set column widths.
1334         if ( HaveChildren() ) {
1335             ITERATE ( TColWidths, w, m_ColWidths ) {
1336                 // Scan all children (which should be <TR> tags)
1337                 // Beginning with row 0
1338                 TIndex row = 0;
1339                 for ( CNCBINode::TChildren::iterator iRow = ChildBegin(),
1340                     iRowEnd = ChildEnd(); iRow != iRowEnd; ++iRow ) {
1341                     try {
1342                         CHTML_tc* cell = Cell(row, (TIndex)w->first);
1343                         if ( cell ) {
1344                         cell->SetWidth(w->second);
1345                         }
1346                     }
1347                     catch (CHTMLException&) {
1348                         // catch exception with messages about absent cells
1349                     }
1350                     ++row;
1351                 }
1352             }
1353         }
1354         break;
1355     }
1356     return CParent::PrintBegin(out, mode);
1357 }
1358 
SetPlainSeparators(const string & col_left,const string & col_middle,const string & col_right,const char row_sep_char,ERowPlainSep is_row_sep)1359 void CHTML_table::SetPlainSeparators(const string& col_left,
1360                                      const string& col_middle,
1361                                      const string& col_right,
1362                                      const char    row_sep_char,
1363                                      ERowPlainSep  is_row_sep)
1364 {
1365     m_ColSepL    = col_left;
1366     m_ColSepM    = col_middle;
1367     m_ColSepR    = col_right;
1368     m_RowSepChar = row_sep_char;
1369     m_IsRowSep   = is_row_sep;
1370 }
1371 
1372 
1373 // <form> tag.
1374 
CHTML_form(void)1375 CHTML_form::CHTML_form(void)
1376     : CParent("form")
1377 {
1378     return;
1379 }
1380 
CHTML_form(const string & url,EMethod method)1381 CHTML_form::CHTML_form(const string& url, EMethod method)
1382     : CParent("form")
1383 {
1384     Init(url, method);
1385 }
1386 
CHTML_form(const string & url,CNCBINode * node,EMethod method)1387 CHTML_form::CHTML_form(const string& url, CNCBINode* node, EMethod method)
1388     : CParent("form", node)
1389 {
1390     Init(url, method);
1391 }
1392 
~CHTML_form(void)1393 CHTML_form::~CHTML_form(void)
1394 {
1395     return;
1396 }
1397 
Init(const string & url,EMethod method)1398 void CHTML_form::Init(const string& url, EMethod method)
1399 {
1400     SetOptionalAttribute("action", url);
1401     switch ( method ) {
1402     case eGet:
1403         SetAttribute("method", "GET");
1404         break;
1405     case ePost:
1406         SetAttribute("enctype",
1407                      "application/x-www-form-urlencoded");
1408         SetAttribute("method", "POST");
1409         break;
1410     case ePostData:
1411         SetAttribute("enctype",
1412                      "multipart/form-data");
1413         SetAttribute("method", "POST");
1414         break;
1415     }
1416 }
1417 
AddHidden(const string & name,const string & value)1418 void CHTML_form::AddHidden(const string& name, const string& value)
1419 {
1420     AppendChild(new CHTML_hidden(name, value));
1421 }
1422 
AddHidden(const string & name,int value)1423 void CHTML_form::AddHidden(const string& name, int value)
1424 {
1425     AppendChild(new CHTML_hidden(name, value));
1426 }
1427 
1428 
1429 // <input> tag.
1430 
CHTML_input(const char * type,const string & name)1431 CHTML_input::CHTML_input(const char* type, const string& name)
1432     : CParent("input")
1433 {
1434     SetAttribute("type", type);
1435     if ( !name.empty() ) {
1436         SetNameAttribute(name);
1437     }
1438 }
1439 
~CHTML_input(void)1440 CHTML_input::~CHTML_input(void)
1441 {
1442     return;
1443 }
1444 
1445 
1446 // <legend> tag.
1447 
CHTML_legend(const string & legend)1448 CHTML_legend::CHTML_legend(const string& legend)
1449     : CParent("legend", legend)
1450 {
1451     return;
1452 }
1453 
CHTML_legend(CHTMLNode * legend)1454 CHTML_legend::CHTML_legend(CHTMLNode* legend)
1455     : CParent("legend", legend)
1456 {
1457     return;
1458 }
1459 
~CHTML_legend(void)1460 CHTML_legend::~CHTML_legend(void)
1461 {
1462     return;
1463 }
1464 
1465 // <fieldset> tag.
1466 
CHTML_fieldset(void)1467 CHTML_fieldset::CHTML_fieldset(void)
1468     : CParent("fieldset")
1469 {
1470     return;
1471 }
1472 
CHTML_fieldset(const string & legend)1473 CHTML_fieldset::CHTML_fieldset(const string& legend)
1474     : CParent("fieldset", new CHTML_legend(legend))
1475 {
1476     return;
1477 }
1478 
CHTML_fieldset(CHTML_legend * legend)1479 CHTML_fieldset::CHTML_fieldset(CHTML_legend* legend)
1480     : CParent("fieldset", legend)
1481 {
1482     return;
1483 }
1484 
~CHTML_fieldset(void)1485 CHTML_fieldset::~CHTML_fieldset(void)
1486 {
1487     return;
1488 }
1489 
1490 
1491 // <label> tag.
1492 
CHTML_label(const string & text)1493 CHTML_label::CHTML_label(const string& text)
1494     : CParent("label", text)
1495 {
1496     return;
1497 }
1498 
CHTML_label(const string & text,const string & idRef)1499 CHTML_label::CHTML_label(const string& text, const string& idRef)
1500     : CParent("label", text)
1501 {
1502     SetFor(idRef);
1503 }
1504 
~CHTML_label(void)1505 CHTML_label::~CHTML_label(void)
1506 {
1507     return;
1508 }
1509 
SetFor(const string & idRef)1510 void CHTML_label::SetFor(const string& idRef)
1511 {
1512     SetAttribute("for", idRef);
1513 }
1514 
1515 
1516 // <textarea> tag.
1517 
CHTML_textarea(const string & name,int cols,int rows)1518 CHTML_textarea::CHTML_textarea(const string& name, int cols, int rows)
1519     : CParent("textarea")
1520 {
1521     if ( !name.empty() ) {
1522         SetNameAttribute(name);
1523     }
1524     SetAttribute("cols", cols);
1525     SetAttribute("rows", rows);
1526 }
1527 
CHTML_textarea(const string & name,int cols,int rows,const string & value)1528 CHTML_textarea::CHTML_textarea(const string& name, int cols, int rows,
1529                                const string& value)
1530     : CParent("textarea", value)
1531 {
1532     SetNameAttribute(name);
1533     SetAttribute("cols", cols);
1534     SetAttribute("rows", rows);
1535 }
1536 
~CHTML_textarea(void)1537 CHTML_textarea::~CHTML_textarea(void)
1538 {
1539     return;
1540 }
1541 
1542 
1543 // <input type=checkbox> tag.
1544 
1545 const char CHTML_checkbox::sm_InputType[] = "checkbox";
1546 
CHTML_checkbox(const string & name)1547 CHTML_checkbox::CHTML_checkbox(const string& name)
1548     : CParent(sm_InputType, name)
1549 {
1550     return;
1551 }
1552 
CHTML_checkbox(const string & name,const string & value)1553 CHTML_checkbox::CHTML_checkbox(const string& name, const string& value)
1554     : CParent(sm_InputType, name)
1555 {
1556     SetOptionalAttribute("value", value);
1557 }
1558 
CHTML_checkbox(const string & name,bool checked,const string & description)1559 CHTML_checkbox::CHTML_checkbox(const string& name, bool checked,
1560                                const string& description)
1561     : CParent(sm_InputType, name)
1562 {
1563     SetOptionalAttribute("checked", checked);
1564     // Add the description at the end
1565     AppendPlainText(description);
1566 }
1567 
CHTML_checkbox(const string & name,const string & value,bool checked,const string & description)1568 CHTML_checkbox::CHTML_checkbox(const string& name, const string& value,
1569                                bool checked, const string& description)
1570     : CParent(sm_InputType, name)
1571 {
1572     SetOptionalAttribute("value", value);
1573     SetOptionalAttribute("checked", checked);
1574     // Add the description at the end
1575     AppendPlainText(description);
1576 }
1577 
~CHTML_checkbox(void)1578 CHTML_checkbox::~CHTML_checkbox(void)
1579 {
1580     return;
1581 }
1582 
1583 
1584 // <input type=image> tag.
1585 
1586 const char CHTML_image::sm_InputType[] = "image";
1587 
CHTML_image(const string & name,const string & src,const string & alt)1588 CHTML_image::CHTML_image(const string& name, const string& src,
1589                          const string& alt)
1590     : CParent(sm_InputType, name)
1591 {
1592     SetAttribute("src", src);
1593     SetOptionalAttribute("alt", alt);
1594 }
1595 
CHTML_image(const string & name,const string & src,int border,const string & alt)1596 CHTML_image::CHTML_image(const string& name, const string& src, int border,
1597                          const string& alt)
1598     : CParent(sm_InputType, name)
1599 {
1600     SetAttribute("src", src);
1601     SetAttribute("border", border);
1602     SetOptionalAttribute("alt", alt);
1603 }
1604 
~CHTML_image(void)1605 CHTML_image::~CHTML_image(void)
1606 {
1607     return;
1608 }
1609 
1610 
1611 // <input type=radio> tag.
1612 
1613 const char CHTML_radio::sm_InputType[] = "radio";
1614 
CHTML_radio(const string & name,const string & value)1615 CHTML_radio::CHTML_radio(const string& name, const string& value)
1616     : CParent(sm_InputType, name)
1617 {
1618     SetAttribute("value", value);
1619 }
1620 
CHTML_radio(const string & name,const string & value,bool checked,const string & description)1621 CHTML_radio::CHTML_radio(const string& name, const string& value,
1622                          bool checked, const string& description)
1623     : CParent(sm_InputType, name)
1624 {
1625     SetAttribute("value", value);
1626     SetOptionalAttribute("checked", checked);
1627     AppendPlainText(description);  // adds the description at the end
1628 }
1629 
~CHTML_radio(void)1630 CHTML_radio::~CHTML_radio(void)
1631 {
1632     return;
1633 }
1634 
1635 
1636 // <input type=hidden> tag.
1637 
1638 const char CHTML_hidden::sm_InputType[] = "hidden";
1639 
CHTML_hidden(const string & name,const string & value)1640 CHTML_hidden::CHTML_hidden(const string& name, const string& value)
1641     : CParent(sm_InputType, name)
1642 {
1643     SetAttribute("value", value);
1644 }
1645 
CHTML_hidden(const string & name,int value)1646 CHTML_hidden::CHTML_hidden(const string& name, int value)
1647     : CParent(sm_InputType, name)
1648 {
1649     SetAttribute("value", value);
1650 }
1651 
~CHTML_hidden(void)1652 CHTML_hidden::~CHTML_hidden(void)
1653 {
1654     return;
1655 }
1656 
1657 
1658 // <input type=password> tag.
1659 
1660 const char CHTML_password::sm_InputType[] = "password";
1661 
CHTML_password(const string & name,const string & value)1662 CHTML_password::CHTML_password(const string& name, const string& value)
1663     : CParent(sm_InputType, name)
1664 {
1665     SetOptionalAttribute("value", value);
1666 }
1667 
CHTML_password(const string & name,int size,const string & value)1668 CHTML_password::CHTML_password(const string& name, int size,
1669                                const string& value)
1670     : CParent(sm_InputType, name)
1671 {
1672     SetSize(size);
1673     SetOptionalAttribute("value", value);
1674 }
1675 
CHTML_password(const string & name,int size,int maxlength,const string & value)1676 CHTML_password::CHTML_password(const string& name, int size, int maxlength,
1677                            const string& value)
1678     : CParent(sm_InputType, name)
1679 {
1680     SetSize(size);
1681     SetAttribute("maxlength", maxlength);
1682     SetOptionalAttribute("value", value);
1683 }
1684 
~CHTML_password(void)1685 CHTML_password::~CHTML_password(void)
1686 {
1687     return;
1688 }
1689 
1690 
1691 // <input type=submit> tag.
1692 
1693 const char CHTML_submit::sm_InputType[] = "submit";
1694 
CHTML_submit(const string & label)1695 CHTML_submit::CHTML_submit(const string& label)
1696     : CParent(sm_InputType, NcbiEmptyString)
1697 {
1698     SetOptionalAttribute("value", label);
1699 }
1700 
CHTML_submit(const string & name,const string & label)1701 CHTML_submit::CHTML_submit(const string& name, const string& label)
1702     : CParent(sm_InputType, name)
1703 {
1704     SetOptionalAttribute("value", label);
1705 }
1706 
~CHTML_submit(void)1707 CHTML_submit::~CHTML_submit(void)
1708 {
1709     return;
1710 }
1711 
1712 
1713 // <input type=reset> tag.
1714 
1715 const char CHTML_reset::sm_InputType[] = "reset";
1716 
CHTML_reset(const string & label)1717 CHTML_reset::CHTML_reset(const string& label)
1718     : CParent(sm_InputType, NcbiEmptyString)
1719 {
1720     SetOptionalAttribute("value", label);
1721 }
1722 
~CHTML_reset(void)1723 CHTML_reset::~CHTML_reset(void)
1724 {
1725     return;
1726 }
1727 
1728 
1729 // <input type=button> tag
1730 
1731 const char CHTML_input_button::sm_InputType[] = "button";
1732 
CHTML_input_button(const string & label)1733 CHTML_input_button::CHTML_input_button(const string& label)
1734     : CParent(sm_InputType, NcbiEmptyString)
1735 {
1736     SetOptionalAttribute("value", label);
1737 }
1738 
CHTML_input_button(const string & name,const string & label)1739 CHTML_input_button::CHTML_input_button(const string& name, const string& label)
1740     : CParent(sm_InputType, name)
1741 {
1742     SetOptionalAttribute("value", label);
1743 }
1744 
~CHTML_input_button(void)1745 CHTML_input_button::~CHTML_input_button(void)
1746 {
1747     return;
1748 }
1749 
1750 
1751 // <input type=text> tag.
1752 
1753 const char CHTML_text::sm_InputType[] = "text";
1754 
CHTML_text(const string & name,const string & value)1755 CHTML_text::CHTML_text(const string& name, const string& value)
1756     : CParent(sm_InputType, name)
1757 {
1758     SetOptionalAttribute("value", value);
1759 }
1760 
CHTML_text(const string & name,int size,const string & value)1761 CHTML_text::CHTML_text(const string& name, int size, const string& value)
1762     : CParent(sm_InputType, name)
1763 {
1764     SetSize(size);
1765     SetOptionalAttribute("value", value);
1766 }
1767 
CHTML_text(const string & name,int size,int maxlength,const string & value)1768 CHTML_text::CHTML_text(const string& name, int size, int maxlength,
1769                        const string& value)
1770     : CParent(sm_InputType, name)
1771 {
1772     SetSize(size);
1773     SetAttribute("maxlength", maxlength);
1774     SetOptionalAttribute("value", value);
1775 }
1776 
~CHTML_text(void)1777 CHTML_text::~CHTML_text(void)
1778 {
1779     return;
1780 }
1781 
1782 
1783 // <input type=file> tag.
1784 
1785 const char CHTML_file::sm_InputType[] = "file";
1786 
CHTML_file(const string & name,const string & value)1787 CHTML_file::CHTML_file(const string& name, const string& value)
1788     : CParent(sm_InputType, name)
1789 {
1790     SetOptionalAttribute("value", value);
1791 }
1792 
~CHTML_file(void)1793 CHTML_file::~CHTML_file(void)
1794 {
1795     return;
1796 }
1797 
1798 
1799 // <button> tag
1800 
1801 const char CHTML_button::sm_TagName[] = "button";
1802 
CHTML_button(const string & text,EButtonType type,const string & name,const string & value)1803 CHTML_button::CHTML_button(const string& text, EButtonType type,
1804                            const string& name, const string& value)
1805     : CParent(sm_TagName, text)
1806 {
1807     SetType(type);
1808     SetSubmitData(name, value);
1809 }
1810 
CHTML_button(CNCBINode * contents,EButtonType type,const string & name,const string & value)1811 CHTML_button::CHTML_button(CNCBINode* contents, EButtonType type,
1812                            const string& name, const string& value)
1813     : CParent(sm_TagName, contents)
1814 {
1815     SetType(type);
1816     SetSubmitData(name, value);
1817 }
1818 
SetType(EButtonType type)1819 CHTML_button* CHTML_button::SetType(EButtonType type)
1820 {
1821     switch ( type ) {
1822         case eSubmit:
1823             SetAttribute("type", "submit");
1824             break;
1825         case eReset:
1826             SetAttribute("type", "reset");
1827             break;
1828         case eButton:
1829             SetAttribute("type", "button");
1830             break;
1831     }
1832     return this;
1833 }
1834 
SetSubmitData(const string & name,const string & value)1835 CHTML_button* CHTML_button::SetSubmitData(const string& name,
1836                                           const string& value)
1837 {
1838     SetOptionalAttribute("name", name);
1839     SetOptionalAttribute("value", value);
1840     return this;
1841 }
1842 
~CHTML_button(void)1843 CHTML_button::~CHTML_button(void)
1844 {
1845     return;
1846 }
1847 
1848 
1849 // <select> tag.
1850 
1851 const char CHTML_select::sm_TagName[] = "select";
1852 
~CHTML_select(void)1853 CHTML_select::~CHTML_select(void)
1854 {
1855     return;
1856 }
1857 
1858 
1859 // <optgroup> tag.
1860 
1861 const char CHTML_optgroup::sm_TagName[] = "optgroup";
1862 
~CHTML_optgroup(void)1863 CHTML_optgroup::~CHTML_optgroup(void)
1864 {
1865     return;
1866 }
1867 
1868 
1869 // <option> tag.
1870 
1871 const char CHTML_option::sm_TagName[] = "option";
1872 
~CHTML_option(void)1873 CHTML_option::~CHTML_option(void)
1874 {
1875     return;
1876 }
1877 
1878 
1879 // <a> tag.
1880 
1881 const char CHTML_a::sm_TagName[] = "a";
1882 
~CHTML_a(void)1883 CHTML_a::~CHTML_a(void)
1884 {
1885     return;
1886 }
1887 
1888 
1889 // <br> tag.
1890 
1891 const char CHTML_br::sm_TagName[] = "br";
1892 
CHTML_br(int count)1893 CHTML_br::CHTML_br(int count)
1894     : CParent(sm_TagName)
1895 {
1896     for ( int i = 1; i < count; ++i ) {
1897         AppendChild(new CHTML_br());
1898     }
1899 }
1900 
~CHTML_br(void)1901 CHTML_br::~CHTML_br(void)
1902 {
1903     return;
1904 }
1905 
PrintBegin(CNcbiOstream & out,TMode mode)1906 CNcbiOstream& CHTML_br::PrintBegin(CNcbiOstream& out, TMode mode)
1907 {
1908     switch (mode) {
1909         case ePlainText:
1910             INIT_STREAM_WRITE;
1911             out << CHTMLHelper::GetNL();
1912             CHECK_STREAM_WRITE(out);
1913             break;
1914         case eHTML:
1915         case eXHTML:
1916             CParent::PrintBegin(out, mode);
1917             break;
1918     }
1919     return out;
1920 }
1921 
1922 
1923 // <img> tag.
1924 
CHTML_img(const string & url,const string & alt)1925 CHTML_img::CHTML_img(const string& url, const string& alt)
1926     : CParent("img")
1927 {
1928     SetAttribute("src", url);
1929     SetOptionalAttribute("alt", alt);
1930 }
1931 
CHTML_img(const string & url,int width,int height,const string & alt)1932 CHTML_img::CHTML_img(const string& url, int width, int height,
1933                      const string& alt)
1934     : CParent("img")
1935 {
1936     SetAttribute("src", url);
1937     SetOptionalAttribute("alt", alt);
1938     SetWidth(width);
1939     SetHeight(height);
1940 }
1941 
~CHTML_img(void)1942 CHTML_img::~CHTML_img(void)
1943 {
1944     return;
1945 }
1946 
UseMap(const string & mapname)1947 void CHTML_img::UseMap(const string& mapname)
1948 {
1949     if ( mapname.find("#") == NPOS ) {
1950         SetAttribute("usemap", "#" + mapname);
1951     } else {
1952         SetAttribute("usemap", mapname);
1953     }
1954 }
1955 
UseMap(const CHTML_map * const mapnode)1956 void CHTML_img::UseMap(const CHTML_map* const mapnode)
1957 {
1958     UseMap(mapnode->GetNameAttribute());
1959 }
1960 
1961 
1962 
1963 // <map> tag.
1964 
CHTML_map(const string & name)1965 CHTML_map::CHTML_map(const string& name)
1966     : CParent("map")
1967 {
1968     SetNameAttribute(name);
1969 }
1970 
~CHTML_map(void)1971 CHTML_map::~CHTML_map(void)
1972 {
1973     return;
1974 }
1975 
1976 
1977 // <area> tag.
1978 
1979 const char CHTML_area::sm_TagName[] = "area";
1980 
~CHTML_area(void)1981 CHTML_area::~CHTML_area(void)
1982 {
1983     return;
1984 }
1985 
DefineRect(int x1,int y1,int x2,int y2)1986 CHTML_area* CHTML_area::DefineRect(int x1, int y1, int x2, int y2)
1987 {
1988     vector<string> c;
1989     c.push_back(NStr::IntToString(x1));
1990     c.push_back(NStr::IntToString(y1));
1991     c.push_back(NStr::IntToString(x2));
1992     c.push_back(NStr::IntToString(y2));
1993     SetAttribute("shape", "rect");
1994     SetAttribute("coords", NStr::Join(c, ","));
1995     return this;
1996 }
1997 
DefineCircle(int x,int y,int radius)1998 CHTML_area* CHTML_area::DefineCircle(int x, int y, int radius)
1999 {
2000     vector<string> c;
2001     c.push_back(NStr::IntToString(x));
2002     c.push_back(NStr::IntToString(y));
2003     c.push_back(NStr::IntToString(radius));
2004     SetAttribute("shape", "circle");
2005     SetAttribute("coords", NStr::Join(c, ","));
2006     return this;
2007 }
2008 
DefinePolygon(int coords[],int count)2009 CHTML_area* CHTML_area::DefinePolygon(int coords[], int count)
2010 {
2011     string c;
2012     for(int i = 0; i<count; i++) {
2013         if ( i ) {
2014             c += ",";
2015         }
2016         c += NStr::IntToString(coords[i]);
2017     }
2018     SetAttribute("shape", "poly");
2019     SetAttribute("coords", c);
2020     return this;
2021 }
2022 
DefinePolygon(vector<int> coords)2023 CHTML_area* CHTML_area::DefinePolygon(vector<int> coords)
2024 {
2025     string c;
2026     ITERATE(vector<int>, it, coords) {
2027         if ( it != coords.begin() ) {
2028             c += ",";
2029         }
2030         c += NStr::IntToString(*it);
2031     }
2032     SetAttribute("shape", "poly");
2033     SetAttribute("coords", c);
2034     return this;
2035 }
2036 
DefinePolygon(list<int> coords)2037 CHTML_area* CHTML_area::DefinePolygon(list<int> coords)
2038 {
2039     string c;
2040     ITERATE(list<int>, it, coords) {
2041         if ( it != coords.begin() ) {
2042             c += ",";
2043         }
2044         c += NStr::IntToString(*it);
2045     }
2046     SetAttribute("shape", "poly");
2047     SetAttribute("coords", c);
2048     return this;
2049 }
2050 
2051 
2052 // <dl> tag.
2053 
2054 const char CHTML_dl::sm_TagName[] = "dl";
2055 
~CHTML_dl(void)2056 CHTML_dl::~CHTML_dl(void)
2057 {
2058     return;
2059 }
2060 
AppendTerm(const string & term,const string & definition)2061 CHTML_dl* CHTML_dl::AppendTerm(const string& term, const string& definition)
2062 {
2063     AppendChild(new CHTML_dt(term));
2064     if ( !definition.empty() )
2065         AppendChild(new CHTML_dd(definition));
2066     return this;
2067 }
2068 
AppendTerm(const string & term,CNCBINode * definition)2069 CHTML_dl* CHTML_dl::AppendTerm(const string& term, CNCBINode* definition)
2070 {
2071     AppendChild(new CHTML_dt(term));
2072     if ( definition )
2073         AppendChild(new CHTML_dd(definition));
2074     return this;
2075 }
2076 
AppendTerm(CNCBINode * term,const string & definition)2077 CHTML_dl* CHTML_dl::AppendTerm(CNCBINode* term, const string& definition)
2078 {
2079     AppendChild(new CHTML_dt(term));
2080     if ( !definition.empty() ) {
2081         AppendChild(new CHTML_dd(definition));
2082     }
2083     return this;
2084 }
2085 
AppendTerm(CNCBINode * term,CNCBINode * definition)2086 CHTML_dl* CHTML_dl::AppendTerm(CNCBINode* term, CNCBINode* definition)
2087 {
2088     AppendChild(new CHTML_dt(term));
2089     if ( definition )
2090         AppendChild(new CHTML_dd(definition));
2091     return this;
2092 }
2093 
SetCompact(void)2094 CHTML_dl* CHTML_dl::SetCompact(void)
2095 {
2096     SetAttribute("compact");
2097     return this;
2098 }
2099 
2100 
2101 // <ol> tag.
2102 
2103 const char CHTML_ol::sm_TagName[] = "ol";
2104 
~CHTML_ol(void)2105 CHTML_ol::~CHTML_ol(void)
2106 {
2107 }
2108 
SetStart(int start)2109 CHTML_ol* CHTML_ol::SetStart(int start)
2110 {
2111     SetAttribute("start", start);
2112     return this;
2113 }
2114 
2115 
2116 // <ul> tag.
2117 
2118 const char CHTML_ul::sm_TagName[] = "ul";
2119 
~CHTML_ul(void)2120 CHTML_ul::~CHTML_ul(void)
2121 {
2122     return;
2123 }
2124 
2125 
2126 // <dir> tag.
2127 
2128 const char CHTML_dir::sm_TagName[] = "dir";
2129 
~CHTML_dir(void)2130 CHTML_dir::~CHTML_dir(void)
2131 {
2132     return;
2133 }
2134 
2135 
2136 // <menu> tag.
2137 
2138 const char CHTML_menu::sm_TagName[] = "menu";
2139 
~CHTML_menu(void)2140 CHTML_menu::~CHTML_menu(void)
2141 {
2142     return;
2143 }
2144 
2145 const char CHTML_font::sm_TagName[] = "font";
2146 
~CHTML_font(void)2147 CHTML_font::~CHTML_font(void)
2148 {
2149     return;
2150 }
2151 
2152 
2153 // <font> tag.
2154 
SetTypeFace(const string & typeface)2155 CHTML_font* CHTML_font::SetTypeFace(const string& typeface)
2156 {
2157     SetAttribute("face", typeface);
2158     return this;
2159 }
2160 
SetRelativeSize(int size)2161 CHTML_font* CHTML_font::SetRelativeSize(int size)
2162 {
2163     if ( size != 0 )
2164         SetAttribute("size", NStr::IntToString(size, NStr::fWithSign));
2165     return this;
2166 }
2167 
2168 const char CHTML_basefont::sm_TagName[] = "basefont";
2169 
~CHTML_basefont(void)2170 CHTML_basefont::~CHTML_basefont(void)
2171 {
2172     return;
2173 }
2174 
SetTypeFace(const string & typeface)2175 CHTML_basefont* CHTML_basefont::SetTypeFace(const string& typeface)
2176 {
2177     SetAttribute("typeface", typeface);
2178     return this;
2179 }
2180 
~CHTML_color(void)2181 CHTML_color::~CHTML_color(void)
2182 {
2183     return;
2184 }
2185 
2186 
2187 // <hr> tag.
2188 
2189 const char CHTML_hr::sm_TagName[] = "hr";
2190 
~CHTML_hr(void)2191 CHTML_hr::~CHTML_hr(void)
2192 {
2193     return;
2194 }
2195 
SetNoShade(void)2196 CHTML_hr* CHTML_hr::SetNoShade(void)
2197 {
2198     SetAttribute("noshade");
2199     return this;
2200 }
2201 
PrintBegin(CNcbiOstream & out,TMode mode)2202 CNcbiOstream& CHTML_hr::PrintBegin(CNcbiOstream& out, TMode mode)
2203 {
2204     switch (mode) {
2205         case ePlainText:
2206             INIT_STREAM_WRITE;
2207             out << CHTMLHelper::GetNL() << CHTMLHelper::GetNL();
2208             CHECK_STREAM_WRITE(out);
2209             break;
2210         case eHTML:
2211         case eXHTML:
2212             CParent::PrintBegin(out, mode);
2213             break;
2214     }
2215     return out;
2216 }
2217 
2218 
2219 // <meta> tag.
2220 
2221 const char CHTML_meta::sm_TagName[] = "meta";
2222 
CHTML_meta(EType mtype,const string & var,const string & content)2223 CHTML_meta::CHTML_meta(EType mtype, const string& var, const string& content)
2224     : CParent(sm_TagName)
2225 {
2226     SetAttribute(( mtype == eName ) ? "name" : "http-equiv", var);
2227     SetAttribute("content", content);
2228 }
2229 
2230 
~CHTML_meta(void)2231 CHTML_meta::~CHTML_meta(void)
2232 {
2233     return;
2234 }
2235 
2236 
2237 // <script> tag.
2238 
2239 const char CHTML_script::sm_TagName[] = "script";
2240 
CHTML_script(const string & stype)2241 CHTML_script::CHTML_script(const string& stype)
2242     : CParent(sm_TagName)
2243 {
2244     SetAttribute("type", stype);
2245 }
2246 
2247 
CHTML_script(const string & stype,const string & url)2248 CHTML_script::CHTML_script(const string& stype, const string& url)
2249     : CParent(sm_TagName)
2250 {
2251     SetAttribute("type", stype);
2252     SetAttribute("src", url);
2253 }
2254 
2255 
~CHTML_script(void)2256 CHTML_script::~CHTML_script(void)
2257 {
2258     return;
2259 }
2260 
AppendScript(const string & script)2261 CHTML_script* CHTML_script::AppendScript(const string& script)
2262 {
2263     const string& nl = CHTMLHelper::GetNL();
2264     AppendChild(
2265         new CHTMLPlainText(nl + "<!--" + nl + script + "-->" + nl, true));
2266     return this;
2267 }
2268 
2269 
2270 // Other tags.
2271 
2272 #define DEFINE_HTML_ELEMENT(Tag) \
2273 CHTML_NAME(Tag)::~CHTML_NAME(Tag)(void) \
2274 { \
2275 } \
2276 const char CHTML_NAME(Tag)::sm_TagName[] = #Tag
2277 
2278 
2279 DEFINE_HTML_ELEMENT(head);
2280 DEFINE_HTML_ELEMENT(body);
2281 DEFINE_HTML_ELEMENT(base);
2282 DEFINE_HTML_ELEMENT(isindex);
2283 DEFINE_HTML_ELEMENT(link);
2284 DEFINE_HTML_ELEMENT(noscript);
2285 DEFINE_HTML_ELEMENT(object);
2286 DEFINE_HTML_ELEMENT(style);
2287 DEFINE_HTML_ELEMENT(title);
2288 DEFINE_HTML_ELEMENT(address);
2289 DEFINE_HTML_ELEMENT(blockquote);
2290 DEFINE_HTML_ELEMENT(center);
2291 DEFINE_HTML_ELEMENT(div);
2292 DEFINE_HTML_ELEMENT(h1);
2293 DEFINE_HTML_ELEMENT(h2);
2294 DEFINE_HTML_ELEMENT(h3);
2295 DEFINE_HTML_ELEMENT(h4);
2296 DEFINE_HTML_ELEMENT(h5);
2297 DEFINE_HTML_ELEMENT(h6);
2298 DEFINE_HTML_ELEMENT(p);
2299 DEFINE_HTML_ELEMENT(pre);
2300 DEFINE_HTML_ELEMENT(dt);
2301 DEFINE_HTML_ELEMENT(dd);
2302 DEFINE_HTML_ELEMENT(li);
2303 DEFINE_HTML_ELEMENT(caption);
2304 DEFINE_HTML_ELEMENT(col);
2305 DEFINE_HTML_ELEMENT(colgroup);
2306 DEFINE_HTML_ELEMENT(thead);
2307 DEFINE_HTML_ELEMENT(tbody);
2308 DEFINE_HTML_ELEMENT(tfoot);
2309 DEFINE_HTML_ELEMENT(th);
2310 DEFINE_HTML_ELEMENT(td);
2311 DEFINE_HTML_ELEMENT(applet);
2312 DEFINE_HTML_ELEMENT(param);
2313 DEFINE_HTML_ELEMENT(cite);
2314 DEFINE_HTML_ELEMENT(code);
2315 DEFINE_HTML_ELEMENT(dfn);
2316 DEFINE_HTML_ELEMENT(em);
2317 DEFINE_HTML_ELEMENT(kbd);
2318 DEFINE_HTML_ELEMENT(samp);
2319 DEFINE_HTML_ELEMENT(strike);
2320 DEFINE_HTML_ELEMENT(strong);
2321 DEFINE_HTML_ELEMENT(var);
2322 DEFINE_HTML_ELEMENT(b);
2323 DEFINE_HTML_ELEMENT(big);
2324 DEFINE_HTML_ELEMENT(i);
2325 DEFINE_HTML_ELEMENT(s);
2326 DEFINE_HTML_ELEMENT(small);
2327 DEFINE_HTML_ELEMENT(sub);
2328 DEFINE_HTML_ELEMENT(sup);
2329 DEFINE_HTML_ELEMENT(tt);
2330 DEFINE_HTML_ELEMENT(u);
2331 DEFINE_HTML_ELEMENT(blink);
2332 DEFINE_HTML_ELEMENT(span);
2333 
2334 
2335 END_NCBI_SCOPE
2336