1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/html/helpdata.cpp
3 // Purpose: wxHtmlHelpData
4 // Notes: Based on htmlhelp.cpp, implementing a monolithic
5 // HTML Help controller class, by Vaclav Slavik
6 // Author: Harm van der Heijden and Vaclav Slavik
7 // Copyright: (c) Harm van der Heijden and Vaclav Slavik
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
18 #if wxUSE_HTML && wxUSE_STREAMS
27 #include "wx/html/helpdata.h"
28 #include "wx/tokenzr.h"
29 #include "wx/wfstream.h"
30 #include "wx/busyinfo.h"
31 #include "wx/encconv.h"
32 #include "wx/fontmap.h"
33 #include "wx/html/htmlpars.h"
34 #include "wx/html/htmldefs.h"
35 #include "wx/html/htmlfilt.h"
36 #include "wx/filename.h"
38 #include "wx/arrimpl.cpp"
39 WX_DEFINE_OBJARRAY(wxHtmlBookRecArray
)
40 WX_DEFINE_OBJARRAY(wxHtmlHelpDataItems
)
42 //-----------------------------------------------------------------------------
43 // static helper functions
44 //-----------------------------------------------------------------------------
46 // Reads one line, stores it into buf and returns pointer to new line or NULL.
47 static const wxChar
* ReadLine(const wxChar
*line
, wxChar
*buf
, size_t bufsize
)
49 wxChar
*writeptr
= buf
;
50 wxChar
*endptr
= buf
+ bufsize
- 1;
51 const wxChar
*readptr
= line
;
53 while (*readptr
!= 0 && *readptr
!= wxT('\r') && *readptr
!= wxT('\n') &&
55 *(writeptr
++) = *(readptr
++);
57 while (*readptr
== wxT('\r') || *readptr
== wxT('\n'))
68 wxHtmlHelpIndexCompareFunc(wxHtmlHelpDataItem
**a
, wxHtmlHelpDataItem
**b
)
70 wxHtmlHelpDataItem
*ia
= *a
;
71 wxHtmlHelpDataItem
*ib
= *b
;
78 if (ia
->parent
== ib
->parent
)
80 return ia
->name
.CmpNoCase(ib
->name
);
82 else if (ia
->level
== ib
->level
)
84 return wxHtmlHelpIndexCompareFunc(&ia
->parent
, &ib
->parent
);
88 wxHtmlHelpDataItem
*ia2
= ia
;
89 wxHtmlHelpDataItem
*ib2
= ib
;
91 while (ia2
->level
> ib2
->level
)
95 while (ib2
->level
> ia2
->level
)
102 int res
= wxHtmlHelpIndexCompareFunc(&ia2
, &ib2
);
105 else if (ia
->level
> ib
->level
)
112 //-----------------------------------------------------------------------------
114 //-----------------------------------------------------------------------------
116 class HP_Parser
: public wxHtmlParser
121 GetEntitiesParser()->SetEncoding(wxFONTENCODING_ISO8859_1
);
124 wxObject
* GetProduct() { return NULL
; }
127 virtual void AddText(const wxString
& WXUNUSED(txt
)) {}
129 wxDECLARE_NO_COPY_CLASS(HP_Parser
);
133 //-----------------------------------------------------------------------------
135 //-----------------------------------------------------------------------------
137 class HP_TagHandler
: public wxHtmlTagHandler
140 wxString m_name
, m_page
;
145 wxHtmlHelpDataItem
*m_parentItem
;
146 wxHtmlBookRecord
*m_book
;
148 wxHtmlHelpDataItems
*m_data
;
151 HP_TagHandler(wxHtmlBookRecord
*b
) : wxHtmlTagHandler()
155 m_name
= m_page
= wxEmptyString
;
161 wxString
GetSupportedTags() { return wxT("UL,OBJECT,PARAM"); }
162 bool HandleTag(const wxHtmlTag
& tag
);
164 void Reset(wxHtmlHelpDataItems
& data
)
172 wxDECLARE_NO_COPY_CLASS(HP_TagHandler
);
176 bool HP_TagHandler::HandleTag(const wxHtmlTag
& tag
)
178 if (tag
.GetName() == wxT("UL"))
180 wxHtmlHelpDataItem
*oldparent
= m_parentItem
;
182 m_parentItem
= (m_count
> 0) ? &(*m_data
)[m_data
->size()-1] : NULL
;
185 m_parentItem
= oldparent
;
188 else if (tag
.GetName() == wxT("OBJECT"))
190 m_name
= m_page
= wxEmptyString
;
195 /* Valid HHW's file may contain only two object tags:
197 <OBJECT type="text/site properties">
198 <param name="ImageType" value="Folder">
203 <OBJECT type="text/sitemap">
204 <param name="Name" value="main page">
205 <param name="Local" value="another.htm">
208 We're interested in the latter. !page.IsEmpty() is valid
209 condition because text/site properties does not contain Local param
212 if (tag
.GetParam(wxT("TYPE")) == wxT("text/sitemap"))
214 wxHtmlHelpDataItem
*item
= new wxHtmlHelpDataItem();
215 item
->parent
= m_parentItem
;
216 item
->level
= m_level
;
230 if (m_name
.empty() && tag
.GetParam(wxT("NAME")) == wxT("Name"))
231 m_name
= tag
.GetParam(wxT("VALUE"));
232 if (tag
.GetParam(wxT("NAME")) == wxT("Local"))
233 m_page
= tag
.GetParam(wxT("VALUE"));
234 if (tag
.GetParam(wxT("NAME")) == wxT("ID"))
235 tag
.GetParamAsInt(wxT("VALUE"), &m_id
);
241 //-----------------------------------------------------------------------------
243 //-----------------------------------------------------------------------------
245 wxString
wxHtmlBookRecord::GetFullPath(const wxString
&page
) const
247 if (wxIsAbsolutePath(page
) || page
.Find(wxT("file:")) == 0)
250 return m_BasePath
+ page
;
253 wxString
wxHtmlHelpDataItem::GetIndentedName() const
256 for (int i
= 1; i
< level
; i
++)
263 IMPLEMENT_DYNAMIC_CLASS(wxHtmlHelpData
, wxObject
)
265 wxHtmlHelpData::wxHtmlHelpData()
269 wxHtmlHelpData::~wxHtmlHelpData()
273 bool wxHtmlHelpData::LoadMSProject(wxHtmlBookRecord
*book
, wxFileSystem
& fsys
,
274 const wxString
& indexfile
,
275 const wxString
& contentsfile
)
278 wxHtmlFilterHTML filter
;
283 HP_TagHandler
*handler
= new HP_TagHandler(book
);
284 parser
.AddTagHandler(handler
);
286 f
= ( contentsfile
.empty() ? NULL
: fsys
.OpenFile(contentsfile
) );
290 buf
= filter
.ReadFile(*f
);
292 handler
->Reset(m_contents
);
297 wxLogError(_("Cannot open contents file: %s"), contentsfile
.c_str());
300 f
= ( indexfile
.empty() ? NULL
: fsys
.OpenFile(indexfile
) );
304 buf
= filter
.ReadFile(*f
);
306 handler
->Reset(m_index
);
309 else if (!indexfile
.empty())
311 wxLogError(_("Cannot open index file: %s"), indexfile
.c_str());
316 inline static void CacheWriteInt32(wxOutputStream
*f
, wxInt32 value
)
318 wxInt32 x
= wxINT32_SWAP_ON_BE(value
);
319 f
->Write(&x
, sizeof(x
));
322 inline static wxInt32
CacheReadInt32(wxInputStream
*f
)
325 f
->Read(&x
, sizeof(x
));
326 return wxINT32_SWAP_ON_BE(x
);
329 inline static void CacheWriteString(wxOutputStream
*f
, const wxString
& str
)
331 const wxWX2MBbuf mbstr
= str
.mb_str(wxConvUTF8
);
332 size_t len
= strlen((const char*)mbstr
)+1;
333 CacheWriteInt32(f
, len
);
334 f
->Write((const char*)mbstr
, len
);
337 inline static wxString
CacheReadString(wxInputStream
*f
)
339 size_t len
= (size_t)CacheReadInt32(f
);
340 wxCharBuffer
str(len
-1);
341 f
->Read(str
.data(), len
);
342 return wxString(str
, wxConvUTF8
);
345 #define CURRENT_CACHED_BOOK_VERSION 5
347 // Additional flags to detect incompatibilities of the runtime environment:
348 #define CACHED_BOOK_FORMAT_FLAGS \
352 bool wxHtmlHelpData::LoadCachedBook(wxHtmlBookRecord
*book
, wxInputStream
*f
)
357 /* load header - version info : */
358 version
= CacheReadInt32(f
);
360 if (version
!= CURRENT_CACHED_BOOK_VERSION
)
362 // NB: We can just silently return false here and don't worry about
363 // it anymore, because AddBookParam will load the MS project in
364 // absence of (properly versioned) .cached file and automatically
365 // create new .cached file immediately afterward.
369 if (CacheReadInt32(f
) != CACHED_BOOK_FORMAT_FLAGS
)
372 /* load contents : */
373 st
= m_contents
.size();
374 newsize
= st
+ CacheReadInt32(f
);
375 m_contents
.Alloc(newsize
);
376 for (i
= st
; i
< newsize
; i
++)
378 wxHtmlHelpDataItem
*item
= new wxHtmlHelpDataItem
;
379 item
->level
= CacheReadInt32(f
);
380 item
->id
= CacheReadInt32(f
);
381 item
->name
= CacheReadString(f
);
382 item
->page
= CacheReadString(f
);
384 m_contents
.Add(item
);
389 newsize
= st
+ CacheReadInt32(f
);
390 m_index
.Alloc(newsize
);
391 for (i
= st
; i
< newsize
; i
++)
393 wxHtmlHelpDataItem
*item
= new wxHtmlHelpDataItem
;
394 item
->name
= CacheReadString(f
);
395 item
->page
= CacheReadString(f
);
396 item
->level
= CacheReadInt32(f
);
398 int parentShift
= CacheReadInt32(f
);
399 if (parentShift
!= 0)
400 item
->parent
= &m_index
[m_index
.size() - parentShift
];
407 bool wxHtmlHelpData::SaveCachedBook(wxHtmlBookRecord
*book
, wxOutputStream
*f
)
412 /* save header - version info : */
413 CacheWriteInt32(f
, CURRENT_CACHED_BOOK_VERSION
);
414 CacheWriteInt32(f
, CACHED_BOOK_FORMAT_FLAGS
);
416 /* save contents : */
417 int len
= m_contents
.size();
418 for (cnt
= 0, i
= 0; i
< len
; i
++)
419 if (m_contents
[i
].book
== book
&& m_contents
[i
].level
> 0)
421 CacheWriteInt32(f
, cnt
);
423 for (i
= 0; i
< len
; i
++)
425 if (m_contents
[i
].book
!= book
|| m_contents
[i
].level
== 0)
427 CacheWriteInt32(f
, m_contents
[i
].level
);
428 CacheWriteInt32(f
, m_contents
[i
].id
);
429 CacheWriteString(f
, m_contents
[i
].name
);
430 CacheWriteString(f
, m_contents
[i
].page
);
434 len
= m_index
.size();
435 for (cnt
= 0, i
= 0; i
< len
; i
++)
436 if (m_index
[i
].book
== book
&& m_index
[i
].level
> 0)
438 CacheWriteInt32(f
, cnt
);
440 for (i
= 0; i
< len
; i
++)
442 if (m_index
[i
].book
!= book
|| m_index
[i
].level
== 0)
444 CacheWriteString(f
, m_index
[i
].name
);
445 CacheWriteString(f
, m_index
[i
].page
);
446 CacheWriteInt32(f
, m_index
[i
].level
);
447 // save distance to parent item, if any:
448 if (m_index
[i
].parent
== NULL
)
450 CacheWriteInt32(f
, 0);
455 wxHtmlHelpDataItem
*parent
= m_index
[i
].parent
;
456 for (int j
= i
-1; j
>= 0; j
--)
458 if (m_index
[j
].book
== book
&& m_index
[j
].level
> 0)
460 if (&m_index
[j
] == parent
)
464 CacheWriteInt32(f
, cnt2
);
471 void wxHtmlHelpData::SetTempDir(const wxString
& path
)
480 m_tempPath
= fn
.GetPath(wxPATH_GET_VOLUME
| wxPATH_GET_SEPARATOR
);
486 static wxString
SafeFileName(const wxString
& s
)
489 res
.Replace(wxT("#"), wxT("_"));
490 res
.Replace(wxT(":"), wxT("_"));
491 res
.Replace(wxT("\\"), wxT("_"));
492 res
.Replace(wxT("/"), wxT("_"));
496 bool wxHtmlHelpData::AddBookParam(const wxFSFile
& bookfile
,
497 wxFontEncoding encoding
,
498 const wxString
& title
, const wxString
& contfile
,
499 const wxString
& indexfile
, const wxString
& deftopic
,
500 const wxString
& path
)
504 #define CORRECT_STR(str, conv) \
505 str = wxString((str).mb_str(wxConvISO8859_1), conv)
507 #define CORRECT_STR(str, conv) \
508 str = wxString((str).wc_str(conv), wxConvLocal)
511 #define CORRECT_STR(str, conv)
516 wxHtmlBookRecord
*bookr
;
518 int IndexOld
= m_index
.size(),
519 ContentsOld
= m_contents
.size();
522 fsys
.ChangePathTo(path
, true);
524 size_t booksCnt
= m_bookRecords
.GetCount();
525 for (size_t i
= 0; i
< booksCnt
; i
++)
527 if ( m_bookRecords
[i
].GetBookFile() == bookfile
.GetLocation() )
528 return true; // book is (was) loaded
531 wxString title1
= title
;
532 if (encoding
!= wxFONTENCODING_SYSTEM
)
534 wxCSConv
conv(encoding
);
535 CORRECT_STR(title1
, conv
);
536 if (title1
.IsEmpty() && !title
.IsEmpty())
540 bookr
= new wxHtmlBookRecord(bookfile
.GetLocation(), fsys
.GetPath(), title1
, deftopic
);
542 wxHtmlHelpDataItem
*bookitem
= new wxHtmlHelpDataItem
;
545 bookitem
->page
= deftopic
;
546 bookitem
->name
= title
;
547 bookitem
->book
= bookr
;
549 // store the contents index for later
550 int cont_start
= m_contents
.size();
552 m_contents
.Add(bookitem
);
554 // Try to find cached binary versions:
555 // 1. save file as book, but with .hhp.cached extension
556 // 2. same as 1. but in temp path
557 // 3. otherwise or if cache load failed, load it from MS.
559 fi
= fsys
.OpenFile(bookfile
.GetLocation() + wxT(".cached"));
563 fi
->GetModificationTime() < bookfile
.GetModificationTime() ||
564 #endif // wxUSE_DATETIME
565 !LoadCachedBook(bookr
, fi
->GetStream()))
567 if (fi
!= NULL
) delete fi
;
568 fi
= fsys
.OpenFile(m_tempPath
+ wxFileNameFromPath(bookfile
.GetLocation()) + wxT(".cached"));
569 if (m_tempPath
.empty() || fi
== NULL
||
571 fi
->GetModificationTime() < bookfile
.GetModificationTime() ||
572 #endif // wxUSE_DATETIME
573 !LoadCachedBook(bookr
, fi
->GetStream()))
575 LoadMSProject(bookr
, fsys
, indexfile
, contfile
);
576 if (!m_tempPath
.empty())
578 wxFileOutputStream
*outs
= new wxFileOutputStream(m_tempPath
+
579 SafeFileName(wxFileNameFromPath(bookfile
.GetLocation())) + wxT(".cached"));
580 SaveCachedBook(bookr
, outs
);
586 if (fi
!= NULL
) delete fi
;
588 // Now store the contents range
589 bookr
->SetContentsRange(cont_start
, m_contents
.size());
591 // MS HTML Help files [written by MS HTML Help Workshop] are broken
592 // in that the data are iso-8859-1 (including HTML entities), but must
593 // be interpreted as being in language's windows charset. Correct the
594 // differences here and also convert to wxConvLocal in ANSI build
595 if (encoding
!= wxFONTENCODING_SYSTEM
)
597 wxCSConv
conv(encoding
);
598 size_t IndexCnt
= m_index
.size();
599 size_t ContentsCnt
= m_contents
.size();
601 for (i
= IndexOld
; i
< IndexCnt
; i
++)
603 CORRECT_STR(m_index
[i
].name
, conv
);
605 for (i
= ContentsOld
; i
< ContentsCnt
; i
++)
607 CORRECT_STR(m_contents
[i
].name
, conv
);
612 m_bookRecords
.Add(bookr
);
613 if (!m_index
.empty())
615 m_index
.Sort(wxHtmlHelpIndexCompareFunc
);
622 bool wxHtmlHelpData::AddBook(const wxString
& book
)
624 wxString
extension(book
.Right(4).Lower());
625 if (extension
== wxT(".zip") ||
627 extension
== wxT(".chm") /*compressed html help book*/ ||
629 extension
== wxT(".htb") /*html book*/)
636 if (extension
== wxT(".chm"))
637 s
= fsys
.FindFirst(book
+ wxT("#chm:*.hhp"), wxFILE
);
640 s
= fsys
.FindFirst(book
+ wxT("#zip:*.hhp"), wxFILE
);
644 if (AddBook(s
)) rt
= true;
654 wxString title
= _("noname"),
656 start
= wxEmptyString
,
657 contents
= wxEmptyString
,
658 index
= wxEmptyString
,
659 charset
= wxEmptyString
;
661 fi
= fsys
.OpenFile(book
);
664 wxLogError(_("Cannot open HTML help book: %s"), book
.c_str());
667 fsys
.ChangePathTo(book
);
669 const wxChar
*lineptr
;
672 wxHtmlFilterPlainText filter
;
673 tmp
= filter
.ReadFile(*fi
);
674 lineptr
= tmp
.c_str();
678 lineptr
= ReadLine(lineptr
, linebuf
, 300);
680 for (wxChar
*ch
= linebuf
; *ch
!= wxT('\0') && *ch
!= wxT('='); ch
++)
681 *ch
= (wxChar
)wxTolower(*ch
);
683 if (wxStrstr(linebuf
, wxT("title=")) == linebuf
)
684 title
= linebuf
+ wxStrlen(wxT("title="));
685 if (wxStrstr(linebuf
, wxT("default topic=")) == linebuf
)
686 start
= linebuf
+ wxStrlen(wxT("default topic="));
687 if (wxStrstr(linebuf
, wxT("index file=")) == linebuf
)
688 index
= linebuf
+ wxStrlen(wxT("index file="));
689 if (wxStrstr(linebuf
, wxT("contents file=")) == linebuf
)
690 contents
= linebuf
+ wxStrlen(wxT("contents file="));
691 if (wxStrstr(linebuf
, wxT("charset=")) == linebuf
)
692 charset
= linebuf
+ wxStrlen(wxT("charset="));
693 } while (lineptr
!= NULL
);
695 wxFontEncoding enc
= wxFONTENCODING_SYSTEM
;
697 if (charset
!= wxEmptyString
)
698 enc
= wxFontMapper::Get()->CharsetToEncoding(charset
);
701 bool rtval
= AddBookParam(*fi
, enc
,
702 title
, contents
, index
, start
, fsys
.GetPath());
708 wxString
wxHtmlHelpData::FindPageByName(const wxString
& x
)
712 bool has_non_ascii
= false;
713 wxString::const_iterator it
;
714 for (it
= x
.begin(); it
!= x
.end(); ++it
)
719 has_non_ascii
= true;
724 int cnt
= m_bookRecords
.GetCount();
730 // 1. try to open given file:
731 for (i
= 0; i
< cnt
; i
++)
733 f
= fsys
.OpenFile(m_bookRecords
[i
].GetFullPath(x
));
736 wxString url
= m_bookRecords
[i
].GetFullPath(x
);
744 // 2. try to find a book:
745 for (i
= 0; i
< cnt
; i
++)
747 if (m_bookRecords
[i
].GetTitle() == x
)
748 return m_bookRecords
[i
].GetFullPath(m_bookRecords
[i
].GetStart());
751 // 3. try to find in contents:
752 cnt
= m_contents
.size();
753 for (i
= 0; i
< cnt
; i
++)
755 if (m_contents
[i
].name
== x
)
756 return m_contents
[i
].GetFullPath();
760 // 4. try to find in index:
761 cnt
= m_index
.size();
762 for (i
= 0; i
< cnt
; i
++)
764 if (m_index
[i
].name
== x
)
765 return m_index
[i
].GetFullPath();
768 // 4b. if still not found, try case-insensitive comparison
769 for (i
= 0; i
< cnt
; i
++)
771 if (m_index
[i
].name
.CmpNoCase(x
) == 0)
772 return m_index
[i
].GetFullPath();
775 return wxEmptyString
;
778 wxString
wxHtmlHelpData::FindPageById(int id
)
780 size_t cnt
= m_contents
.size();
781 for (size_t i
= 0; i
< cnt
; i
++)
783 if (m_contents
[i
].id
== id
)
785 return m_contents
[i
].GetFullPath();
789 return wxEmptyString
;
793 //----------------------------------------------------------------------------------
794 // wxHtmlSearchStatus functions
795 //----------------------------------------------------------------------------------
797 wxHtmlSearchStatus::wxHtmlSearchStatus(wxHtmlHelpData
* data
, const wxString
& keyword
,
798 bool case_sensitive
, bool whole_words_only
,
799 const wxString
& book
)
803 wxHtmlBookRecord
* bookr
= NULL
;
804 if (book
!= wxEmptyString
)
806 // we have to search in a specific book. Find it first
807 int i
, cnt
= data
->m_bookRecords
.GetCount();
808 for (i
= 0; i
< cnt
; i
++)
809 if (data
->m_bookRecords
[i
].GetTitle() == book
)
811 bookr
= &(data
->m_bookRecords
[i
]);
812 m_CurIndex
= bookr
->GetContentsStart();
813 m_MaxIndex
= bookr
->GetContentsEnd();
816 // check; we won't crash if the book doesn't exist, but it's Bad Anyway.
821 // no book specified; search all books
823 m_MaxIndex
= m_Data
->m_contents
.size();
825 m_Engine
.LookFor(keyword
, case_sensitive
, whole_words_only
);
826 m_Active
= (m_CurIndex
< m_MaxIndex
);
829 bool wxHtmlSearchStatus::Search()
832 int i
= m_CurIndex
; // shortcut
838 // sanity check. Illegal use, but we'll try to prevent a crash anyway
843 m_Name
= wxEmptyString
;
845 thepage
= m_Data
->m_contents
[i
].page
;
847 m_Active
= (++m_CurIndex
< m_MaxIndex
);
848 // check if it is same page with different anchor:
849 if (!m_LastPage
.empty())
851 const wxChar
*p1
, *p2
;
852 for (p1
= thepage
.c_str(), p2
= m_LastPage
.c_str();
853 *p1
!= 0 && *p1
!= wxT('#') && *p1
== *p2
; p1
++, p2
++) {}
855 m_LastPage
= thepage
;
857 if (*p1
== 0 || *p1
== wxT('#'))
860 else m_LastPage
= thepage
;
863 file
= fsys
.OpenFile(m_Data
->m_contents
[i
].book
->GetFullPath(thepage
));
866 if (m_Engine
.Scan(*file
))
868 m_Name
= m_Data
->m_contents
[i
].name
;
869 m_CurItem
= &m_Data
->m_contents
[i
];
884 //--------------------------------------------------------------------------------
885 // wxHtmlSearchEngine
886 //--------------------------------------------------------------------------------
888 void wxHtmlSearchEngine::LookFor(const wxString
& keyword
, bool case_sensitive
, bool whole_words_only
)
890 m_CaseSensitive
= case_sensitive
;
891 m_WholeWords
= whole_words_only
;
894 if (!m_CaseSensitive
)
895 m_Keyword
.LowerCase();
899 static inline bool WHITESPACE(wxChar c
)
901 return c
== wxT(' ') || c
== wxT('\n') || c
== wxT('\r') || c
== wxT('\t');
904 // replace continuous spaces by one single space
905 static inline wxString
CompressSpaces(const wxString
& str
)
908 buf
.reserve( str
.size() );
910 bool space_counted
= false;
911 for( const wxChar
* pstr
= str
.c_str(); *pstr
; ++pstr
)
914 if( WHITESPACE( ch
) )
921 space_counted
= true;
925 space_counted
= false;
933 bool wxHtmlSearchEngine::Scan(const wxFSFile
& file
)
935 wxASSERT_MSG(!m_Keyword
.empty(), wxT("wxHtmlSearchEngine::LookFor must be called before scanning!"));
937 wxHtmlFilterHTML filter
;
938 wxString bufStr
= filter
.ReadFile(file
);
940 if (!m_CaseSensitive
)
943 { // remove html tags
945 bufStrCopy
.reserve( bufStr
.size() );
946 bool insideTag
= false;
947 for (const wxChar
* pBufStr
= bufStr
.c_str(); *pBufStr
; ++pBufStr
)
955 // replace the tag by an empty space
961 else if (c
== wxT('<'))
963 wxChar nextCh
= *(pBufStr
+ 1);
964 if (nextCh
== wxT('/') || !WHITESPACE(nextCh
))
972 bufStr
.swap( bufStrCopy
);
975 wxString keyword
= m_Keyword
;
979 // insert ' ' at the beginning and at the end
980 keyword
.insert( 0, wxT(" ") );
981 keyword
.append( wxT(" ") );
982 bufStr
.insert( 0, wxT(" ") );
983 bufStr
.append( wxT(" ") );
986 // remove continuous spaces
987 keyword
= CompressSpaces( keyword
);
988 bufStr
= CompressSpaces( bufStr
);
990 // finally do the search
991 return bufStr
.find( keyword
) != wxString::npos
;