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 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
21 #if wxUSE_HTML && wxUSE_STREAMS
30 #include "wx/html/helpdata.h"
31 #include "wx/tokenzr.h"
32 #include "wx/wfstream.h"
33 #include "wx/busyinfo.h"
34 #include "wx/encconv.h"
35 #include "wx/fontmap.h"
37 #include "wx/html/htmlpars.h"
38 #include "wx/html/htmldefs.h"
39 #include "wx/html/htmlfilt.h"
40 #include "wx/filename.h"
42 #include "wx/arrimpl.cpp"
43 WX_DEFINE_OBJARRAY(wxHtmlBookRecArray
)
44 WX_DEFINE_OBJARRAY(wxHtmlHelpDataItems
)
46 //-----------------------------------------------------------------------------
47 // static helper functions
48 //-----------------------------------------------------------------------------
50 // Reads one line, stores it into buf and returns pointer to new line or NULL.
51 static const wxChar
* ReadLine(const wxChar
*line
, wxChar
*buf
, size_t bufsize
)
53 wxChar
*writeptr
= buf
;
54 wxChar
*endptr
= buf
+ bufsize
- 1;
55 const wxChar
*readptr
= line
;
57 while (*readptr
!= 0 && *readptr
!= _T('\r') && *readptr
!= _T('\n') &&
59 *(writeptr
++) = *(readptr
++);
61 while (*readptr
== _T('\r') || *readptr
== _T('\n'))
72 wxHtmlHelpIndexCompareFunc(wxHtmlHelpDataItem
**a
, wxHtmlHelpDataItem
**b
)
74 wxHtmlHelpDataItem
*ia
= *a
;
75 wxHtmlHelpDataItem
*ib
= *b
;
82 if (ia
->parent
== ib
->parent
)
84 return ia
->name
.CmpNoCase(ib
->name
);
86 else if (ia
->level
== ib
->level
)
88 return wxHtmlHelpIndexCompareFunc(&ia
->parent
, &ib
->parent
);
92 wxHtmlHelpDataItem
*ia2
= ia
;
93 wxHtmlHelpDataItem
*ib2
= ib
;
95 while (ia2
->level
> ib2
->level
)
99 while (ib2
->level
> ia2
->level
)
106 int res
= wxHtmlHelpIndexCompareFunc(&ia2
, &ib2
);
109 else if (ia
->level
> ib
->level
)
116 //-----------------------------------------------------------------------------
118 //-----------------------------------------------------------------------------
120 class HP_Parser
: public wxHtmlParser
125 GetEntitiesParser()->SetEncoding(wxFONTENCODING_ISO8859_1
);
128 wxObject
* GetProduct() { return NULL
; }
131 virtual void AddText(const wxChar
* WXUNUSED(txt
)) {}
133 DECLARE_NO_COPY_CLASS(HP_Parser
)
137 //-----------------------------------------------------------------------------
139 //-----------------------------------------------------------------------------
141 class HP_TagHandler
: public wxHtmlTagHandler
144 wxString m_name
, m_page
;
149 wxHtmlHelpDataItem
*m_parentItem
;
150 wxHtmlBookRecord
*m_book
;
152 wxHtmlHelpDataItems
*m_data
;
155 HP_TagHandler(wxHtmlBookRecord
*b
) : wxHtmlTagHandler()
159 m_name
= m_page
= wxEmptyString
;
165 wxString
GetSupportedTags() { return wxT("UL,OBJECT,PARAM"); }
166 bool HandleTag(const wxHtmlTag
& tag
);
168 void Reset(wxHtmlHelpDataItems
& data
)
176 DECLARE_NO_COPY_CLASS(HP_TagHandler
)
180 bool HP_TagHandler::HandleTag(const wxHtmlTag
& tag
)
182 if (tag
.GetName() == wxT("UL"))
184 wxHtmlHelpDataItem
*oldparent
= m_parentItem
;
186 m_parentItem
= (m_count
> 0) ? &(*m_data
)[m_data
->size()-1] : NULL
;
189 m_parentItem
= oldparent
;
192 else if (tag
.GetName() == wxT("OBJECT"))
194 m_name
= m_page
= wxEmptyString
;
199 /* Valid HHW's file may contain only two object tags:
201 <OBJECT type="text/site properties">
202 <param name="ImageType" value="Folder">
207 <OBJECT type="text/sitemap">
208 <param name="Name" value="main page">
209 <param name="Local" value="another.htm">
212 We're interested in the latter. !page.IsEmpty() is valid
213 condition because text/site properties does not contain Local param
216 if (tag
.GetParam(wxT("TYPE")) == wxT("text/sitemap"))
218 wxHtmlHelpDataItem
*item
= new wxHtmlHelpDataItem();
219 item
->parent
= m_parentItem
;
220 item
->level
= m_level
;
234 if (m_name
.empty() && tag
.GetParam(wxT("NAME")) == wxT("Name"))
235 m_name
= tag
.GetParam(wxT("VALUE"));
236 if (tag
.GetParam(wxT("NAME")) == wxT("Local"))
237 m_page
= tag
.GetParam(wxT("VALUE"));
238 if (tag
.GetParam(wxT("NAME")) == wxT("ID"))
239 tag
.GetParamAsInt(wxT("VALUE"), &m_id
);
245 //-----------------------------------------------------------------------------
247 //-----------------------------------------------------------------------------
249 wxString
wxHtmlBookRecord::GetFullPath(const wxString
&page
) const
251 if (wxIsAbsolutePath(page
))
254 return m_BasePath
+ page
;
257 wxString
wxHtmlHelpDataItem::GetIndentedName() const
260 for (int i
= 1; i
< level
; i
++)
267 IMPLEMENT_DYNAMIC_CLASS(wxHtmlHelpData
, wxObject
)
269 wxHtmlHelpData::wxHtmlHelpData()
271 #if WXWIN_COMPATIBILITY_2_4
272 m_cacheContents
= NULL
;
277 wxHtmlHelpData::~wxHtmlHelpData()
279 #if WXWIN_COMPATIBILITY_2_4
280 CleanCompatibilityData();
284 bool wxHtmlHelpData::LoadMSProject(wxHtmlBookRecord
*book
, wxFileSystem
& fsys
,
285 const wxString
& indexfile
,
286 const wxString
& contentsfile
)
289 wxHtmlFilterHTML filter
;
294 HP_TagHandler
*handler
= new HP_TagHandler(book
);
295 parser
.AddTagHandler(handler
);
297 f
= ( contentsfile
.IsEmpty() ? (wxFSFile
*) NULL
: fsys
.OpenFile(contentsfile
) );
301 buf
= filter
.ReadFile(*f
);
303 handler
->Reset(m_contents
);
308 wxLogError(_("Cannot open contents file: %s"), contentsfile
.c_str());
311 f
= ( indexfile
.IsEmpty() ? (wxFSFile
*) NULL
: fsys
.OpenFile(indexfile
) );
315 buf
= filter
.ReadFile(*f
);
317 handler
->Reset(m_index
);
320 else if (!indexfile
.IsEmpty())
322 wxLogError(_("Cannot open index file: %s"), indexfile
.c_str());
327 inline static void CacheWriteInt32(wxOutputStream
*f
, wxInt32 value
)
329 wxInt32 x
= wxINT32_SWAP_ON_BE(value
);
330 f
->Write(&x
, sizeof(x
));
333 inline static wxInt32
CacheReadInt32(wxInputStream
*f
)
336 f
->Read(&x
, sizeof(x
));
337 return wxINT32_SWAP_ON_BE(x
);
340 inline static void CacheWriteString(wxOutputStream
*f
, const wxString
& str
)
342 const wxWX2MBbuf mbstr
= str
.mb_str(wxConvUTF8
);
343 size_t len
= strlen((const char*)mbstr
)+1;
344 CacheWriteInt32(f
, len
);
345 f
->Write((const char*)mbstr
, len
);
348 inline static wxString
CacheReadString(wxInputStream
*f
)
350 size_t len
= (size_t)CacheReadInt32(f
);
351 wxCharBuffer
str(len
-1);
352 f
->Read(str
.data(), len
);
353 return wxString(str
, wxConvUTF8
);
356 #define CURRENT_CACHED_BOOK_VERSION 5
358 // Additional flags to detect incompatibilities of the runtime environment:
359 #define CACHED_BOOK_FORMAT_FLAGS \
363 bool wxHtmlHelpData::LoadCachedBook(wxHtmlBookRecord
*book
, wxInputStream
*f
)
368 /* load header - version info : */
369 version
= CacheReadInt32(f
);
371 if (version
!= CURRENT_CACHED_BOOK_VERSION
)
373 // NB: We can just silently return false here and don't worry about
374 // it anymore, because AddBookParam will load the MS project in
375 // absence of (properly versioned) .cached file and automatically
376 // create new .cached file immediately afterward.
380 if (CacheReadInt32(f
) != CACHED_BOOK_FORMAT_FLAGS
)
383 /* load contents : */
384 st
= m_contents
.size();
385 newsize
= st
+ CacheReadInt32(f
);
386 m_contents
.Alloc(newsize
);
387 for (i
= st
; i
< newsize
; i
++)
389 wxHtmlHelpDataItem
*item
= new wxHtmlHelpDataItem
;
390 item
->level
= CacheReadInt32(f
);
391 item
->id
= CacheReadInt32(f
);
392 item
->name
= CacheReadString(f
);
393 item
->page
= CacheReadString(f
);
395 m_contents
.Add(item
);
400 newsize
= st
+ CacheReadInt32(f
);
401 m_index
.Alloc(newsize
);
402 for (i
= st
; i
< newsize
; i
++)
404 wxHtmlHelpDataItem
*item
= new wxHtmlHelpDataItem
;
405 item
->name
= CacheReadString(f
);
406 item
->page
= CacheReadString(f
);
407 item
->level
= CacheReadInt32(f
);
409 int parentShift
= CacheReadInt32(f
);
410 if (parentShift
!= 0)
411 item
->parent
= &m_index
[m_index
.size() - parentShift
];
418 bool wxHtmlHelpData::SaveCachedBook(wxHtmlBookRecord
*book
, wxOutputStream
*f
)
423 /* save header - version info : */
424 CacheWriteInt32(f
, CURRENT_CACHED_BOOK_VERSION
);
425 CacheWriteInt32(f
, CACHED_BOOK_FORMAT_FLAGS
);
427 /* save contents : */
428 int len
= m_contents
.size();
429 for (cnt
= 0, i
= 0; i
< len
; i
++)
430 if (m_contents
[i
].book
== book
&& m_contents
[i
].level
> 0)
432 CacheWriteInt32(f
, cnt
);
434 for (i
= 0; i
< len
; i
++)
436 if (m_contents
[i
].book
!= book
|| m_contents
[i
].level
== 0)
438 CacheWriteInt32(f
, m_contents
[i
].level
);
439 CacheWriteInt32(f
, m_contents
[i
].id
);
440 CacheWriteString(f
, m_contents
[i
].name
);
441 CacheWriteString(f
, m_contents
[i
].page
);
445 len
= m_index
.size();
446 for (cnt
= 0, i
= 0; i
< len
; i
++)
447 if (m_index
[i
].book
== book
&& m_index
[i
].level
> 0)
449 CacheWriteInt32(f
, cnt
);
451 for (i
= 0; i
< len
; i
++)
453 if (m_index
[i
].book
!= book
|| m_index
[i
].level
== 0)
455 CacheWriteString(f
, m_index
[i
].name
);
456 CacheWriteString(f
, m_index
[i
].page
);
457 CacheWriteInt32(f
, m_index
[i
].level
);
458 // save distance to parent item, if any:
459 if (m_index
[i
].parent
== NULL
)
461 CacheWriteInt32(f
, 0);
466 wxHtmlHelpDataItem
*parent
= m_index
[i
].parent
;
467 for (int j
= i
-1; j
>= 0; j
--)
469 if (m_index
[j
].book
== book
&& m_index
[j
].level
> 0)
471 if (&m_index
[j
] == parent
)
475 CacheWriteInt32(f
, cnt2
);
482 void wxHtmlHelpData::SetTempDir(const wxString
& path
)
488 if (wxIsAbsolutePath(path
)) m_tempPath
= path
;
489 else m_tempPath
= wxGetCwd() + _T("/") + path
;
491 if (m_tempPath
[m_tempPath
.Length() - 1] != _T('/'))
492 m_tempPath
<< _T('/');
498 static wxString
SafeFileName(const wxString
& s
)
501 res
.Replace(wxT("#"), wxT("_"));
502 res
.Replace(wxT(":"), wxT("_"));
503 res
.Replace(wxT("\\"), wxT("_"));
504 res
.Replace(wxT("/"), wxT("_"));
508 bool wxHtmlHelpData::AddBookParam(const wxFSFile
& bookfile
,
509 wxFontEncoding encoding
,
510 const wxString
& title
, const wxString
& contfile
,
511 const wxString
& indexfile
, const wxString
& deftopic
,
512 const wxString
& path
)
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 bookr
= new wxHtmlBookRecord(bookfile
.GetLocation(), fsys
.GetPath(), title
, deftopic
);
533 wxHtmlHelpDataItem
*bookitem
= new wxHtmlHelpDataItem
;
536 bookitem
->page
= deftopic
;
537 bookitem
->name
= title
;
538 bookitem
->book
= bookr
;
540 // store the contents index for later
541 int cont_start
= m_contents
.size();
543 m_contents
.Add(bookitem
);
545 // Try to find cached binary versions:
546 // 1. save file as book, but with .hhp.cached extension
547 // 2. same as 1. but in temp path
548 // 3. otherwise or if cache load failed, load it from MS.
550 fi
= fsys
.OpenFile(bookfile
.GetLocation() + wxT(".cached"));
554 fi
->GetModificationTime() < bookfile
.GetModificationTime() ||
555 #endif // wxUSE_DATETIME
556 !LoadCachedBook(bookr
, fi
->GetStream()))
558 if (fi
!= NULL
) delete fi
;
559 fi
= fsys
.OpenFile(m_tempPath
+ wxFileNameFromPath(bookfile
.GetLocation()) + wxT(".cached"));
560 if (m_tempPath
.empty() || fi
== NULL
||
562 fi
->GetModificationTime() < bookfile
.GetModificationTime() ||
563 #endif // wxUSE_DATETIME
564 !LoadCachedBook(bookr
, fi
->GetStream()))
566 LoadMSProject(bookr
, fsys
, indexfile
, contfile
);
567 if (!m_tempPath
.empty())
569 wxFileOutputStream
*outs
= new wxFileOutputStream(m_tempPath
+
570 SafeFileName(wxFileNameFromPath(bookfile
.GetLocation())) + wxT(".cached"));
571 SaveCachedBook(bookr
, outs
);
577 if (fi
!= NULL
) delete fi
;
579 // Now store the contents range
580 bookr
->SetContentsRange(cont_start
, m_contents
.size());
583 // MS HTML Help files [written by MS HTML Help Workshop] are broken
584 // in that the data are iso-8859-1 (including HTML entities), but must
585 // be interpreted as being in language's windows charset. Correct the
586 // differences here and also convert to wxConvLocal in ANSI build
587 if (encoding
!= wxFONTENCODING_SYSTEM
)
590 #define CORRECT_STR(str, conv) \
591 str = wxString((str).mb_str(wxConvISO8859_1), conv)
593 #define CORRECT_STR(str, conv) \
594 str = wxString((str).wc_str(conv), wxConvLocal)
596 wxCSConv
conv(encoding
);
597 size_t IndexCnt
= m_index
.size();
598 size_t ContentsCnt
= m_contents
.size();
600 for (i
= IndexOld
; i
< IndexCnt
; i
++)
602 CORRECT_STR(m_index
[i
].name
, conv
);
604 for (i
= ContentsOld
; i
< ContentsCnt
; i
++)
606 CORRECT_STR(m_contents
[i
].name
, conv
);
611 wxUnusedVar(IndexOld
);
612 wxUnusedVar(ContentsOld
);
613 wxASSERT_MSG(encoding
== wxFONTENCODING_SYSTEM
, wxT("Help files need charset conversion, but wxUSE_WCHAR_T is 0"));
614 #endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T
616 m_bookRecords
.Add(bookr
);
617 if (!m_index
.empty())
619 m_index
.Sort(wxHtmlHelpIndexCompareFunc
);
626 bool wxHtmlHelpData::AddBook(const wxString
& book
)
628 wxString
extension(book
.Right(4).Lower());
629 if (extension
== wxT(".zip") ||
631 extension
== wxT(".chm") /*compressed html help book*/ ||
633 extension
== wxT(".htb") /*html book*/)
640 if (extension
== wxT(".chm"))
641 s
= fsys
.FindFirst(book
+ wxT("#chm:*.hhp"), wxFILE
);
644 s
= fsys
.FindFirst(book
+ wxT("#zip:*.hhp"), wxFILE
);
648 if (AddBook(s
)) rt
= true;
658 wxString title
= _("noname"),
660 start
= wxEmptyString
,
661 contents
= wxEmptyString
,
662 index
= wxEmptyString
,
663 charset
= wxEmptyString
;
665 fi
= fsys
.OpenFile(book
);
668 wxLogError(_("Cannot open HTML help book: %s"), book
.c_str());
671 fsys
.ChangePathTo(book
);
673 const wxChar
*lineptr
;
676 wxHtmlFilterPlainText filter
;
677 tmp
= filter
.ReadFile(*fi
);
678 lineptr
= tmp
.c_str();
682 lineptr
= ReadLine(lineptr
, linebuf
, 300);
684 for (wxChar
*ch
= linebuf
; *ch
!= wxT('\0') && *ch
!= wxT('='); ch
++)
685 *ch
= (wxChar
)wxTolower(*ch
);
687 if (wxStrstr(linebuf
, _T("title=")) == linebuf
)
688 title
= linebuf
+ wxStrlen(_T("title="));
689 if (wxStrstr(linebuf
, _T("default topic=")) == linebuf
)
690 start
= linebuf
+ wxStrlen(_T("default topic="));
691 if (wxStrstr(linebuf
, _T("index file=")) == linebuf
)
692 index
= linebuf
+ wxStrlen(_T("index file="));
693 if (wxStrstr(linebuf
, _T("contents file=")) == linebuf
)
694 contents
= linebuf
+ wxStrlen(_T("contents file="));
695 if (wxStrstr(linebuf
, _T("charset=")) == linebuf
)
696 charset
= linebuf
+ wxStrlen(_T("charset="));
697 } while (lineptr
!= NULL
);
699 wxFontEncoding enc
= wxFONTENCODING_SYSTEM
;
701 if (charset
!= wxEmptyString
)
702 enc
= wxFontMapper::Get()->CharsetToEncoding(charset
);
705 bool rtval
= AddBookParam(*fi
, enc
,
706 title
, contents
, index
, start
, fsys
.GetPath());
709 #if WXWIN_COMPATIBILITY_2_4
710 CleanCompatibilityData();
716 wxString
wxHtmlHelpData::FindPageByName(const wxString
& x
)
723 /* 1. try to open given file: */
725 cnt
= m_bookRecords
.GetCount();
726 for (i
= 0; i
< cnt
; i
++)
728 f
= fsys
.OpenFile(m_bookRecords
[i
].GetFullPath(x
));
731 wxString url
= m_bookRecords
[i
].GetFullPath(x
);
738 /* 2. try to find a book: */
740 for (i
= 0; i
< cnt
; i
++)
742 if (m_bookRecords
[i
].GetTitle() == x
)
743 return m_bookRecords
[i
].GetFullPath(m_bookRecords
[i
].GetStart());
746 /* 3. try to find in contents: */
748 cnt
= m_contents
.size();
749 for (i
= 0; i
< cnt
; i
++)
751 if (m_contents
[i
].name
== x
)
752 return m_contents
[i
].GetFullPath();
756 /* 4. try to find in index: */
758 cnt
= m_index
.size();
759 for (i
= 0; i
< cnt
; i
++)
761 if (m_index
[i
].name
== x
)
762 return m_index
[i
].GetFullPath();
765 return wxEmptyString
;
768 wxString
wxHtmlHelpData::FindPageById(int id
)
770 size_t cnt
= m_contents
.size();
771 for (size_t i
= 0; i
< cnt
; i
++)
773 if (m_contents
[i
].id
== id
)
775 return m_contents
[i
].GetFullPath();
779 return wxEmptyString
;
782 #if WXWIN_COMPATIBILITY_2_4
783 wxHtmlContentsItem::wxHtmlContentsItem()
784 : m_Level(0), m_ID(wxID_ANY
), m_Name(NULL
), m_Page(NULL
), m_Book(NULL
),
789 wxHtmlContentsItem::wxHtmlContentsItem(const wxHtmlHelpDataItem
& d
)
794 m_Name
= wxStrdup(d
.name
.c_str());
795 m_Page
= wxStrdup(d
.page
.c_str());
799 wxHtmlContentsItem
& wxHtmlContentsItem::operator=(const wxHtmlContentsItem
& d
)
809 m_Name
= d
.m_Name
? wxStrdup(d
.m_Name
) : NULL
;
810 m_Page
= d
.m_Page
? wxStrdup(d
.m_Page
) : NULL
;
815 wxHtmlContentsItem::~wxHtmlContentsItem()
824 wxHtmlContentsItem
* wxHtmlHelpData::GetContents()
826 if (!m_cacheContents
&& !m_contents
.empty())
828 size_t len
= m_contents
.size();
829 m_cacheContents
= new wxHtmlContentsItem
[len
];
830 for (size_t i
= 0; i
< len
; i
++)
831 m_cacheContents
[i
] = m_contents
[i
];
833 return m_cacheContents
;
836 int wxHtmlHelpData::GetContentsCnt()
838 return m_contents
.size();
841 wxHtmlContentsItem
* wxHtmlHelpData::GetIndex()
843 if (!m_cacheContents
&& !m_index
.empty())
845 size_t len
= m_index
.size();
846 m_cacheContents
= new wxHtmlContentsItem
[len
];
847 for (size_t i
= 0; i
< len
; i
++)
848 m_cacheContents
[i
] = m_index
[i
];
850 return m_cacheContents
;
853 int wxHtmlHelpData::GetIndexCnt()
855 return m_index
.size();
858 void wxHtmlHelpData::CleanCompatibilityData()
860 delete[] m_cacheContents
;
861 m_cacheContents
= NULL
;
862 delete[] m_cacheIndex
;
865 #endif // WXWIN_COMPATIBILITY_2_4
867 //----------------------------------------------------------------------------------
868 // wxHtmlSearchStatus functions
869 //----------------------------------------------------------------------------------
871 wxHtmlSearchStatus::wxHtmlSearchStatus(wxHtmlHelpData
* data
, const wxString
& keyword
,
872 bool case_sensitive
, bool whole_words_only
,
873 const wxString
& book
)
877 wxHtmlBookRecord
* bookr
= NULL
;
878 if (book
!= wxEmptyString
)
880 // we have to search in a specific book. Find it first
881 int i
, cnt
= data
->m_bookRecords
.GetCount();
882 for (i
= 0; i
< cnt
; i
++)
883 if (data
->m_bookRecords
[i
].GetTitle() == book
)
885 bookr
= &(data
->m_bookRecords
[i
]);
886 m_CurIndex
= bookr
->GetContentsStart();
887 m_MaxIndex
= bookr
->GetContentsEnd();
890 // check; we won't crash if the book doesn't exist, but it's Bad Anyway.
895 // no book specified; search all books
897 m_MaxIndex
= m_Data
->m_contents
.size();
899 m_Engine
.LookFor(keyword
, case_sensitive
, whole_words_only
);
900 m_Active
= (m_CurIndex
< m_MaxIndex
);
903 #if WXWIN_COMPATIBILITY_2_4
904 wxHtmlContentsItem
* wxHtmlSearchStatus::GetContentsItem()
906 static wxHtmlContentsItem it
;
907 it
= wxHtmlContentsItem(*m_CurItem
);
912 bool wxHtmlSearchStatus::Search()
915 int i
= m_CurIndex
; // shortcut
921 // sanity check. Illegal use, but we'll try to prevent a crash anyway
926 m_Name
= wxEmptyString
;
928 thepage
= m_Data
->m_contents
[i
].page
;
930 m_Active
= (++m_CurIndex
< m_MaxIndex
);
931 // check if it is same page with different anchor:
932 if (!m_LastPage
.empty())
934 const wxChar
*p1
, *p2
;
935 for (p1
= thepage
.c_str(), p2
= m_LastPage
.c_str();
936 *p1
!= 0 && *p1
!= _T('#') && *p1
== *p2
; p1
++, p2
++) {}
938 m_LastPage
= thepage
;
940 if (*p1
== 0 || *p1
== _T('#'))
943 else m_LastPage
= thepage
;
946 file
= fsys
.OpenFile(m_Data
->m_contents
[i
].book
->GetFullPath(thepage
));
949 if (m_Engine
.Scan(*file
))
951 m_Name
= m_Data
->m_contents
[i
].name
;
952 m_CurItem
= &m_Data
->m_contents
[i
];
967 //--------------------------------------------------------------------------------
968 // wxHtmlSearchEngine
969 //--------------------------------------------------------------------------------
971 void wxHtmlSearchEngine::LookFor(const wxString
& keyword
, bool case_sensitive
, bool whole_words_only
)
973 m_CaseSensitive
= case_sensitive
;
974 m_WholeWords
= whole_words_only
;
977 if (!m_CaseSensitive
)
978 m_Keyword
.LowerCase();
982 static inline bool WHITESPACE(wxChar c
)
984 return c
== _T(' ') || c
== _T('\n') || c
== _T('\r') || c
== _T('\t');
987 bool wxHtmlSearchEngine::Scan(const wxFSFile
& file
)
989 wxASSERT_MSG(!m_Keyword
.empty(), wxT("wxHtmlSearchEngine::LookFor must be called before scanning!"));
992 int wrd
= m_Keyword
.Length();
994 wxHtmlFilterHTML filter
;
995 wxString tmp
= filter
.ReadFile(file
);
996 int lng
= tmp
.length();
997 const wxChar
*buf
= tmp
.c_str();
999 if (!m_CaseSensitive
)
1002 const wxChar
*kwd
= m_Keyword
.c_str();
1006 for (i
= 0; i
< lng
- wrd
; i
++)
1008 if (WHITESPACE(buf
[i
])) continue;
1010 while ((j
< wrd
) && (buf
[i
+ j
] == kwd
[j
])) j
++;
1011 if (j
== wrd
&& WHITESPACE(buf
[i
+ j
])) { found
= true; break; }
1017 for (i
= 0; i
< lng
- wrd
; i
++)
1020 while ((j
< wrd
) && (buf
[i
+ j
] == kwd
[j
])) j
++;
1021 if (j
== wrd
) { found
= true; break; }