home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / html / htmltag.cpp < prev    next >
C/C++ Source or Header  |  2002-11-09  |  13KB  |  451 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        htmltag.cpp
  3. // Purpose:     wxHtmlTag class (represents single tag)
  4. // Author:      Vaclav Slavik
  5. // RCS-ID:      $Id: htmltag.cpp,v 1.30.2.1 2002/11/04 22:46:22 VZ Exp $
  6. // Copyright:   (c) 1999 Vaclav Slavik
  7. // Licence:     wxWindows Licence
  8. /////////////////////////////////////////////////////////////////////////////
  9.  
  10.  
  11. #ifdef __GNUG__
  12. #pragma implementation "htmltag.h"
  13. #endif
  14.  
  15. #include "wx/wxprec.h"
  16.  
  17. #include "wx/defs.h"
  18. #if wxUSE_HTML
  19.  
  20. #ifdef __BORLANDC__
  21. #pragma hdrstop
  22. #endif
  23.  
  24. #ifndef WXPRECOMP
  25. #endif
  26.  
  27. #include "wx/html/htmltag.h"
  28. #include "wx/html/htmlpars.h"
  29. #include "wx/colour.h"
  30. #include <stdio.h> // for vsscanf
  31. #include <stdarg.h>
  32.  
  33.  
  34. //-----------------------------------------------------------------------------
  35. // wxHtmlTagsCache
  36. //-----------------------------------------------------------------------------
  37.  
  38. struct wxHtmlCacheItem
  39. {
  40.     // this is "pos" value passed to wxHtmlTag's constructor.
  41.     // it is position of '<' character of the tag
  42.     int Key;
  43.  
  44.     // end positions for the tag:
  45.     // end1 is '<' of ending tag,
  46.     // end2 is '>' or both are
  47.     // -1 if there is no ending tag for this one...
  48.     // or -2 if this is ending tag  </...>
  49.     int End1, End2;
  50.  
  51.     // name of this tag
  52.     wxChar *Name;
  53. };
  54.  
  55.  
  56. IMPLEMENT_CLASS(wxHtmlTagsCache,wxObject)
  57.  
  58. #define CACHE_INCREMENT  64
  59.  
  60. wxHtmlTagsCache::wxHtmlTagsCache(const wxString& source)
  61. {
  62.     const wxChar *src = source.c_str();
  63.     int tg, stpos;
  64.     int lng = source.Length();
  65.     wxChar tagBuffer[256];
  66.  
  67.     m_Cache = NULL;
  68.     m_CacheSize = 0;
  69.     m_CachePos = 0;
  70.  
  71.     int pos = 0;
  72.     while (pos < lng)
  73.     {
  74.         if (src[pos] == wxT('<'))   // tag found:
  75.         {
  76.             if (m_CacheSize % CACHE_INCREMENT == 0)
  77.                 m_Cache = (wxHtmlCacheItem*) realloc(m_Cache, (m_CacheSize + CACHE_INCREMENT) * sizeof(wxHtmlCacheItem));
  78.             tg = m_CacheSize++;
  79.             m_Cache[tg].Key = stpos = pos++;
  80.  
  81.             int i;
  82.             for ( i = 0;
  83.                   pos < lng && i < (int)WXSIZEOF(tagBuffer) - 1 &&
  84.                   src[pos] != wxT('>') && !wxIsspace(src[pos]);
  85.                   i++, pos++ )
  86.             {
  87.                 tagBuffer[i] = wxToupper(src[pos]);
  88.             }
  89.             tagBuffer[i] = _T('\0');
  90.  
  91.             m_Cache[tg].Name = new wxChar[i+1];
  92.             memcpy(m_Cache[tg].Name, tagBuffer, (i+1)*sizeof(wxChar));
  93.  
  94.             while (pos < lng && src[pos] != wxT('>')) pos++;
  95.  
  96.             if (src[stpos+1] == wxT('/')) // ending tag:
  97.             {
  98.                 m_Cache[tg].End1 = m_Cache[tg].End2 = -2;
  99.                 // find matching begin tag:
  100.                 for (i = tg; i >= 0; i--)
  101.                     if ((m_Cache[i].End1 == -1) && (wxStrcmp(m_Cache[i].Name, tagBuffer+1) == 0))
  102.                     {
  103.                         m_Cache[i].End1 = stpos;
  104.                         m_Cache[i].End2 = pos + 1;
  105.                         break;
  106.                     }
  107.             }
  108.             else
  109.             {
  110.                 m_Cache[tg].End1 = m_Cache[tg].End2 = -1;
  111.             }
  112.         }
  113.  
  114.         pos++;
  115.     }
  116.  
  117.     // ok, we're done, now we'll free .Name members of cache - we don't need it anymore:
  118.     for (int i = 0; i < m_CacheSize; i++)
  119.     {
  120.         delete[] m_Cache[i].Name;
  121.         m_Cache[i].Name = NULL;
  122.     }
  123. }
  124.  
  125. void wxHtmlTagsCache::QueryTag(int at, int* end1, int* end2)
  126. {
  127.     if (m_Cache == NULL) return;
  128.     if (m_Cache[m_CachePos].Key != at)
  129.     {
  130.         int delta = (at < m_Cache[m_CachePos].Key) ? -1 : 1;
  131.         do
  132.         {
  133.             m_CachePos += delta;
  134.         }
  135.         while (m_Cache[m_CachePos].Key != at);
  136.     }
  137.     *end1 = m_Cache[m_CachePos].End1;
  138.     *end2 = m_Cache[m_CachePos].End2;
  139. }
  140.  
  141.  
  142.  
  143.  
  144. //-----------------------------------------------------------------------------
  145. // wxHtmlTag
  146. //-----------------------------------------------------------------------------
  147.  
  148. IMPLEMENT_CLASS(wxHtmlTag,wxObject)
  149.  
  150. wxHtmlTag::wxHtmlTag(wxHtmlTag *parent,
  151.                      const wxString& source, int pos, int end_pos,
  152.                      wxHtmlTagsCache *cache,
  153.                      wxHtmlEntitiesParser *entParser) : wxObject()
  154. {
  155.     /* Setup DOM relations */
  156.  
  157.     m_Next = NULL;
  158.     m_FirstChild = m_LastChild = NULL;
  159.     m_Parent = parent;
  160.     if (parent)
  161.     {
  162.         m_Prev = m_Parent->m_LastChild;
  163.         if (m_Prev == NULL)
  164.             m_Parent->m_FirstChild = this;
  165.         else
  166.             m_Prev->m_Next = this;
  167.         m_Parent->m_LastChild = this;
  168.     }
  169.     else
  170.         m_Prev = NULL;
  171.  
  172.     /* Find parameters and their values: */
  173.  
  174.     int i;
  175.     wxChar c;
  176.  
  177.     // fill-in name, params and begin pos:
  178.     i = pos+1;
  179.  
  180.     // find tag's name and convert it to uppercase:
  181.     while ((i < end_pos) &&
  182.            ((c = source[i++]) != wxT(' ') && c != wxT('\r') &&
  183.              c != wxT('\n') && c != wxT('\t') &&
  184.              c != wxT('>')))
  185.     {
  186.         if ((c >= wxT('a')) && (c <= wxT('z')))
  187.             c -= (wxT('a') - wxT('A'));
  188.         m_Name << c;
  189.     }
  190.  
  191.     // if the tag has parameters, read them and "normalize" them,
  192.     // i.e. convert to uppercase, replace whitespaces by spaces and
  193.     // remove whitespaces around '=':
  194.     if (source[i-1] != wxT('>'))
  195.     {
  196.         #define IS_WHITE(c) (c == wxT(' ') || c == wxT('\r') || \
  197.                              c == wxT('\n') || c == wxT('\t'))
  198.         wxString pname, pvalue;
  199.         wxChar quote;
  200.         enum
  201.         {
  202.             ST_BEFORE_NAME = 1,
  203.             ST_NAME,
  204.             ST_BEFORE_EQ,
  205.             ST_BEFORE_VALUE,
  206.             ST_VALUE
  207.         } state;
  208.  
  209.         quote = 0;
  210.         state = ST_BEFORE_NAME;
  211.         while (i < end_pos)
  212.         {
  213.             c = source[i++];
  214.  
  215.             if (c == wxT('>') && !(state == ST_VALUE && quote != 0))
  216.             {
  217.                 if (state == ST_BEFORE_EQ || state == ST_NAME)
  218.                 {
  219.                     m_ParamNames.Add(pname);
  220.                     m_ParamValues.Add(wxEmptyString);
  221.                 }
  222.                 else if (state == ST_VALUE && quote == 0)
  223.                 {
  224.                     m_ParamNames.Add(pname);
  225.                     if (entParser)
  226.                         m_ParamValues.Add(entParser->Parse(pvalue));
  227.                     else
  228.                         m_ParamValues.Add(pvalue);
  229.                 }
  230.                 break;
  231.             }
  232.             switch (state)
  233.             {
  234.                 case ST_BEFORE_NAME:
  235.                     if (!IS_WHITE(c))
  236.                     {
  237.                         pname = c;
  238.                         state = ST_NAME;
  239.                     }
  240.                     break;
  241.                 case ST_NAME:
  242.                     if (IS_WHITE(c))
  243.                         state = ST_BEFORE_EQ;
  244.                     else if (c == wxT('='))
  245.                         state = ST_BEFORE_VALUE;
  246.                     else
  247.                         pname << c;
  248.                     break;
  249.                 case ST_BEFORE_EQ:
  250.                     if (c == wxT('='))
  251.                         state = ST_BEFORE_VALUE;
  252.                     else if (!IS_WHITE(c))
  253.                     {
  254.                         m_ParamNames.Add(pname);
  255.                         m_ParamValues.Add(wxEmptyString);
  256.                         pname = c;
  257.                         state = ST_NAME;
  258.                     }
  259.                     break;
  260.                 case ST_BEFORE_VALUE:
  261.                     if (!IS_WHITE(c))
  262.                     {
  263.                         if (c == wxT('"') || c == wxT('\''))
  264.                             quote = c, pvalue = wxEmptyString;
  265.                         else
  266.                             quote = 0, pvalue = c;
  267.                         state = ST_VALUE;
  268.                     }
  269.                     break;
  270.                 case ST_VALUE:
  271.                     if ((quote != 0 && c == quote) ||
  272.                         (quote == 0 && IS_WHITE(c)))
  273.                     {
  274.                         m_ParamNames.Add(pname);
  275.                         if (quote == 0)
  276.                         {
  277.                             // VS: backward compatibility, no real reason,
  278.                             //     but wxHTML code relies on this... :(
  279.                             pvalue.MakeUpper();
  280.                         }
  281.                         if (entParser)
  282.                             m_ParamValues.Add(entParser->Parse(pvalue));
  283.                         else
  284.                             m_ParamValues.Add(pvalue);
  285.                         state = ST_BEFORE_NAME;
  286.                     }
  287.                     else
  288.                         pvalue << c;
  289.                     break;
  290.             }
  291.         }
  292.  
  293.         #undef IS_WHITE
  294.    }
  295.    m_Begin = i;
  296.  
  297.    cache->QueryTag(pos, &m_End1, &m_End2);
  298.    if (m_End1 > end_pos) m_End1 = end_pos;
  299.    if (m_End2 > end_pos) m_End2 = end_pos;
  300. }
  301.  
  302. wxHtmlTag::~wxHtmlTag()
  303. {
  304.     wxHtmlTag *t1, *t2;
  305.     t1 = m_FirstChild;
  306.     while (t1)
  307.     {
  308.         t2 = t1->GetNextSibling();
  309.         delete t1;
  310.         t1 = t2;
  311.     }
  312. }
  313.  
  314. bool wxHtmlTag::HasParam(const wxString& par) const
  315. {
  316.     return (m_ParamNames.Index(par, FALSE) != wxNOT_FOUND);
  317. }
  318.  
  319. wxString wxHtmlTag::GetParam(const wxString& par, bool with_commas) const
  320. {
  321.     int index = m_ParamNames.Index(par, FALSE);
  322.     if (index == wxNOT_FOUND)
  323.         return wxEmptyString;
  324.     if (with_commas)
  325.     {
  326.         // VS: backward compatibility, seems to be never used by wxHTML...
  327.         wxString s;
  328.         s << wxT('"') << m_ParamValues[index] << wxT('"');
  329.         return s;
  330.     }
  331.     else
  332.         return m_ParamValues[index];
  333. }
  334.  
  335. int wxHtmlTag::ScanParam(const wxString& par,
  336.                          const wxChar *format,
  337.                          void *param) const
  338. {
  339.     wxString parval = GetParam(par);
  340.     return wxSscanf(parval, format, param);
  341. }
  342.  
  343. bool wxHtmlTag::GetParamAsColour(const wxString& par, wxColour *clr) const
  344. {
  345.     wxString str = GetParam(par);
  346.  
  347.     if (str.IsEmpty()) return FALSE;
  348.     if (str.GetChar(0) == wxT('#'))
  349.     {
  350.         unsigned long tmp;
  351.         if (ScanParam(par, wxT("#%lX"), &tmp) != 1)
  352.             return FALSE;
  353.         *clr = wxColour((unsigned char)((tmp & 0xFF0000) >> 16),
  354.                         (unsigned char)((tmp & 0x00FF00) >> 8),
  355.                         (unsigned char)(tmp & 0x0000FF));
  356.         return TRUE;
  357.     }
  358.     else
  359.     {
  360.         // Handle colours defined in HTML 4.0:
  361.         #define HTML_COLOUR(name,r,g,b)                 \
  362.             if (str.IsSameAs(wxT(name), FALSE))         \
  363.                 { *clr = wxColour(r,g,b); return TRUE; }
  364.         HTML_COLOUR("black",   0x00,0x00,0x00)
  365.         HTML_COLOUR("silver",  0xC0,0xC0,0xC0)
  366.         HTML_COLOUR("gray",    0x80,0x80,0x80)
  367.         HTML_COLOUR("white",   0xFF,0xFF,0xFF)
  368.         HTML_COLOUR("maroon",  0x80,0x00,0x00)
  369.         HTML_COLOUR("red",     0xFF,0x00,0x00)
  370.         HTML_COLOUR("purple",  0x80,0x00,0x80)
  371.         HTML_COLOUR("fuchsia", 0xFF,0x00,0xFF)
  372.         HTML_COLOUR("green",   0x00,0x80,0x00)
  373.         HTML_COLOUR("lime",    0x00,0xFF,0x00)
  374.         HTML_COLOUR("olive",   0x80,0x80,0x00)
  375.         HTML_COLOUR("yellow",  0xFF,0xFF,0x00)
  376.         HTML_COLOUR("navy",    0x00,0x00,0x80)
  377.         HTML_COLOUR("blue",    0x00,0x00,0xFF)
  378.         HTML_COLOUR("teal",    0x00,0x80,0x80)
  379.         HTML_COLOUR("aqua",    0x00,0xFF,0xFF)
  380.         #undef HTML_COLOUR
  381.     }
  382.  
  383.     return FALSE;
  384. }
  385.  
  386. bool wxHtmlTag::GetParamAsInt(const wxString& par, int *clr) const
  387. {
  388.     if (!HasParam(par)) return FALSE;
  389.     long i;
  390.     bool succ = GetParam(par).ToLong(&i);
  391.     *clr = (int)i;
  392.     return succ;
  393. }
  394.  
  395. wxString wxHtmlTag::GetAllParams() const
  396. {
  397.     // VS: this function is for backward compatiblity only,
  398.     //     never used by wxHTML
  399.     wxString s;
  400.     size_t cnt = m_ParamNames.GetCount();
  401.     for (size_t i = 0; i < cnt; i++)
  402.     {
  403.         s << m_ParamNames[i];
  404.         s << wxT('=');
  405.         if (m_ParamValues[i].Find(wxT('"')) != wxNOT_FOUND)
  406.             s << wxT('\'') << m_ParamValues[i] << wxT('\'');
  407.         else
  408.             s << wxT('"') << m_ParamValues[i] << wxT('"');
  409.     }
  410.     return s;
  411. }
  412.  
  413. wxHtmlTag *wxHtmlTag::GetFirstSibling() const
  414. {
  415.     if (m_Parent)
  416.         return m_Parent->m_FirstChild;
  417.     else
  418.     {
  419.         wxHtmlTag *cur = (wxHtmlTag*)this;
  420.         while (cur->m_Prev)
  421.             cur = cur->m_Prev;
  422.         return cur;
  423.     }
  424. }
  425.  
  426. wxHtmlTag *wxHtmlTag::GetLastSibling() const
  427. {
  428.     if (m_Parent)
  429.         return m_Parent->m_LastChild;
  430.     else
  431.     {
  432.         wxHtmlTag *cur = (wxHtmlTag*)this;
  433.         while (cur->m_Next)
  434.             cur = cur->m_Next;
  435.         return cur;
  436.     }
  437. }
  438.  
  439. wxHtmlTag *wxHtmlTag::GetNextTag() const
  440. {
  441.     if (m_FirstChild) return m_FirstChild;
  442.     if (m_Next) return m_Next;
  443.     wxHtmlTag *cur = m_Parent;
  444.     if (!cur) return NULL;
  445.     while (cur->m_Parent && !cur->m_Next)
  446.         cur = cur->m_Parent;
  447.     return cur->m_Next;
  448. }
  449.  
  450. #endif
  451.