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

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        htmlpars.cpp
  3. // Purpose:     wxHtmlParser class (generic parser)
  4. // Author:      Vaclav Slavik
  5. // RCS-ID:      $Id: htmlpars.cpp,v 1.28.2.5 2002/11/10 00:05:39 VS Exp $
  6. // Copyright:   (c) 1999 Vaclav Slavik
  7. // Licence:     wxWindows Licence
  8. /////////////////////////////////////////////////////////////////////////////
  9.  
  10.  
  11. #ifdef __GNUG__
  12. #pragma implementation "htmlpars.h"
  13. #endif
  14.  
  15. #include "wx/wxprec.h"
  16.  
  17. #include "wx/defs.h"
  18. #if wxUSE_HTML && wxUSE_STREAMS
  19.  
  20. #ifdef __BORLANDC__
  21. #pragma hdrstop
  22. #endif
  23.  
  24. #ifndef WXPRECOMP
  25.     #include "wx/log.h"
  26.     #include "wx/intl.h"
  27. #endif
  28.  
  29. #include "wx/tokenzr.h"
  30. #include "wx/wfstream.h"
  31. #include "wx/url.h"
  32. #include "wx/fontmap.h"
  33. #include "wx/html/htmldefs.h"
  34. #include "wx/html/htmlpars.h"
  35. #include "wx/dynarray.h"
  36. #include "wx/arrimpl.cpp"
  37.  
  38. //-----------------------------------------------------------------------------
  39. // wxHtmlParser helpers
  40. //-----------------------------------------------------------------------------
  41.  
  42. class wxHtmlTextPiece
  43. {
  44. public:
  45.     wxHtmlTextPiece(int pos, int lng) : m_pos(pos), m_lng(lng) {}
  46.     int m_pos, m_lng;
  47. };
  48.  
  49. WX_DECLARE_OBJARRAY(wxHtmlTextPiece, wxHtmlTextPieces);
  50. WX_DEFINE_OBJARRAY(wxHtmlTextPieces);
  51.  
  52. class wxHtmlParserState
  53. {
  54. public:
  55.     wxHtmlTag         *m_curTag;
  56.     wxHtmlTag         *m_tags;
  57.     wxHtmlTextPieces  *m_textPieces;
  58.     int                m_curTextPiece;
  59.     wxString           m_source;
  60.     wxHtmlParserState *m_nextState;
  61. };
  62.  
  63. //-----------------------------------------------------------------------------
  64. // wxHtmlParser
  65. //-----------------------------------------------------------------------------
  66.  
  67. IMPLEMENT_ABSTRACT_CLASS(wxHtmlParser,wxObject)
  68.  
  69. wxHtmlParser::wxHtmlParser()
  70.     : wxObject(), m_HandlersHash(wxKEY_STRING),
  71.       m_FS(NULL), m_HandlersStack(NULL)
  72. {
  73.     m_entitiesParser = new wxHtmlEntitiesParser;
  74.     m_Tags = NULL;
  75.     m_CurTag = NULL;
  76.     m_TextPieces = NULL;
  77.     m_CurTextPiece = 0;
  78.     m_SavedStates = NULL;
  79. }
  80.  
  81. wxHtmlParser::~wxHtmlParser()
  82. {
  83.     while (RestoreState()) {}
  84.     DestroyDOMTree();
  85.     
  86.     delete m_HandlersStack;
  87.     m_HandlersHash.Clear();
  88.     m_HandlersList.DeleteContents(TRUE);
  89.     m_HandlersList.Clear();
  90.     delete m_entitiesParser;
  91. }
  92.  
  93. wxObject* wxHtmlParser::Parse(const wxString& source)
  94. {
  95.     InitParser(source);
  96.     DoParsing();
  97.     wxObject *result = GetProduct();
  98.     DoneParser();
  99.     return result;
  100. }
  101.  
  102. void wxHtmlParser::InitParser(const wxString& source)
  103. {
  104.     SetSource(source);
  105.     m_stopParsing = FALSE;
  106. }
  107.  
  108. void wxHtmlParser::DoneParser()
  109. {
  110.     DestroyDOMTree();
  111. }
  112.  
  113. void wxHtmlParser::SetSource(const wxString& src)
  114. {
  115.     DestroyDOMTree();
  116.     m_Source = src;
  117.     CreateDOMTree();
  118.     m_CurTag = NULL;
  119.     m_CurTextPiece = 0;
  120. }
  121.  
  122. void wxHtmlParser::CreateDOMTree()
  123. {
  124.     wxHtmlTagsCache cache(m_Source);
  125.     m_TextPieces = new wxHtmlTextPieces;
  126.     CreateDOMSubTree(NULL, 0, m_Source.Length(), &cache);
  127.     m_CurTextPiece = 0;
  128. }
  129.  
  130. void wxHtmlParser::CreateDOMSubTree(wxHtmlTag *cur,
  131.                                     int begin_pos, int end_pos,
  132.                                     wxHtmlTagsCache *cache)
  133. {
  134.     if (end_pos <= begin_pos) return;
  135.  
  136.     wxChar c;
  137.     int i = begin_pos;
  138.     int textBeginning = begin_pos;
  139.  
  140.     while (i < end_pos)
  141.     {
  142.         c = m_Source.GetChar(i);
  143.  
  144.         if (c == wxT('<'))
  145.         {
  146.             // add text to m_TextPieces:
  147.             if (i - textBeginning > 0)
  148.                 m_TextPieces->Add(
  149.                     wxHtmlTextPiece(textBeginning, i - textBeginning));
  150.  
  151.             // if it is a comment, skip it:
  152.             if (i < end_pos-6 && m_Source.GetChar(i+1) == wxT('!') &&
  153.                                  m_Source.GetChar(i+2) == wxT('-') &&
  154.                                  m_Source.GetChar(i+3) == wxT('-'))
  155.             {
  156.                 // Comments begin with "<!--" and end with "--[ \t\r\n]*>"
  157.                 // according to HTML 4.0
  158.                 int dashes = 0;
  159.                 i += 4;
  160.                 while (i < end_pos)
  161.                 {
  162.                     c = m_Source.GetChar(i++);
  163.                     if ((c == wxT(' ') || c == wxT('\n') ||
  164.                         c == wxT('\r') || c == wxT('\t')) && dashes >= 2) {}
  165.                     else if (c == wxT('>') && dashes >= 2)
  166.                     {
  167.                         textBeginning = i;
  168.                         break;
  169.                     }
  170.                     else if (c == wxT('-'))
  171.                         dashes++;
  172.                     else
  173.                         dashes = 0;
  174.                 }
  175.             }
  176.  
  177.             // add another tag to the tree:
  178.             else if (i < end_pos-1 && m_Source.GetChar(i+1) != wxT('/'))
  179.             {
  180.                 wxHtmlTag *chd;
  181.                 if (cur)
  182.                     chd = new wxHtmlTag(cur, m_Source,
  183.                                         i, end_pos, cache, m_entitiesParser);
  184.                 else
  185.                 {
  186.                     chd = new wxHtmlTag(NULL, m_Source,
  187.                                         i, end_pos, cache, m_entitiesParser);
  188.                     if (!m_Tags)
  189.                     {
  190.                         // if this is the first tag to be created make the root
  191.                         // m_Tags point to it:
  192.                         m_Tags = chd;
  193.                     }
  194.                     else
  195.                     {
  196.                         // if there is already a root tag add this tag as
  197.                         // the last sibling:
  198.                         chd->m_Prev = m_Tags->GetLastSibling();
  199.                         chd->m_Prev->m_Next = chd;
  200.                     }
  201.                 }
  202.  
  203.                 if (chd->HasEnding())
  204.                 {
  205.                     CreateDOMSubTree(chd,
  206.                                      chd->GetBeginPos(), chd->GetEndPos1(),
  207.                                      cache);
  208.                     i = chd->GetEndPos2();
  209.                 }
  210.                 else
  211.                     i = chd->GetBeginPos();
  212.                 textBeginning = i;
  213.             }
  214.  
  215.             // ... or skip ending tag:
  216.             else
  217.             {
  218.                 while (i < end_pos && m_Source.GetChar(i) != wxT('>')) i++;
  219.                 textBeginning = i+1;
  220.             }
  221.         }
  222.         else i++;
  223.     }
  224.  
  225.     // add remaining text to m_TextPieces:
  226.     if (end_pos - textBeginning > 0)
  227.         m_TextPieces->Add(
  228.             wxHtmlTextPiece(textBeginning, end_pos - textBeginning));
  229. }
  230.  
  231. void wxHtmlParser::DestroyDOMTree()
  232. {
  233.     wxHtmlTag *t1, *t2;
  234.     t1 = m_Tags;
  235.     while (t1)
  236.     {
  237.         t2 = t1->GetNextSibling();
  238.         delete t1;
  239.         t1 = t2;
  240.     }
  241.     m_Tags = m_CurTag = NULL;
  242.  
  243.     delete m_TextPieces;
  244.     m_TextPieces = NULL;
  245. }
  246.  
  247. void wxHtmlParser::DoParsing()
  248. {
  249.     m_CurTag = m_Tags;
  250.     m_CurTextPiece = 0;
  251.     DoParsing(0, m_Source.Length());
  252. }
  253.  
  254. void wxHtmlParser::DoParsing(int begin_pos, int end_pos)
  255. {
  256.     if (end_pos <= begin_pos) return;
  257.  
  258.     wxHtmlTextPieces& pieces = *m_TextPieces;
  259.     size_t piecesCnt = pieces.GetCount();
  260.  
  261.     while (begin_pos < end_pos)
  262.     {
  263.         while (m_CurTag && m_CurTag->GetBeginPos() < begin_pos)
  264.             m_CurTag = m_CurTag->GetNextTag();
  265.         while (m_CurTextPiece < piecesCnt &&
  266.                pieces[m_CurTextPiece].m_pos < begin_pos)
  267.             m_CurTextPiece++;
  268.  
  269.         if (m_CurTextPiece < piecesCnt &&
  270.             (!m_CurTag ||
  271.              pieces[m_CurTextPiece].m_pos < m_CurTag->GetBeginPos()))
  272.         {
  273.             // Add text:
  274.             AddText(GetEntitiesParser()->Parse(
  275.                        m_Source.Mid(pieces[m_CurTextPiece].m_pos,
  276.                                     pieces[m_CurTextPiece].m_lng)));
  277.             begin_pos = pieces[m_CurTextPiece].m_pos +
  278.                         pieces[m_CurTextPiece].m_lng;
  279.             m_CurTextPiece++;
  280.         }
  281.         else if (m_CurTag)
  282.         {
  283.             // Add tag:
  284.             if (m_CurTag)
  285.             {
  286.                 if (m_CurTag->HasEnding())
  287.                     begin_pos = m_CurTag->GetEndPos2();
  288.                 else
  289.                     begin_pos = m_CurTag->GetBeginPos();
  290.             }
  291.             wxHtmlTag *t = m_CurTag;
  292.             m_CurTag = m_CurTag->GetNextTag();
  293.             AddTag(*t);
  294.             if (m_stopParsing)
  295.                 return;
  296.         }
  297.         else break;
  298.     }
  299. }
  300.  
  301. void wxHtmlParser::AddTag(const wxHtmlTag& tag)
  302. {
  303.     wxHtmlTagHandler *h;
  304.     bool inner = FALSE;
  305.  
  306.     h = (wxHtmlTagHandler*) m_HandlersHash.Get(tag.GetName());
  307.     if (h)
  308.     {
  309.         inner = h->HandleTag(tag);
  310.         if (m_stopParsing)
  311.             return;
  312.     }
  313.     if (!inner)
  314.     {
  315.         if (tag.HasEnding())
  316.             DoParsing(tag.GetBeginPos(), tag.GetEndPos1());
  317.     }
  318. }
  319.  
  320. void wxHtmlParser::AddTagHandler(wxHtmlTagHandler *handler)
  321. {
  322.     wxString s(handler->GetSupportedTags());
  323.     wxStringTokenizer tokenizer(s, wxT(", "));
  324.  
  325.     while (tokenizer.HasMoreTokens())
  326.         m_HandlersHash.Put(tokenizer.GetNextToken(), handler);
  327.  
  328.     if (m_HandlersList.IndexOf(handler) == wxNOT_FOUND)
  329.         m_HandlersList.Append(handler);
  330.  
  331.     handler->SetParser(this);
  332. }
  333.  
  334. void wxHtmlParser::PushTagHandler(wxHtmlTagHandler *handler, wxString tags)
  335. {
  336.     wxStringTokenizer tokenizer(tags, wxT(", "));
  337.     wxString key;
  338.  
  339.     if (m_HandlersStack == NULL)
  340.     {
  341.         m_HandlersStack = new wxList;
  342.         m_HandlersStack->DeleteContents(TRUE);
  343.     }
  344.  
  345.     m_HandlersStack->Insert(new wxHashTable(m_HandlersHash));
  346.  
  347.     while (tokenizer.HasMoreTokens())
  348.     {
  349.         key = tokenizer.GetNextToken();
  350.         m_HandlersHash.Delete(key);
  351.         m_HandlersHash.Put(key, handler);
  352.     }
  353. }
  354.  
  355. void wxHtmlParser::PopTagHandler()
  356. {
  357.     wxNode *first;
  358.  
  359.     if (m_HandlersStack == NULL ||
  360.         (first = m_HandlersStack->GetFirst()) == NULL)
  361.     {
  362.         wxLogWarning(_("Warning: attempt to remove HTML tag handler from empty stack."));
  363.         return;
  364.     }
  365.     m_HandlersHash = *((wxHashTable*) first->GetData());
  366.     m_HandlersStack->DeleteNode(first);
  367. }
  368.  
  369. void wxHtmlParser::SetSourceAndSaveState(const wxString& src)
  370. {
  371.     wxHtmlParserState *s = new wxHtmlParserState;
  372.  
  373.     s->m_curTag = m_CurTag;
  374.     s->m_tags = m_Tags;
  375.     s->m_textPieces = m_TextPieces;
  376.     s->m_curTextPiece = m_CurTextPiece;
  377.     s->m_source = m_Source;
  378.  
  379.     s->m_nextState = m_SavedStates;
  380.     m_SavedStates = s;
  381.  
  382.     m_CurTag = NULL;
  383.     m_Tags = NULL;
  384.     m_TextPieces = NULL;
  385.     m_CurTextPiece = 0;
  386.     m_Source = wxEmptyString;
  387.  
  388.     SetSource(src);
  389. }
  390.  
  391. bool wxHtmlParser::RestoreState()
  392. {
  393.     if (!m_SavedStates) return FALSE;
  394.  
  395.     DestroyDOMTree();
  396.  
  397.     wxHtmlParserState *s = m_SavedStates;
  398.     m_SavedStates = s->m_nextState;
  399.  
  400.     m_CurTag = s->m_curTag;
  401.     m_Tags = s->m_tags;
  402.     m_TextPieces = s->m_textPieces;
  403.     m_CurTextPiece = s->m_curTextPiece;
  404.     m_Source = s->m_source;
  405.  
  406.     delete s;
  407.     return TRUE;
  408. }
  409.  
  410. //-----------------------------------------------------------------------------
  411. // wxHtmlTagHandler
  412. //-----------------------------------------------------------------------------
  413.  
  414. IMPLEMENT_ABSTRACT_CLASS(wxHtmlTagHandler,wxObject)
  415.  
  416.  
  417. //-----------------------------------------------------------------------------
  418. // wxHtmlEntitiesParser
  419. //-----------------------------------------------------------------------------
  420.  
  421. IMPLEMENT_DYNAMIC_CLASS(wxHtmlEntitiesParser,wxObject)
  422.  
  423. wxHtmlEntitiesParser::wxHtmlEntitiesParser()
  424. #if wxUSE_WCHAR_T && !wxUSE_UNICODE
  425.     : m_conv(NULL), m_encoding(wxFONTENCODING_SYSTEM)
  426. #endif
  427. {
  428. }
  429.  
  430. wxHtmlEntitiesParser::~wxHtmlEntitiesParser()
  431. {
  432. #if wxUSE_WCHAR_T && !wxUSE_UNICODE
  433.     delete m_conv;
  434. #endif
  435. }
  436.  
  437. void wxHtmlEntitiesParser::SetEncoding(wxFontEncoding encoding)
  438. {
  439. #if wxUSE_WCHAR_T && !wxUSE_UNICODE
  440.     if (encoding == m_encoding)
  441.         return;
  442.  
  443.     delete m_conv;
  444.  
  445.     m_encoding = encoding;
  446.     if (m_encoding == wxFONTENCODING_SYSTEM)
  447.         m_conv = NULL;
  448.     else
  449.         m_conv = new wxCSConv(wxFontMapper::GetEncodingName(m_encoding));
  450. #else
  451.     (void) encoding;
  452. #endif
  453. }
  454.  
  455. wxString wxHtmlEntitiesParser::Parse(const wxString& input)
  456. {
  457.     const wxChar *c, *last;
  458.     const wxChar *in_str = input.c_str();
  459.     wxString output;
  460.     
  461.     output.reserve(input.length());
  462.  
  463.     for (c = in_str, last = in_str; *c != wxT('\0'); c++)
  464.     {
  465.         if (*c == wxT('&'))
  466.         {
  467.             if (c - last > 0)
  468.                 output.append(last, c - last);
  469.             if (++c == wxT('\0')) break;
  470.         
  471.             wxString entity;
  472.             const wxChar *ent_s = c;
  473.             wxChar entity_char;
  474.         
  475.             for (; (*c >= wxT('a') && *c <= wxT('z')) ||
  476.                    (*c >= wxT('A') && *c <= wxT('Z')) ||
  477.                    (*c >= wxT('0') && *c <= wxT('9')) ||
  478.                    *c == wxT('_') || *c == wxT('#'); c++) {}
  479.             entity.append(ent_s, c - ent_s);
  480.             if (*c != wxT(';')) c--;
  481.             last = c+1;
  482.             entity_char = GetEntityChar(entity);
  483.             if (entity_char)
  484.                 output << entity_char;
  485.             else
  486.             {
  487.                 output.append(ent_s-1, c-ent_s+2);
  488.                 wxLogDebug(wxT("Unrecognized HTML entity: '%s'"), entity.c_str());
  489.             }
  490.         }
  491.     }
  492.     if (*last != wxT('\0'))
  493.         output.append(last);
  494.     return output;
  495. }
  496.  
  497. struct wxHtmlEntityInfo
  498. {
  499.     const wxChar *name;
  500.     unsigned code;
  501. };
  502.  
  503. extern "C" int LINKAGEMODE wxHtmlEntityCompare(const void *key, const void *item)
  504. {
  505.     return wxStrcmp((wxChar*)key, ((wxHtmlEntityInfo*)item)->name);
  506. }
  507.  
  508. #if !wxUSE_UNICODE
  509. wxChar wxHtmlEntitiesParser::GetCharForCode(unsigned code)
  510. {
  511. #if wxUSE_WCHAR_T
  512.     char buf[2];
  513.     wchar_t wbuf[2];
  514.     wbuf[0] = (wchar_t)code;
  515.     wbuf[1] = 0;
  516.     wxMBConv *conv = m_conv ? m_conv : &wxConvLocal;
  517.     if (conv->WC2MB(buf, wbuf, 2) == (size_t)-1)
  518.         return '?';
  519.     return buf[0];
  520. #else
  521.     return (code < 256) ? (wxChar)code : '?';
  522. #endif
  523. }
  524. #endif
  525.  
  526. wxChar wxHtmlEntitiesParser::GetEntityChar(const wxString& entity)
  527. {
  528.     unsigned code = 0;
  529.  
  530.     if (entity[0] == wxT('#'))
  531.     {
  532.         const wxChar *ent_s = entity.c_str();
  533.         const wxChar *format;
  534.  
  535.         if (ent_s[1] == wxT('x') || ent_s[1] == wxT('X'))
  536.         {
  537.             format = wxT("%x");
  538.             ent_s++;
  539.         }
  540.         else
  541.             format = wxT("%u");
  542.         ent_s++;
  543.  
  544.         if (wxSscanf(ent_s, format, &code) != 1)
  545.             code = 0;
  546.     }
  547.     else
  548.     {
  549.         static wxHtmlEntityInfo substitutions[] = {
  550.             { wxT("AElig"),198 },
  551.             { wxT("Aacute"),193 },
  552.             { wxT("Acirc"),194 },
  553.             { wxT("Agrave"),192 },
  554.             { wxT("Alpha"),913 },
  555.             { wxT("Aring"),197 },
  556.             { wxT("Atilde"),195 },
  557.             { wxT("Auml"),196 },
  558.             { wxT("Beta"),914 },
  559.             { wxT("Ccedil"),199 },
  560.             { wxT("Chi"),935 },
  561.             { wxT("Dagger"),8225 },
  562.             { wxT("Delta"),916 },
  563.             { wxT("ETH"),208 },
  564.             { wxT("Eacute"),201 },
  565.             { wxT("Ecirc"),202 },
  566.             { wxT("Egrave"),200 },
  567.             { wxT("Epsilon"),917 },
  568.             { wxT("Eta"),919 },
  569.             { wxT("Euml"),203 },
  570.             { wxT("Gamma"),915 },
  571.             { wxT("Iacute"),205 },
  572.             { wxT("Icirc"),206 },
  573.             { wxT("Igrave"),204 },
  574.             { wxT("Iota"),921 },
  575.             { wxT("Iuml"),207 },
  576.             { wxT("Kappa"),922 },
  577.             { wxT("Lambda"),923 },
  578.             { wxT("Mu"),924 },
  579.             { wxT("Ntilde"),209 },
  580.             { wxT("Nu"),925 },
  581.             { wxT("OElig"),338 },
  582.             { wxT("Oacute"),211 },
  583.             { wxT("Ocirc"),212 },
  584.             { wxT("Ograve"),210 },
  585.             { wxT("Omega"),937 },
  586.             { wxT("Omicron"),927 },
  587.             { wxT("Oslash"),216 },
  588.             { wxT("Otilde"),213 },
  589.             { wxT("Ouml"),214 },
  590.             { wxT("Phi"),934 },
  591.             { wxT("Pi"),928 },
  592.             { wxT("Prime"),8243 },
  593.             { wxT("Psi"),936 },
  594.             { wxT("Rho"),929 },
  595.             { wxT("Scaron"),352 },
  596.             { wxT("Sigma"),931 },
  597.             { wxT("THORN"),222 },
  598.             { wxT("Tau"),932 },
  599.             { wxT("Theta"),920 },
  600.             { wxT("Uacute"),218 },
  601.             { wxT("Ucirc"),219 },
  602.             { wxT("Ugrave"),217 },
  603.             { wxT("Upsilon"),933 },
  604.             { wxT("Uuml"),220 },
  605.             { wxT("Xi"),926 },
  606.             { wxT("Yacute"),221 },
  607.             { wxT("Yuml"),376 },
  608.             { wxT("Zeta"),918 },
  609.             { wxT("aacute"),225 },
  610.             { wxT("acirc"),226 },
  611.             { wxT("acute"),180 },
  612.             { wxT("aelig"),230 },
  613.             { wxT("agrave"),224 },
  614.             { wxT("alefsym"),8501 },
  615.             { wxT("alpha"),945 },
  616.             { wxT("amp"),38 },
  617.             { wxT("and"),8743 },
  618.             { wxT("ang"),8736 },
  619.             { wxT("aring"),229 },
  620.             { wxT("asymp"),8776 },
  621.             { wxT("atilde"),227 },
  622.             { wxT("auml"),228 },
  623.             { wxT("bdquo"),8222 },
  624.             { wxT("beta"),946 },
  625.             { wxT("brvbar"),166 },
  626.             { wxT("bull"),8226 },
  627.             { wxT("cap"),8745 },
  628.             { wxT("ccedil"),231 },
  629.             { wxT("cedil"),184 },
  630.             { wxT("cent"),162 },
  631.             { wxT("chi"),967 },
  632.             { wxT("circ"),710 },
  633.             { wxT("clubs"),9827 },
  634.             { wxT("cong"),8773 },
  635.             { wxT("copy"),169 },
  636.             { wxT("crarr"),8629 },
  637.             { wxT("cup"),8746 },
  638.             { wxT("curren"),164 },
  639.             { wxT("dArr"),8659 },
  640.             { wxT("dagger"),8224 },
  641.             { wxT("darr"),8595 },
  642.             { wxT("deg"),176 },
  643.             { wxT("delta"),948 },
  644.             { wxT("diams"),9830 },
  645.             { wxT("divide"),247 },
  646.             { wxT("eacute"),233 },
  647.             { wxT("ecirc"),234 },
  648.             { wxT("egrave"),232 },
  649.             { wxT("empty"),8709 },
  650.             { wxT("emsp"),8195 },
  651.             { wxT("ensp"),8194 },
  652.             { wxT("epsilon"),949 },
  653.             { wxT("equiv"),8801 },
  654.             { wxT("eta"),951 },
  655.             { wxT("eth"),240 },
  656.             { wxT("euml"),235 },
  657.             { wxT("euro"),8364 },
  658.             { wxT("exist"),8707 },
  659.             { wxT("fnof"),402 },
  660.             { wxT("forall"),8704 },
  661.             { wxT("frac12"),189 },
  662.             { wxT("frac14"),188 },
  663.             { wxT("frac34"),190 },
  664.             { wxT("frasl"),8260 },
  665.             { wxT("gamma"),947 },
  666.             { wxT("ge"),8805 },
  667.             { wxT("gt"),62 },
  668.             { wxT("hArr"),8660 },
  669.             { wxT("harr"),8596 },
  670.             { wxT("hearts"),9829 },
  671.             { wxT("hellip"),8230 },
  672.             { wxT("iacute"),237 },
  673.             { wxT("icirc"),238 },
  674.             { wxT("iexcl"),161 },
  675.             { wxT("igrave"),236 },
  676.             { wxT("image"),8465 },
  677.             { wxT("infin"),8734 },
  678.             { wxT("int"),8747 },
  679.             { wxT("iota"),953 },
  680.             { wxT("iquest"),191 },
  681.             { wxT("isin"),8712 },
  682.             { wxT("iuml"),239 },
  683.             { wxT("kappa"),954 },
  684.             { wxT("lArr"),8656 },
  685.             { wxT("lambda"),955 },
  686.             { wxT("lang"),9001 },
  687.             { wxT("laquo"),171 },
  688.             { wxT("larr"),8592 },
  689.             { wxT("lceil"),8968 },
  690.             { wxT("ldquo"),8220 },
  691.             { wxT("le"),8804 },
  692.             { wxT("lfloor"),8970 },
  693.             { wxT("lowast"),8727 },
  694.             { wxT("loz"),9674 },
  695.             { wxT("lrm"),8206 },
  696.             { wxT("lsaquo"),8249 },
  697.             { wxT("lsquo"),8216 },
  698.             { wxT("lt"),60 },
  699.             { wxT("macr"),175 },
  700.             { wxT("mdash"),8212 },
  701.             { wxT("micro"),181 },
  702.             { wxT("middot"),183 },
  703.             { wxT("minus"),8722 },
  704.             { wxT("mu"),956 },
  705.             { wxT("nabla"),8711 },
  706.             { wxT("nbsp"),160 },
  707.             { wxT("ndash"),8211 },
  708.             { wxT("ne"),8800 },
  709.             { wxT("ni"),8715 },
  710.             { wxT("not"),172 },
  711.             { wxT("notin"),8713 },
  712.             { wxT("nsub"),8836 },
  713.             { wxT("ntilde"),241 },
  714.             { wxT("nu"),957 },
  715.             { wxT("oacute"),243 },
  716.             { wxT("ocirc"),244 },
  717.             { wxT("oelig"),339 },
  718.             { wxT("ograve"),242 },
  719.             { wxT("oline"),8254 },
  720.             { wxT("omega"),969 },
  721.             { wxT("omicron"),959 },
  722.             { wxT("oplus"),8853 },
  723.             { wxT("or"),8744 },
  724.             { wxT("ordf"),170 },
  725.             { wxT("ordm"),186 },
  726.             { wxT("oslash"),248 },
  727.             { wxT("otilde"),245 },
  728.             { wxT("otimes"),8855 },
  729.             { wxT("ouml"),246 },
  730.             { wxT("para"),182 },
  731.             { wxT("part"),8706 },
  732.             { wxT("permil"),8240 },
  733.             { wxT("perp"),8869 },
  734.             { wxT("phi"),966 },
  735.             { wxT("pi"),960 },
  736.             { wxT("piv"),982 },
  737.             { wxT("plusmn"),177 },
  738.             { wxT("pound"),163 },
  739.             { wxT("prime"),8242 },
  740.             { wxT("prod"),8719 },
  741.             { wxT("prop"),8733 },
  742.             { wxT("psi"),968 },
  743.             { wxT("quot"),34 },
  744.             { wxT("rArr"),8658 },
  745.             { wxT("radic"),8730 },
  746.             { wxT("rang"),9002 },
  747.             { wxT("raquo"),187 },
  748.             { wxT("rarr"),8594 },
  749.             { wxT("rceil"),8969 },
  750.             { wxT("rdquo"),8221 },
  751.             { wxT("real"),8476 },
  752.             { wxT("reg"),174 },
  753.             { wxT("rfloor"),8971 },
  754.             { wxT("rho"),961 },
  755.             { wxT("rlm"),8207 },
  756.             { wxT("rsaquo"),8250 },
  757.             { wxT("rsquo"),8217 },
  758.             { wxT("sbquo"),8218 },
  759.             { wxT("scaron"),353 },
  760.             { wxT("sdot"),8901 },
  761.             { wxT("sect"),167 },
  762.             { wxT("shy"),173 },
  763.             { wxT("sigma"),963 },
  764.             { wxT("sigmaf"),962 },
  765.             { wxT("sim"),8764 },
  766.             { wxT("spades"),9824 },
  767.             { wxT("sub"),8834 },
  768.             { wxT("sube"),8838 },
  769.             { wxT("sum"),8721 },
  770.             { wxT("sup"),8835 },
  771.             { wxT("sup1"),185 },
  772.             { wxT("sup2"),178 },
  773.             { wxT("sup3"),179 },
  774.             { wxT("supe"),8839 },
  775.             { wxT("szlig"),223 },
  776.             { wxT("tau"),964 },
  777.             { wxT("there4"),8756 },
  778.             { wxT("theta"),952 },
  779.             { wxT("thetasym"),977 },
  780.             { wxT("thinsp"),8201 },
  781.             { wxT("thorn"),254 },
  782.             { wxT("tilde"),732 },
  783.             { wxT("times"),215 },
  784.             { wxT("trade"),8482 },
  785.             { wxT("uArr"),8657 },
  786.             { wxT("uacute"),250 },
  787.             { wxT("uarr"),8593 },
  788.             { wxT("ucirc"),251 },
  789.             { wxT("ugrave"),249 },
  790.             { wxT("uml"),168 },
  791.             { wxT("upsih"),978 },
  792.             { wxT("upsilon"),965 },
  793.             { wxT("uuml"),252 },
  794.             { wxT("weierp"),8472 },
  795.             { wxT("xi"),958 },
  796.             { wxT("yacute"),253 },
  797.             { wxT("yen"),165 },
  798.             { wxT("yuml"),255 },
  799.             { wxT("zeta"),950 },
  800.             { wxT("zwj"),8205 },
  801.             { wxT("zwnj"),8204 },
  802.             {NULL, 0}};
  803.         static size_t substitutions_cnt = 0;
  804.  
  805.         if (substitutions_cnt == 0)
  806.             while (substitutions[substitutions_cnt].code != 0)
  807.                 substitutions_cnt++;
  808.  
  809.         wxHtmlEntityInfo *info;
  810.         info = (wxHtmlEntityInfo*) bsearch(entity.c_str(), substitutions,
  811.                                            substitutions_cnt,
  812.                                            sizeof(wxHtmlEntityInfo),
  813.                                            wxHtmlEntityCompare);
  814.         if (info)
  815.             code = info->code;
  816.     }
  817.  
  818.     if (code == 0)
  819.         return 0;
  820.     else
  821.         return GetCharForCode(code);
  822. }
  823.  
  824. wxFSFile *wxHtmlParser::OpenURL(wxHtmlURLType WXUNUSED(type), 
  825.                                 const wxString& url) const
  826. {
  827.     return GetFS()->OpenFile(url);
  828. }
  829.  
  830.  
  831. //-----------------------------------------------------------------------------
  832. // wxHtmlParser::ExtractCharsetInformation
  833. //-----------------------------------------------------------------------------
  834.  
  835. class wxMetaTagParser : public wxHtmlParser
  836. {
  837. public:
  838.     wxObject* GetProduct() { return NULL; }
  839. protected:
  840.     virtual void AddText(const wxChar* WXUNUSED(txt)) {}
  841. };
  842.  
  843. class wxMetaTagHandler : public wxHtmlTagHandler
  844. {
  845. public:
  846.     wxMetaTagHandler(wxString *retval) : wxHtmlTagHandler(), m_retval(retval) {}
  847.     wxString GetSupportedTags() { return wxT("META,BODY"); }
  848.     bool HandleTag(const wxHtmlTag& tag);
  849.  
  850. private:
  851.     wxString *m_retval;
  852. };
  853.  
  854. bool wxMetaTagHandler::HandleTag(const wxHtmlTag& tag)
  855. {
  856.     if (tag.GetName() == _T("BODY"))
  857.     {
  858.         m_Parser->StopParsing();
  859.         return FALSE;
  860.     }
  861.  
  862.     if (tag.HasParam(_T("HTTP-EQUIV")) &&
  863.         tag.GetParam(_T("HTTP-EQUIV")) == _T("Content-Type") &&
  864.         tag.HasParam(_T("CONTENT")))
  865.     {
  866.         wxString content = tag.GetParam(_T("CONTENT"));
  867.         if (content.Left(19) == _T("text/html; charset="))
  868.         {
  869.             *m_retval = content.Mid(19);
  870.             m_Parser->StopParsing();
  871.         }
  872.     }
  873.     return FALSE;
  874. }
  875.  
  876.  
  877. /*static*/
  878. wxString wxHtmlParser::ExtractCharsetInformation(const wxString& markup)
  879. {
  880.     wxString charset;
  881.     wxMetaTagParser parser;
  882.     parser.AddTagHandler(new wxMetaTagHandler(&charset));
  883.     parser.Parse(markup);
  884.     return charset;
  885. }
  886.  
  887.  
  888. #endif
  889.