X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/eaf1a1d902a3cd03125452667c50957a73aa237f..c5c04fabb02c27bcc8115bff024d74ddd48f8175:/src/html/htmlpars.cpp?ds=sidebyside diff --git a/src/html/htmlpars.cpp b/src/html/htmlpars.cpp index 31bc825d5c..ac2fc44880 100644 --- a/src/html/htmlpars.cpp +++ b/src/html/htmlpars.cpp @@ -9,7 +9,7 @@ #ifdef __GNUG__ -#pragma implementation +#pragma implementation "htmlpars.h" #endif #include "wx/wxprec.h" @@ -17,7 +17,7 @@ #include "wx/defs.h" #if wxUSE_HTML && wxUSE_STREAMS -#ifdef __BORDLANDC__ +#ifdef __BORLANDC__ #pragma hdrstop #endif @@ -80,8 +80,9 @@ wxHtmlParser::wxHtmlParser() wxHtmlParser::~wxHtmlParser() { - while (RestoreState()) - DestroyDOMTree(); + while (RestoreState()) {} + DestroyDOMTree(); + delete m_HandlersStack; m_HandlersHash.Clear(); m_HandlersList.DeleteContents(TRUE); @@ -91,11 +92,9 @@ wxHtmlParser::~wxHtmlParser() wxObject* wxHtmlParser::Parse(const wxString& source) { - wxObject *result; - InitParser(source); DoParsing(); - result = GetProduct(); + wxObject *result = GetProduct(); DoneParser(); return result; } @@ -103,6 +102,7 @@ wxObject* wxHtmlParser::Parse(const wxString& source) void wxHtmlParser::InitParser(const wxString& source) { SetSource(source); + m_stopParsing = FALSE; } void wxHtmlParser::DoneParser() @@ -127,6 +127,8 @@ void wxHtmlParser::CreateDOMTree() m_CurTextPiece = 0; } +extern bool wxIsCDATAElement(const wxChar *tag); + void wxHtmlParser::CreateDOMSubTree(wxHtmlTag *cur, int begin_pos, int end_pos, wxHtmlTagsCache *cache) @@ -136,7 +138,16 @@ void wxHtmlParser::CreateDOMSubTree(wxHtmlTag *cur, wxChar c; int i = begin_pos; int textBeginning = begin_pos; - + + // If the tag contains CDATA text, we include the text between beginning + // and ending tag verbosely. Setting i=end_pos will skip to the very + // end of this function where text piece is added, bypassing any child + // tags parsing (CDATA element can't have child elements by definition): + if (cur != NULL && wxIsCDATAElement(cur->GetName().c_str())) + { + i = end_pos; + } + while (i < end_pos) { c = m_Source.GetChar(i); @@ -160,7 +171,7 @@ void wxHtmlParser::CreateDOMSubTree(wxHtmlTag *cur, while (i < end_pos) { c = m_Source.GetChar(i++); - if ((c == wxT(' ') || c == wxT('\n') || + if ((c == wxT(' ') || c == wxT('\n') || c == wxT('\r') || c == wxT('\t')) && dashes >= 2) {} else if (c == wxT('>') && dashes >= 2) { @@ -169,31 +180,31 @@ void wxHtmlParser::CreateDOMSubTree(wxHtmlTag *cur, } else if (c == wxT('-')) dashes++; - else + else dashes = 0; } } - + // add another tag to the tree: else if (i < end_pos-1 && m_Source.GetChar(i+1) != wxT('/')) { wxHtmlTag *chd; - if (cur) - chd = new wxHtmlTag(cur, m_Source, + if (cur) + chd = new wxHtmlTag(cur, m_Source, i, end_pos, cache, m_entitiesParser); - else + else { chd = new wxHtmlTag(NULL, m_Source, i, end_pos, cache, m_entitiesParser); - if (!m_Tags) + if (!m_Tags) { - // if this is the first tag to be created make the root + // if this is the first tag to be created make the root // m_Tags point to it: m_Tags = chd; } else { - // if there is already a root tag add this tag as + // if there is already a root tag add this tag as // the last sibling: chd->m_Prev = m_Tags->GetLastSibling(); chd->m_Prev->m_Next = chd; @@ -203,17 +214,18 @@ void wxHtmlParser::CreateDOMSubTree(wxHtmlTag *cur, if (chd->HasEnding()) { CreateDOMSubTree(chd, - chd->GetBeginPos(), chd->GetEndPos1(), + chd->GetBeginPos(), chd->GetEndPos1(), cache); i = chd->GetEndPos2(); } else i = chd->GetBeginPos(); + textBeginning = i; } // ... or skip ending tag: - else + else { while (i < end_pos && m_Source.GetChar(i) != wxT('>')) i++; textBeginning = i+1; @@ -244,36 +256,37 @@ void wxHtmlParser::DestroyDOMTree() m_TextPieces = NULL; } -void wxHtmlParser::DoParsing() +void wxHtmlParser::DoParsing() { m_CurTag = m_Tags; m_CurTextPiece = 0; - DoParsing(0, m_Source.Length()); + DoParsing(0, m_Source.Length()); } void wxHtmlParser::DoParsing(int begin_pos, int end_pos) { if (end_pos <= begin_pos) return; - + wxHtmlTextPieces& pieces = *m_TextPieces; size_t piecesCnt = pieces.GetCount(); - + while (begin_pos < end_pos) { while (m_CurTag && m_CurTag->GetBeginPos() < begin_pos) m_CurTag = m_CurTag->GetNextTag(); - while (m_CurTextPiece < piecesCnt && + while (m_CurTextPiece < piecesCnt && pieces[m_CurTextPiece].m_pos < begin_pos) m_CurTextPiece++; - if (m_CurTextPiece < piecesCnt && - (!m_CurTag || + if (m_CurTextPiece < piecesCnt && + (!m_CurTag || pieces[m_CurTextPiece].m_pos < m_CurTag->GetBeginPos())) { // Add text: - AddText(m_Source.Mid(pieces[m_CurTextPiece].m_pos, - pieces[m_CurTextPiece].m_lng)); - begin_pos = pieces[m_CurTextPiece].m_pos + + AddText(GetEntitiesParser()->Parse( + m_Source.Mid(pieces[m_CurTextPiece].m_pos, + pieces[m_CurTextPiece].m_lng))); + begin_pos = pieces[m_CurTextPiece].m_pos + pieces[m_CurTextPiece].m_lng; m_CurTextPiece++; } @@ -284,12 +297,14 @@ void wxHtmlParser::DoParsing(int begin_pos, int end_pos) { if (m_CurTag->HasEnding()) begin_pos = m_CurTag->GetEndPos2(); - else + else begin_pos = m_CurTag->GetBeginPos(); } wxHtmlTag *t = m_CurTag; m_CurTag = m_CurTag->GetNextTag(); AddTag(*t); + if (m_stopParsing) + return; } else break; } @@ -302,7 +317,11 @@ void wxHtmlParser::AddTag(const wxHtmlTag& tag) h = (wxHtmlTagHandler*) m_HandlersHash.Get(tag.GetName()); if (h) + { inner = h->HandleTag(tag); + if (m_stopParsing) + return; + } if (!inner) { if (tag.HasEnding()) @@ -316,7 +335,7 @@ void wxHtmlParser::AddTagHandler(wxHtmlTagHandler *handler) wxStringTokenizer tokenizer(s, wxT(", ")); while (tokenizer.HasMoreTokens()) - m_HandlersHash.Put(tokenizer.NextToken(), handler); + m_HandlersHash.Put(tokenizer.GetNextToken(), handler); if (m_HandlersList.IndexOf(handler) == wxNOT_FOUND) m_HandlersList.Append(handler); @@ -339,7 +358,7 @@ void wxHtmlParser::PushTagHandler(wxHtmlTagHandler *handler, wxString tags) while (tokenizer.HasMoreTokens()) { - key = tokenizer.NextToken(); + key = tokenizer.GetNextToken(); m_HandlersHash.Delete(key); m_HandlersHash.Put(key, handler); } @@ -377,23 +396,25 @@ void wxHtmlParser::SetSourceAndSaveState(const wxString& src) m_TextPieces = NULL; m_CurTextPiece = 0; m_Source = wxEmptyString; - + SetSource(src); } bool wxHtmlParser::RestoreState() { if (!m_SavedStates) return FALSE; - + + DestroyDOMTree(); + wxHtmlParserState *s = m_SavedStates; m_SavedStates = s->m_nextState; - + m_CurTag = s->m_curTag; m_Tags = s->m_tags; m_TextPieces = s->m_textPieces; m_CurTextPiece = s->m_curTextPiece; m_Source = s->m_source; - + delete s; return TRUE; } @@ -428,12 +449,18 @@ wxHtmlEntitiesParser::~wxHtmlEntitiesParser() void wxHtmlEntitiesParser::SetEncoding(wxFontEncoding encoding) { #if wxUSE_WCHAR_T && !wxUSE_UNICODE - if (encoding == m_encoding) return; + if (encoding == m_encoding) + return; + delete m_conv; - m_conv = NULL; + m_encoding = encoding; - if (m_encoding != wxFONTENCODING_SYSTEM) + if (m_encoding == wxFONTENCODING_SYSTEM) + m_conv = NULL; + else m_conv = new wxCSConv(wxFontMapper::GetEncodingName(m_encoding)); +#else + (void) encoding; #endif } @@ -442,6 +469,8 @@ wxString wxHtmlEntitiesParser::Parse(const wxString& input) const wxChar *c, *last; const wxChar *in_str = input.c_str(); wxString output; + + output.reserve(input.length()); for (c = in_str, last = in_str; *c != wxT('\0'); c++) { @@ -450,8 +479,11 @@ wxString wxHtmlEntitiesParser::Parse(const wxString& input) if (c - last > 0) output.append(last, c - last); if (++c == wxT('\0')) break; + wxString entity; const wxChar *ent_s = c; + wxChar entity_char; + for (; (*c >= wxT('a') && *c <= wxT('z')) || (*c >= wxT('A') && *c <= wxT('Z')) || (*c >= wxT('0') && *c <= wxT('9')) || @@ -459,7 +491,14 @@ wxString wxHtmlEntitiesParser::Parse(const wxString& input) entity.append(ent_s, c - ent_s); if (*c != wxT(';')) c--; last = c+1; - output << GetEntityChar(entity); + entity_char = GetEntityChar(entity); + if (entity_char) + output << entity_char; + else + { + output.append(ent_s-1, c-ent_s+2); + wxLogDebug(wxT("Unrecognized HTML entity: '%s'"), entity.c_str()); + } } } if (*last != wxT('\0')) @@ -473,16 +512,15 @@ struct wxHtmlEntityInfo unsigned code; }; -static int LINKAGEMODE compar_entity(const void *key, const void *item) +extern "C" int LINKAGEMODE wxHtmlEntityCompare(const void *key, const void *item) { return wxStrcmp((wxChar*)key, ((wxHtmlEntityInfo*)item)->name); } +#if !wxUSE_UNICODE wxChar wxHtmlEntitiesParser::GetCharForCode(unsigned code) { -#if wxUSE_UNICODE - return (wxChar)code; -#elif wxUSE_WCHAR_T +#if wxUSE_WCHAR_T char buf[2]; wchar_t wbuf[2]; wbuf[0] = (wchar_t)code; @@ -495,6 +533,7 @@ wxChar wxHtmlEntitiesParser::GetCharForCode(unsigned code) return (code < 256) ? (wxChar)code : '?'; #endif } +#endif wxChar wxHtmlEntitiesParser::GetEntityChar(const wxString& entity) { @@ -783,15 +822,79 @@ wxChar wxHtmlEntitiesParser::GetEntityChar(const wxString& entity) info = (wxHtmlEntityInfo*) bsearch(entity.c_str(), substitutions, substitutions_cnt, sizeof(wxHtmlEntityInfo), - compar_entity); + wxHtmlEntityCompare); if (info) code = info->code; } if (code == 0) - return wxT('?'); + return 0; else return GetCharForCode(code); } +wxFSFile *wxHtmlParser::OpenURL(wxHtmlURLType WXUNUSED(type), + const wxString& url) const +{ + return GetFS()->OpenFile(url); +} + + +//----------------------------------------------------------------------------- +// wxHtmlParser::ExtractCharsetInformation +//----------------------------------------------------------------------------- + +class wxMetaTagParser : public wxHtmlParser +{ +public: + wxObject* GetProduct() { return NULL; } +protected: + virtual void AddText(const wxChar* WXUNUSED(txt)) {} +}; + +class wxMetaTagHandler : public wxHtmlTagHandler +{ +public: + wxMetaTagHandler(wxString *retval) : wxHtmlTagHandler(), m_retval(retval) {} + wxString GetSupportedTags() { return wxT("META,BODY"); } + bool HandleTag(const wxHtmlTag& tag); + +private: + wxString *m_retval; +}; + +bool wxMetaTagHandler::HandleTag(const wxHtmlTag& tag) +{ + if (tag.GetName() == _T("BODY")) + { + m_Parser->StopParsing(); + return FALSE; + } + + if (tag.HasParam(_T("HTTP-EQUIV")) && + tag.GetParam(_T("HTTP-EQUIV")) == _T("Content-Type") && + tag.HasParam(_T("CONTENT"))) + { + wxString content = tag.GetParam(_T("CONTENT")); + if (content.Left(19) == _T("text/html; charset=")) + { + *m_retval = content.Mid(19); + m_Parser->StopParsing(); + } + } + return FALSE; +} + + +/*static*/ +wxString wxHtmlParser::ExtractCharsetInformation(const wxString& markup) +{ + wxString charset; + wxMetaTagParser parser; + parser.AddTagHandler(new wxMetaTagHandler(&charset)); + parser.Parse(markup); + return charset; +} + + #endif