1 /////////////////////////////////////////////////////////////////////////////
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
8 // Copyright: (c) Harm van der Heijden and Vaclav Slavik
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
13 #pragma implementation "helpdata.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
25 #if wxUSE_HTML && wxUSE_STREAMS
34 #include "wx/html/helpdata.h"
35 #include "wx/tokenzr.h"
36 #include "wx/wfstream.h"
37 #include "wx/busyinfo.h"
38 #include "wx/encconv.h"
39 #include "wx/fontmap.h"
41 #include "wx/html/htmlpars.h"
42 #include "wx/html/htmldefs.h"
43 #include "wx/html/htmlfilt.h"
44 #include "wx/filename.h"
46 #include "wx/arrimpl.cpp"
47 WX_DEFINE_OBJARRAY(wxHtmlBookRecArray
)
49 //-----------------------------------------------------------------------------
50 // static helper functions
51 //-----------------------------------------------------------------------------
53 // Reads one line, stores it into buf and returns pointer to new line or NULL.
54 static const wxChar
* ReadLine(const wxChar
*line
, wxChar
*buf
, size_t bufsize
)
56 wxChar
*writeptr
= buf
;
57 wxChar
*endptr
= buf
+ bufsize
- 1;
58 const wxChar
*readptr
= line
;
60 while (*readptr
!= 0 && *readptr
!= _T('\r') && *readptr
!= _T('\n') &&
62 *(writeptr
++) = *(readptr
++);
64 while (*readptr
== _T('\r') || *readptr
== _T('\n'))
74 extern "C" int LINKAGEMODE
75 wxHtmlHelpIndexCompareFunc(const void *a
, const void *b
)
77 return wxStricmp(((wxHtmlContentsItem
*)a
)->m_Name
, ((wxHtmlContentsItem
*)b
)->m_Name
);
81 //-----------------------------------------------------------------------------
83 //-----------------------------------------------------------------------------
85 class HP_Parser
: public wxHtmlParser
90 wxObject
* GetProduct() { return NULL
; }
93 virtual void AddText(const wxChar
* WXUNUSED(txt
)) {}
95 DECLARE_NO_COPY_CLASS(HP_Parser
)
99 //-----------------------------------------------------------------------------
101 //-----------------------------------------------------------------------------
103 class HP_TagHandler
: public wxHtmlTagHandler
106 wxString m_Name
, m_Page
;
110 wxHtmlContentsItem
*m_Items
;
112 wxHtmlBookRecord
*m_Book
;
115 HP_TagHandler(wxHtmlBookRecord
*b
) : wxHtmlTagHandler()
116 { m_Book
= b
; m_Items
= NULL
; m_ItemsCnt
= 0; m_Name
= m_Page
= wxEmptyString
;
117 m_Level
= 0; m_ID
= -1; }
118 wxString
GetSupportedTags() { return wxT("UL,OBJECT,PARAM"); }
119 bool HandleTag(const wxHtmlTag
& tag
);
120 void WriteOut(wxHtmlContentsItem
*& array
, int& size
);
121 void ReadIn(wxHtmlContentsItem
* array
, int size
);
123 DECLARE_NO_COPY_CLASS(HP_TagHandler
)
127 bool HP_TagHandler::HandleTag(const wxHtmlTag
& tag
)
129 if (tag
.GetName() == wxT("UL"))
136 else if (tag
.GetName() == wxT("OBJECT"))
138 m_Name
= m_Page
= wxEmptyString
;
142 if (!m_Page
.IsEmpty())
143 /* Valid HHW's file may contain only two object tags:
145 <OBJECT type="text/site properties">
146 <param name="ImageType" value="Folder">
151 <OBJECT type="text/sitemap">
152 <param name="Name" value="main page">
153 <param name="Local" value="another.htm">
156 We're interested in the latter. !m_Page.IsEmpty() is valid
157 condition because text/site properties does not contain Local param
160 if (tag
.GetParam(wxT("TYPE")) == wxT("text/sitemap"))
162 if (m_ItemsCnt
% wxHTML_REALLOC_STEP
== 0)
163 m_Items
= (wxHtmlContentsItem
*) realloc(m_Items
,
164 (m_ItemsCnt
+ wxHTML_REALLOC_STEP
) *
165 sizeof(wxHtmlContentsItem
));
167 m_Items
[m_ItemsCnt
].m_Level
= m_Level
;
168 m_Items
[m_ItemsCnt
].m_ID
= m_ID
;
169 m_Items
[m_ItemsCnt
].m_Page
= new wxChar
[m_Page
.Length() + 1];
170 wxStrcpy(m_Items
[m_ItemsCnt
].m_Page
, m_Page
.c_str());
171 m_Items
[m_ItemsCnt
].m_Name
= new wxChar
[m_Name
.Length() + 1];
172 wxStrcpy(m_Items
[m_ItemsCnt
].m_Name
, m_Name
.c_str());
173 m_Items
[m_ItemsCnt
].m_Book
= m_Book
;
181 if (m_Name
== wxEmptyString
&& tag
.GetParam(wxT("NAME")) == wxT("Name"))
182 m_Name
= tag
.GetParam(wxT("VALUE"));
183 if (tag
.GetParam(wxT("NAME")) == wxT("Local"))
184 m_Page
= tag
.GetParam(wxT("VALUE"));
185 if (tag
.GetParam(wxT("NAME")) == wxT("ID"))
186 tag
.GetParamAsInt(wxT("VALUE"), &m_ID
);
193 void HP_TagHandler::WriteOut(wxHtmlContentsItem
*& array
, int& size
)
201 void HP_TagHandler::ReadIn(wxHtmlContentsItem
* array
, int size
)
210 //-----------------------------------------------------------------------------
212 //-----------------------------------------------------------------------------
214 wxString
wxHtmlBookRecord::GetFullPath(const wxString
&page
) const
216 if (wxIsAbsolutePath(page
))
219 return m_BasePath
+ page
;
224 IMPLEMENT_DYNAMIC_CLASS(wxHtmlHelpData
, wxObject
)
226 wxHtmlHelpData::wxHtmlHelpData()
228 m_TempPath
= wxEmptyString
;
236 wxHtmlHelpData::~wxHtmlHelpData()
240 m_BookRecords
.Empty();
243 for (i
= 0; i
< m_ContentsCnt
; i
++)
245 delete[] m_Contents
[i
].m_Page
;
246 delete[] m_Contents
[i
].m_Name
;
252 for (i
= 0; i
< m_IndexCnt
; i
++)
254 delete[] m_Index
[i
].m_Page
;
255 delete[] m_Index
[i
].m_Name
;
261 bool wxHtmlHelpData::LoadMSProject(wxHtmlBookRecord
*book
, wxFileSystem
& fsys
, const wxString
& indexfile
, const wxString
& contentsfile
)
264 wxHtmlFilterHTML filter
;
269 HP_TagHandler
*handler
= new HP_TagHandler(book
);
270 parser
.AddTagHandler(handler
);
272 f
= ( contentsfile
.IsEmpty() ? (wxFSFile
*) NULL
: fsys
.OpenFile(contentsfile
) );
276 buf
= filter
.ReadFile(*f
);
278 handler
->ReadIn(m_Contents
, m_ContentsCnt
);
280 handler
->WriteOut(m_Contents
, m_ContentsCnt
);
284 wxLogError(_("Cannot open contents file: %s"), contentsfile
.c_str());
287 f
= ( indexfile
.IsEmpty() ? (wxFSFile
*) NULL
: fsys
.OpenFile(indexfile
) );
291 buf
= filter
.ReadFile(*f
);
293 handler
->ReadIn(m_Index
, m_IndexCnt
);
295 handler
->WriteOut(m_Index
, m_IndexCnt
);
297 else if (!indexfile
.IsEmpty())
299 wxLogError(_("Cannot open index file: %s"), indexfile
.c_str());
306 inline static void CacheWriteInt32(wxOutputStream
*f
, wxInt32 value
)
308 wxInt32 x
= wxINT32_SWAP_ON_BE(value
);
309 f
->Write(&x
, sizeof(x
));
312 inline static wxInt32
CacheReadInt32(wxInputStream
*f
)
315 f
->Read(&x
, sizeof(x
));
316 return wxINT32_SWAP_ON_BE(x
);
319 inline static void CacheWriteString(wxOutputStream
*f
, const wxChar
*str
)
322 wxWX2MBbuf
mbstr(wxConvUTF8
.cWX2MB(str
));
324 const wxChar
*mbstr
= str
;
326 size_t len
= strlen(mbstr
)+1;
327 CacheWriteInt32(f
, len
);
328 f
->Write(mbstr
, len
);
331 inline static wxChar
* CacheReadString(wxInputStream
*f
)
334 size_t len
= (size_t)CacheReadInt32(f
);
340 wxMB2WXbuf
wxstr(wxConvUTF8
.cMB2WX(str
));
341 wxChar
*outstr
= new wxChar
[wxStrlen(wxstr
)+1];
342 wxStrcpy(outstr
, wxstr
);
347 #define CURRENT_CACHED_BOOK_VERSION 4
349 // Additional flags to detect incompatibilities of the runtime environment:
350 #define CACHED_BOOK_FORMAT_FLAGS \
354 bool wxHtmlHelpData::LoadCachedBook(wxHtmlBookRecord
*book
, wxInputStream
*f
)
359 /* load header - version info : */
360 version
= CacheReadInt32(f
);
362 if (version
!= CURRENT_CACHED_BOOK_VERSION
)
364 // NB: We can just silently return FALSE here and don't worry about
365 // it anymore, because AddBookParam will load the MS project in
366 // absence of (properly versioned) .cached file and automatically
367 // create new .cached file immediately afterward.
371 if (CacheReadInt32(f
) != CACHED_BOOK_FORMAT_FLAGS
)
374 /* load contents : */
376 m_ContentsCnt
+= CacheReadInt32(f
);
377 m_Contents
= (wxHtmlContentsItem
*) realloc(m_Contents
,
378 (m_ContentsCnt
/ wxHTML_REALLOC_STEP
+ 1) *
379 wxHTML_REALLOC_STEP
* sizeof(wxHtmlContentsItem
));
380 for (i
= st
; i
< m_ContentsCnt
; i
++)
382 m_Contents
[i
].m_Level
= CacheReadInt32(f
);
383 m_Contents
[i
].m_ID
= CacheReadInt32(f
);
384 m_Contents
[i
].m_Name
= CacheReadString(f
);
385 m_Contents
[i
].m_Page
= CacheReadString(f
);
386 m_Contents
[i
].m_Book
= book
;
391 m_IndexCnt
+= CacheReadInt32(f
);
392 m_Index
= (wxHtmlContentsItem
*) realloc(m_Index
, (m_IndexCnt
/ wxHTML_REALLOC_STEP
+ 1) *
393 wxHTML_REALLOC_STEP
* sizeof(wxHtmlContentsItem
));
394 for (i
= st
; i
< m_IndexCnt
; i
++)
396 m_Index
[i
].m_Name
= CacheReadString(f
);
397 m_Index
[i
].m_Page
= CacheReadString(f
);
398 m_Index
[i
].m_Book
= book
;
404 bool wxHtmlHelpData::SaveCachedBook(wxHtmlBookRecord
*book
, wxOutputStream
*f
)
409 /* save header - version info : */
410 CacheWriteInt32(f
, CURRENT_CACHED_BOOK_VERSION
);
411 CacheWriteInt32(f
, CACHED_BOOK_FORMAT_FLAGS
);
413 /* save contents : */
414 for (cnt
= 0, i
= 0; i
< m_ContentsCnt
; i
++)
415 if (m_Contents
[i
].m_Book
== book
&& m_Contents
[i
].m_Level
> 0)
417 CacheWriteInt32(f
, cnt
);
419 for (i
= 0; i
< m_ContentsCnt
; i
++)
421 if (m_Contents
[i
].m_Book
!= book
|| m_Contents
[i
].m_Level
== 0)
423 CacheWriteInt32(f
, m_Contents
[i
].m_Level
);
424 CacheWriteInt32(f
, m_Contents
[i
].m_ID
);
425 CacheWriteString(f
, m_Contents
[i
].m_Name
);
426 CacheWriteString(f
, m_Contents
[i
].m_Page
);
430 for (cnt
= 0, i
= 0; i
< m_IndexCnt
; i
++)
431 if (m_Index
[i
].m_Book
== book
&& m_Index
[i
].m_Level
> 0)
433 CacheWriteInt32(f
, cnt
);
435 for (i
= 0; i
< m_IndexCnt
; i
++)
437 if (m_Index
[i
].m_Book
!= book
|| m_Index
[i
].m_Level
== 0)
439 CacheWriteString(f
, m_Index
[i
].m_Name
);
440 CacheWriteString(f
, m_Index
[i
].m_Page
);
446 void wxHtmlHelpData::SetTempDir(const wxString
& path
)
448 if (path
== wxEmptyString
) m_TempPath
= path
;
451 if (wxIsAbsolutePath(path
)) m_TempPath
= path
;
452 else m_TempPath
= wxGetCwd() + _T("/") + path
;
454 if (m_TempPath
[m_TempPath
.Length() - 1] != _T('/'))
455 m_TempPath
<< _T('/');
461 static wxString
SafeFileName(const wxString
& s
)
464 res
.Replace(wxT("#"), wxT("_"));
465 res
.Replace(wxT(":"), wxT("_"));
466 res
.Replace(wxT("\\"), wxT("_"));
467 res
.Replace(wxT("/"), wxT("_"));
471 bool wxHtmlHelpData::AddBookParam(const wxFSFile
& bookfile
,
472 wxFontEncoding encoding
,
473 const wxString
& title
, const wxString
& contfile
,
474 const wxString
& indexfile
, const wxString
& deftopic
,
475 const wxString
& path
)
479 wxHtmlBookRecord
*bookr
;
481 int IndexOld
= m_IndexCnt
,
482 ContentsOld
= m_ContentsCnt
;
485 fsys
.ChangePathTo(path
, TRUE
);
487 size_t booksCnt
= m_BookRecords
.GetCount();
488 for (size_t i
= 0; i
< booksCnt
; i
++)
490 if ( m_BookRecords
[i
].GetBookFile() == bookfile
.GetLocation() )
491 return TRUE
; // book is (was) loaded
494 bookr
= new wxHtmlBookRecord(bookfile
.GetLocation(), fsys
.GetPath(), title
, deftopic
);
496 if (m_ContentsCnt
% wxHTML_REALLOC_STEP
== 0)
497 m_Contents
= (wxHtmlContentsItem
*) realloc(m_Contents
, (m_ContentsCnt
+ wxHTML_REALLOC_STEP
) * sizeof(wxHtmlContentsItem
));
498 m_Contents
[m_ContentsCnt
].m_Level
= 0;
499 m_Contents
[m_ContentsCnt
].m_ID
= 0;
500 m_Contents
[m_ContentsCnt
].m_Page
= new wxChar
[deftopic
.Length() + 1];
501 wxStrcpy(m_Contents
[m_ContentsCnt
].m_Page
, deftopic
.c_str());
502 m_Contents
[m_ContentsCnt
].m_Name
= new wxChar
[title
.Length() + 1];
503 wxStrcpy(m_Contents
[m_ContentsCnt
].m_Name
, title
.c_str());
504 m_Contents
[m_ContentsCnt
].m_Book
= bookr
;
506 // store the contents index for later
507 int cont_start
= m_ContentsCnt
++;
509 // Try to find cached binary versions:
510 // 1. save file as book, but with .hhp.cached extension
511 // 2. same as 1. but in temp path
512 // 3. otherwise or if cache load failed, load it from MS.
514 fi
= fsys
.OpenFile(bookfile
.GetLocation() + wxT(".cached"));
518 fi
->GetModificationTime() < bookfile
.GetModificationTime() ||
519 #endif // wxUSE_DATETIME
520 !LoadCachedBook(bookr
, fi
->GetStream()))
522 if (fi
!= NULL
) delete fi
;
523 fi
= fsys
.OpenFile(m_TempPath
+ wxFileNameFromPath(bookfile
.GetLocation()) + wxT(".cached"));
524 if (m_TempPath
== wxEmptyString
|| fi
== NULL
||
526 fi
->GetModificationTime() < bookfile
.GetModificationTime() ||
527 #endif // wxUSE_DATETIME
528 !LoadCachedBook(bookr
, fi
->GetStream()))
530 LoadMSProject(bookr
, fsys
, indexfile
, contfile
);
531 if (m_TempPath
!= wxEmptyString
)
533 wxFileOutputStream
*outs
= new wxFileOutputStream(m_TempPath
+
534 SafeFileName(wxFileNameFromPath(bookfile
.GetLocation())) + wxT(".cached"));
535 SaveCachedBook(bookr
, outs
);
541 if (fi
!= NULL
) delete fi
;
543 // Now store the contents range
544 bookr
->SetContentsRange(cont_start
, m_ContentsCnt
);
546 // Convert encoding, if neccessary:
547 if (encoding
!= wxFONTENCODING_SYSTEM
)
549 wxFontEncodingArray a
= wxEncodingConverter::GetPlatformEquivalents(encoding
);
550 if (a
.GetCount() != 0 && a
[0] != encoding
)
553 wxEncodingConverter conv
;
554 conv
.Init(encoding
, a
[0]);
556 for (i
= IndexOld
; i
< m_IndexCnt
; i
++)
557 conv
.Convert(m_Index
[i
].m_Name
);
558 for (i
= ContentsOld
; i
< m_ContentsCnt
; i
++)
559 conv
.Convert(m_Contents
[i
].m_Name
);
563 m_BookRecords
.Add(bookr
);
565 qsort(m_Index
, m_IndexCnt
, sizeof(wxHtmlContentsItem
), wxHtmlHelpIndexCompareFunc
);
571 bool wxHtmlHelpData::AddBook(const wxString
& book
)
573 wxString
extension(book
.Right(4).Lower());
574 if (extension
== wxT(".zip") ||
576 extension
== wxT(".chm") /*compressed html help book*/ ||
578 extension
== wxT(".htb") /*html book*/)
585 if (extension
== wxT(".chm"))
586 s
= fsys
.FindFirst(book
+ wxT("#chm:*.hhp"), wxFILE
);
589 s
= fsys
.FindFirst(book
+ wxT("#zip:*.hhp"), wxFILE
);
593 if (AddBook(s
)) rt
= TRUE
;
603 wxString title
= _("noname"),
605 start
= wxEmptyString
,
606 contents
= wxEmptyString
,
607 index
= wxEmptyString
,
608 charset
= wxEmptyString
;
610 fi
= fsys
.OpenFile(book
);
613 wxLogError(_("Cannot open HTML help book: %s"), book
.c_str());
616 fsys
.ChangePathTo(book
);
618 const wxChar
*lineptr
;
621 wxHtmlFilterPlainText filter
;
622 tmp
= filter
.ReadFile(*fi
);
623 lineptr
= tmp
.c_str();
627 lineptr
= ReadLine(lineptr
, linebuf
, 300);
629 for (wxChar
*ch
= linebuf
; *ch
!= wxT('\0') && *ch
!= wxT('='); ch
++)
632 if (wxStrstr(linebuf
, _T("title=")) == linebuf
)
633 title
= linebuf
+ wxStrlen(_T("title="));
634 if (wxStrstr(linebuf
, _T("default topic=")) == linebuf
)
635 start
= linebuf
+ wxStrlen(_T("default topic="));
636 if (wxStrstr(linebuf
, _T("index file=")) == linebuf
)
637 index
= linebuf
+ wxStrlen(_T("index file="));
638 if (wxStrstr(linebuf
, _T("contents file=")) == linebuf
)
639 contents
= linebuf
+ wxStrlen(_T("contents file="));
640 if (wxStrstr(linebuf
, _T("charset=")) == linebuf
)
641 charset
= linebuf
+ wxStrlen(_T("charset="));
642 } while (lineptr
!= NULL
);
645 if (charset
== wxEmptyString
) enc
= wxFONTENCODING_SYSTEM
;
646 else enc
= wxFontMapper::Get()->CharsetToEncoding(charset
);
647 bool rtval
= AddBookParam(*fi
, enc
,
648 title
, contents
, index
, start
, fsys
.GetPath());
653 wxString
wxHtmlHelpData::FindPageByName(const wxString
& x
)
659 wxString
url(wxEmptyString
);
661 /* 1. try to open given file: */
663 cnt
= m_BookRecords
.GetCount();
664 for (i
= 0; i
< cnt
; i
++)
666 f
= fsys
.OpenFile(m_BookRecords
[i
].GetFullPath(x
));
669 url
= m_BookRecords
[i
].GetFullPath(x
);
676 /* 2. try to find a book: */
678 for (i
= 0; i
< cnt
; i
++)
680 if (m_BookRecords
[i
].GetTitle() == x
)
682 url
= m_BookRecords
[i
].GetFullPath(m_BookRecords
[i
].GetStart());
687 /* 3. try to find in contents: */
690 for (i
= 0; i
< cnt
; i
++)
692 if (wxStrcmp(m_Contents
[i
].m_Name
, x
) == 0)
694 url
= m_Contents
[i
].GetFullPath();
700 /* 4. try to find in index: */
703 for (i
= 0; i
< cnt
; i
++)
705 if (wxStrcmp(m_Index
[i
].m_Name
, x
) == 0)
707 url
= m_Index
[i
].GetFullPath();
715 wxString
wxHtmlHelpData::FindPageById(int id
)
718 wxString
url(wxEmptyString
);
720 for (i
= 0; i
< m_ContentsCnt
; i
++)
722 if (m_Contents
[i
].m_ID
== id
)
724 url
= m_Contents
[i
].GetFullPath();
732 //----------------------------------------------------------------------------------
733 // wxHtmlSearchStatus functions
734 //----------------------------------------------------------------------------------
736 wxHtmlSearchStatus::wxHtmlSearchStatus(wxHtmlHelpData
* data
, const wxString
& keyword
,
737 bool case_sensitive
, bool whole_words_only
,
738 const wxString
& book
)
742 wxHtmlBookRecord
* bookr
= NULL
;
743 if (book
!= wxEmptyString
)
745 // we have to search in a specific book. Find it first
746 int i
, cnt
= data
->m_BookRecords
.GetCount();
747 for (i
= 0; i
< cnt
; i
++)
748 if (data
->m_BookRecords
[i
].GetTitle() == book
)
750 bookr
= &(data
->m_BookRecords
[i
]);
751 m_CurIndex
= bookr
->GetContentsStart();
752 m_MaxIndex
= bookr
->GetContentsEnd();
755 // check; we won't crash if the book doesn't exist, but it's Bad Anyway.
760 // no book specified; search all books
762 m_MaxIndex
= m_Data
->m_ContentsCnt
;
764 m_Engine
.LookFor(keyword
, case_sensitive
, whole_words_only
);
765 m_Active
= (m_CurIndex
< m_MaxIndex
);
769 bool wxHtmlSearchStatus::Search()
772 int i
= m_CurIndex
; // shortcut
778 // sanity check. Illegal use, but we'll try to prevent a crash anyway
783 m_Name
= wxEmptyString
;
784 m_ContentsItem
= NULL
;
785 thepage
= m_Data
->m_Contents
[i
].m_Page
;
787 m_Active
= (++m_CurIndex
< m_MaxIndex
);
788 // check if it is same page with different anchor:
789 if (m_LastPage
!= NULL
)
792 for (p1
= thepage
, p2
= m_LastPage
;
793 *p1
!= 0 && *p1
!= _T('#') && *p1
== *p2
; p1
++, p2
++) {}
795 m_LastPage
= thepage
;
797 if (*p1
== 0 || *p1
== _T('#'))
800 else m_LastPage
= thepage
;
803 file
= fsys
.OpenFile(m_Data
->m_Contents
[i
].m_Book
->GetFullPath(thepage
));
806 if (m_Engine
.Scan(*file
))
808 m_Name
= m_Data
->m_Contents
[i
].m_Name
;
809 m_ContentsItem
= m_Data
->m_Contents
+ i
;
824 //--------------------------------------------------------------------------------
825 // wxHtmlSearchEngine
826 //--------------------------------------------------------------------------------
828 void wxHtmlSearchEngine::LookFor(const wxString
& keyword
, bool case_sensitive
, bool whole_words_only
)
830 m_CaseSensitive
= case_sensitive
;
831 m_WholeWords
= whole_words_only
;
832 if (m_Keyword
) delete[] m_Keyword
;
833 m_Keyword
= new wxChar
[keyword
.Length() + 1];
834 wxStrcpy(m_Keyword
, keyword
.c_str());
836 if (!m_CaseSensitive
)
838 for (int i
= wxStrlen(m_Keyword
) - 1; i
>= 0; i
--)
840 if ((m_Keyword
[i
] >= wxT('A')) && (m_Keyword
[i
] <= wxT('Z')))
841 m_Keyword
[i
] += wxT('a') - wxT('A');
847 static inline bool WHITESPACE(wxChar c
)
849 return c
== _T(' ') || c
== _T('\n') || c
== _T('\r') || c
== _T('\t');
852 bool wxHtmlSearchEngine::Scan(const wxFSFile
& file
)
854 wxASSERT_MSG(m_Keyword
!= NULL
, wxT("wxHtmlSearchEngine::LookFor must be called before scanning!"));
857 int wrd
= wxStrlen(m_Keyword
);
859 wxHtmlFilterHTML filter
;
860 wxString tmp
= filter
.ReadFile(file
);
861 int lng
= tmp
.length();
862 const wxChar
*buf
= tmp
.c_str();
864 if (!m_CaseSensitive
)
865 for (i
= 0; i
< lng
; i
++)
866 tmp
[(size_t)i
] = (wxChar
)wxTolower(tmp
[(size_t)i
]);
870 for (i
= 0; i
< lng
- wrd
; i
++)
872 if (WHITESPACE(buf
[i
])) continue;
874 while ((j
< wrd
) && (buf
[i
+ j
] == m_Keyword
[j
])) j
++;
875 if (j
== wrd
&& WHITESPACE(buf
[i
+ j
])) { found
= TRUE
; break; }
881 for (i
= 0; i
< lng
- wrd
; i
++)
884 while ((j
< wrd
) && (buf
[i
+ j
] == m_Keyword
[j
])) j
++;
885 if (j
== wrd
) { found
= TRUE
; break; }