]>
git.saurik.com Git - wxWidgets.git/blob - src/html/htmltag.cpp
   1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     wxHtmlTag class (represents single tag) 
   4 // Author:      Vaclav Slavik 
   6 // Copyright:   (c) 1999 Vaclav Slavik 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 #include "wx/wxprec.h" 
  22 #include "wx/html/htmltag.h" 
  23 #include "wx/html/htmlpars.h" 
  24 #include "wx/colour.h" 
  25 #include <stdio.h> // for vsscanf 
  29 //----------------------------------------------------------------------------- 
  31 //----------------------------------------------------------------------------- 
  33 struct wxHtmlCacheItem
 
  35     // this is "pos" value passed to wxHtmlTag's constructor. 
  36     // it is position of '<' character of the tag 
  39     // end positions for the tag: 
  40     // end1 is '<' of ending tag, 
  41     // end2 is '>' or both are 
  42     // -1 if there is no ending tag for this one... 
  43     // or -2 if this is ending tag  </...> 
  51 IMPLEMENT_CLASS(wxHtmlTagsCache
,wxObject
) 
  53 #define CACHE_INCREMENT  64 
  55 bool wxIsCDATAElement(const wxChar 
*tag
) 
  57     return (wxStrcmp(tag
, _T("SCRIPT")) == 0) || 
  58            (wxStrcmp(tag
, _T("STYLE")) == 0); 
  61 wxHtmlTagsCache::wxHtmlTagsCache(const wxString
& source
) 
  63     const wxChar 
*src 
= source
.c_str(); 
  64     int lng 
= source
.Length(); 
  65     wxChar tagBuffer
[256]; 
  74         if (src
[pos
] == wxT('<'))   // tag found: 
  76             if (m_CacheSize 
% CACHE_INCREMENT 
== 0) 
  77                 m_Cache 
= (wxHtmlCacheItem
*) realloc(m_Cache
, (m_CacheSize 
+ CACHE_INCREMENT
) * sizeof(wxHtmlCacheItem
)); 
  78             int tg 
= m_CacheSize
++; 
  80             m_Cache
[tg
].Key 
= stpos
; 
  84                   pos 
< lng 
&& i 
< (int)WXSIZEOF(tagBuffer
) - 1 && 
  85                   src
[pos
] != wxT('>') && !wxIsspace(src
[pos
]); 
  88                 tagBuffer
[i
] = (wxChar
)wxToupper(src
[pos
]); 
  90             tagBuffer
[i
] = _T('\0'); 
  92             m_Cache
[tg
].Name 
= new wxChar
[i
+1]; 
  93             memcpy(m_Cache
[tg
].Name
, tagBuffer
, (i
+1)*sizeof(wxChar
)); 
  95             while (pos 
< lng 
&& src
[pos
] != wxT('>')) pos
++; 
  97             if (src
[stpos
+1] == wxT('/')) // ending tag: 
  99                 m_Cache
[tg
].End1 
= m_Cache
[tg
].End2 
= -2; 
 100                 // find matching begin tag: 
 101                 for (i 
= tg
; i 
>= 0; i
--) 
 102                     if ((m_Cache
[i
].End1 
== -1) && (wxStrcmp(m_Cache
[i
].Name
, tagBuffer
+1) == 0)) 
 104                         m_Cache
[i
].End1 
= stpos
; 
 105                         m_Cache
[i
].End2 
= pos 
+ 1; 
 111                 m_Cache
[tg
].End1 
= m_Cache
[tg
].End2 
= -1; 
 113                 if (wxIsCDATAElement(tagBuffer
)) 
 115                     // store the orig pos in case we are missing the closing 
 117                     wxInt32 old_pos 
= pos
; 
 118                     bool foundCloseTag 
= false; 
 120                     // find next matching tag 
 121                     int tag_len 
= wxStrlen(tagBuffer
); 
 124                         // find the ending tag 
 125                         while (pos 
+ 1 < lng 
&& 
 126                                (src
[pos
] != '<' || src
[pos
+1] != '/')) 
 133                         while (pos 
< lng 
&& match_pos 
< tag_len 
&& src
[pos
] != '>' && src
[pos
] != '<') { 
 134                             // cast to wxChar needed to suppress warning in 
 136                             if ((wxChar
)wxToupper(src
[pos
]) == tagBuffer
[match_pos
]) { 
 139                             else if (src
[pos
] == wxT(' ') || src
[pos
] == wxT('\n') || 
 140                                 src
[pos
] == wxT('\r') || src
[pos
] == wxT('\t')) { 
 141                                 // need to skip over these 
 150                         if (match_pos 
== tag_len
) 
 152                             pos 
= pos 
- tag_len 
- 3; 
 153                             foundCloseTag 
= true; 
 156                         else // keep looking for the closing tag 
 163                         // we didn't find closing tag; this means the markup 
 164                         // is incorrect and the best thing we can do is to 
 165                         // ignore the unclosed tag and continue parsing as if 
 176     // ok, we're done, now we'll free .Name members of cache - we don't need it anymore: 
 177     for (int i 
= 0; i 
< m_CacheSize
; i
++) 
 179         delete[] m_Cache
[i
].Name
; 
 180         m_Cache
[i
].Name 
= NULL
; 
 184 void wxHtmlTagsCache::QueryTag(int at
, int* end1
, int* end2
) 
 186     if (m_Cache 
== NULL
) return; 
 187     if (m_Cache
[m_CachePos
].Key 
!= at
) 
 189         int delta 
= (at 
< m_Cache
[m_CachePos
].Key
) ? -1 : 1; 
 192             if ( m_CachePos 
< 0 || m_CachePos 
== m_CacheSize 
) 
 194                 // something is very wrong with HTML, give up by returning an 
 195                 // impossibly large value which is going to be ignored by the 
 204         while (m_Cache
[m_CachePos
].Key 
!= at
); 
 206     *end1 
= m_Cache
[m_CachePos
].End1
; 
 207     *end2 
= m_Cache
[m_CachePos
].End2
; 
 213 //----------------------------------------------------------------------------- 
 215 //----------------------------------------------------------------------------- 
 217 IMPLEMENT_CLASS(wxHtmlTag
,wxObject
) 
 219 wxHtmlTag::wxHtmlTag(wxHtmlTag 
*parent
, 
 220                      const wxString
& source
, int pos
, int end_pos
, 
 221                      wxHtmlTagsCache 
*cache
, 
 222                      wxHtmlEntitiesParser 
*entParser
) : wxObject() 
 224     /* Setup DOM relations */ 
 227     m_FirstChild 
= m_LastChild 
= NULL
; 
 231         m_Prev 
= m_Parent
->m_LastChild
; 
 233             m_Parent
->m_FirstChild 
= this; 
 235             m_Prev
->m_Next 
= this; 
 236         m_Parent
->m_LastChild 
= this; 
 241     /* Find parameters and their values: */ 
 246     // fill-in name, params and begin pos: 
 249     // find tag's name and convert it to uppercase: 
 250     while ((i 
< end_pos
) && 
 251            ((c 
= source
[i
++]) != wxT(' ') && c 
!= wxT('\r') && 
 252              c 
!= wxT('\n') && c 
!= wxT('\t') && 
 255         if ((c 
>= wxT('a')) && (c 
<= wxT('z'))) 
 256             c 
-= (wxT('a') - wxT('A')); 
 260     // if the tag has parameters, read them and "normalize" them, 
 261     // i.e. convert to uppercase, replace whitespaces by spaces and 
 262     // remove whitespaces around '=': 
 263     if (source
[i
-1] != wxT('>')) 
 265         #define IS_WHITE(c) (c == wxT(' ') || c == wxT('\r') || \ 
 266                              c == wxT('\n') || c == wxT('\t')) 
 267         wxString pname
, pvalue
; 
 279         state 
= ST_BEFORE_NAME
; 
 284             if (c 
== wxT('>') && !(state 
== ST_VALUE 
&& quote 
!= 0)) 
 286                 if (state 
== ST_BEFORE_EQ 
|| state 
== ST_NAME
) 
 288                     m_ParamNames
.Add(pname
); 
 289                     m_ParamValues
.Add(wxEmptyString
); 
 291                 else if (state 
== ST_VALUE 
&& quote 
== 0) 
 293                     m_ParamNames
.Add(pname
); 
 295                         m_ParamValues
.Add(entParser
->Parse(pvalue
)); 
 297                         m_ParamValues
.Add(pvalue
); 
 312                         state 
= ST_BEFORE_EQ
; 
 313                     else if (c 
== wxT('=')) 
 314                         state 
= ST_BEFORE_VALUE
; 
 320                         state 
= ST_BEFORE_VALUE
; 
 321                     else if (!IS_WHITE(c
)) 
 323                         m_ParamNames
.Add(pname
); 
 324                         m_ParamValues
.Add(wxEmptyString
); 
 329                 case ST_BEFORE_VALUE
: 
 332                         if (c 
== wxT('"') || c 
== wxT('\'')) 
 333                             quote 
= c
, pvalue 
= wxEmptyString
; 
 335                             quote 
= 0, pvalue 
= c
; 
 340                     if ((quote 
!= 0 && c 
== quote
) || 
 341                         (quote 
== 0 && IS_WHITE(c
))) 
 343                         m_ParamNames
.Add(pname
); 
 346                             // VS: backward compatibility, no real reason, 
 347                             //     but wxHTML code relies on this... :( 
 351                             m_ParamValues
.Add(entParser
->Parse(pvalue
)); 
 353                             m_ParamValues
.Add(pvalue
); 
 354                         state 
= ST_BEFORE_NAME
; 
 366     cache
->QueryTag(pos
, &m_End1
, &m_End2
); 
 367     if (m_End1 
> end_pos
) m_End1 
= end_pos
; 
 368     if (m_End2 
> end_pos
) m_End2 
= end_pos
; 
 371 wxHtmlTag::~wxHtmlTag() 
 377         t2 
= t1
->GetNextSibling(); 
 383 bool wxHtmlTag::HasParam(const wxString
& par
) const 
 385     return (m_ParamNames
.Index(par
, false) != wxNOT_FOUND
); 
 388 wxString 
wxHtmlTag::GetParam(const wxString
& par
, bool with_commas
) const 
 390     int index 
= m_ParamNames
.Index(par
, false); 
 391     if (index 
== wxNOT_FOUND
) 
 392         return wxEmptyString
; 
 395         // VS: backward compatibility, seems to be never used by wxHTML... 
 397         s 
<< wxT('"') << m_ParamValues
[index
] << wxT('"'); 
 401         return m_ParamValues
[index
]; 
 404 int wxHtmlTag::ScanParam(const wxString
& par
, 
 405                          const wxChar 
*format
, 
 408     wxString parval 
= GetParam(par
); 
 409     return wxSscanf(parval
, format
, param
); 
 412 bool wxHtmlTag::GetParamAsColour(const wxString
& par
, wxColour 
*clr
) const 
 414     wxString str 
= GetParam(par
); 
 416     if (str
.empty()) return false; 
 417     if (str
.GetChar(0) == wxT('#')) 
 420         if (ScanParam(par
, wxT("#%lX"), &tmp
) != 1) 
 422         *clr 
= wxColour((unsigned char)((tmp 
& 0xFF0000) >> 16), 
 423                         (unsigned char)((tmp 
& 0x00FF00) >> 8), 
 424                         (unsigned char)(tmp 
& 0x0000FF)); 
 429         // Handle colours defined in HTML 4.0: 
 430         #define HTML_COLOUR(name,r,g,b)                 \ 
 431             if (str.IsSameAs(wxT(name), false))         \ 
 432                 { *clr = wxColour(r,g,b); return true; } 
 433         HTML_COLOUR("black",   0x00,0x00,0x00) 
 434         HTML_COLOUR("silver",  0xC0,0xC0,0xC0) 
 435         HTML_COLOUR("gray",    0x80,0x80,0x80) 
 436         HTML_COLOUR("white",   0xFF,0xFF,0xFF) 
 437         HTML_COLOUR("maroon",  0x80,0x00,0x00) 
 438         HTML_COLOUR("red",     0xFF,0x00,0x00) 
 439         HTML_COLOUR("purple",  0x80,0x00,0x80) 
 440         HTML_COLOUR("fuchsia", 0xFF,0x00,0xFF) 
 441         HTML_COLOUR("green",   0x00,0x80,0x00) 
 442         HTML_COLOUR("lime",    0x00,0xFF,0x00) 
 443         HTML_COLOUR("olive",   0x80,0x80,0x00) 
 444         HTML_COLOUR("yellow",  0xFF,0xFF,0x00) 
 445         HTML_COLOUR("navy",    0x00,0x00,0x80) 
 446         HTML_COLOUR("blue",    0x00,0x00,0xFF) 
 447         HTML_COLOUR("teal",    0x00,0x80,0x80) 
 448         HTML_COLOUR("aqua",    0x00,0xFF,0xFF) 
 455 bool wxHtmlTag::GetParamAsInt(const wxString
& par
, int *clr
) const 
 457     if (!HasParam(par
)) return false; 
 459     bool succ 
= GetParam(par
).ToLong(&i
); 
 464 wxString 
wxHtmlTag::GetAllParams() const 
 466     // VS: this function is for backward compatibility only, 
 467     //     never used by wxHTML 
 469     size_t cnt 
= m_ParamNames
.GetCount(); 
 470     for (size_t i 
= 0; i 
< cnt
; i
++) 
 472         s 
<< m_ParamNames
[i
]; 
 474         if (m_ParamValues
[i
].Find(wxT('"')) != wxNOT_FOUND
) 
 475             s 
<< wxT('\'') << m_ParamValues
[i
] << wxT('\''); 
 477             s 
<< wxT('"') << m_ParamValues
[i
] << wxT('"'); 
 482 wxHtmlTag 
*wxHtmlTag::GetFirstSibling() const 
 485         return m_Parent
->m_FirstChild
; 
 488         wxHtmlTag 
*cur 
= (wxHtmlTag
*)this; 
 495 wxHtmlTag 
*wxHtmlTag::GetLastSibling() const 
 498         return m_Parent
->m_LastChild
; 
 501         wxHtmlTag 
*cur 
= (wxHtmlTag
*)this; 
 508 wxHtmlTag 
*wxHtmlTag::GetNextTag() const 
 510     if (m_FirstChild
) return m_FirstChild
; 
 511     if (m_Next
) return m_Next
; 
 512     wxHtmlTag 
*cur 
= m_Parent
; 
 513     if (!cur
) return NULL
; 
 514     while (cur
->m_Parent 
&& !cur
->m_Next
)