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
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"
19 #if wxUSE_HTML && wxUSE_STREAMS
28 #include "wx/html/helpdata.h"
29 #include "wx/tokenzr.h"
30 #include "wx/wfstream.h"
31 #include "wx/busyinfo.h"
32 #include "wx/encconv.h"
33 #include "wx/fontmap.h"
35 #include "wx/html/htmlpars.h"
36 #include "wx/html/htmldefs.h"
37 #include "wx/html/htmlfilt.h"
38 #include "wx/filename.h"
40 #include "wx/arrimpl.cpp"
41 WX_DEFINE_OBJARRAY(wxHtmlBookRecArray
)
42 WX_DEFINE_OBJARRAY(wxHtmlHelpDataItems
)
44 //-----------------------------------------------------------------------------
45 // static helper functions
46 //-----------------------------------------------------------------------------
48 // Reads one line, stores it into buf and returns pointer to new line or NULL.
49 static const wxChar
* ReadLine(const wxChar
*line
, wxChar
*buf
, size_t bufsize
)
51 wxChar
*writeptr
= buf
;
52 wxChar
*endptr
= buf
+ bufsize
- 1;
53 const wxChar
*readptr
= line
;
55 while (*readptr
!= 0 && *readptr
!= _T('\r') && *readptr
!= _T('\n') &&
57 *(writeptr
++) = *(readptr
++);
59 while (*readptr
== _T('\r') || *readptr
== _T('\n'))
70 wxHtmlHelpIndexCompareFunc(wxHtmlHelpDataItem
**a
, wxHtmlHelpDataItem
**b
)
72 wxHtmlHelpDataItem
*ia
= *a
;
73 wxHtmlHelpDataItem
*ib
= *b
;
80 if (ia
->parent
== ib
->parent
)
82 return ia
->name
.CmpNoCase(ib
->name
);
84 else if (ia
->level
== ib
->level
)
86 return wxHtmlHelpIndexCompareFunc(&ia
->parent
, &ib
->parent
);
90 wxHtmlHelpDataItem
*ia2
= ia
;
91 wxHtmlHelpDataItem
*ib2
= ib
;
93 while (ia2
->level
> ib2
->level
)
97 while (ib2
->level
> ia2
->level
)
104 int res
= wxHtmlHelpIndexCompareFunc(&ia2
, &ib2
);
107 else if (ia
->level
> ib
->level
)
114 //-----------------------------------------------------------------------------
116 //-----------------------------------------------------------------------------
118 class HP_Parser
: public wxHtmlParser
123 GetEntitiesParser()->SetEncoding(wxFONTENCODING_ISO8859_1
);
126 wxObject
* GetProduct() { return NULL
; }
129 virtual void AddText(const wxChar
* WXUNUSED(txt
)) {}
131 DECLARE_NO_COPY_CLASS(HP_Parser
)
135 //-----------------------------------------------------------------------------
137 //-----------------------------------------------------------------------------
139 class HP_TagHandler
: public wxHtmlTagHandler
142 wxString m_name
, m_page
;
147 wxHtmlHelpDataItem
*m_parentItem
;
148 wxHtmlBookRecord
*m_book
;
150 wxHtmlHelpDataItems
*m_data
;
153 HP_TagHandler(wxHtmlBookRecord
*b
) : wxHtmlTagHandler()
157 m_name
= m_page
= wxEmptyString
;
163 wxString
GetSupportedTags() { return wxT("UL,OBJECT,PARAM"); }
164 bool HandleTag(const wxHtmlTag
& tag
);
166 void Reset(wxHtmlHelpDataItems
& data
)
174 DECLARE_NO_COPY_CLASS(HP_TagHandler
)
178 bool HP_TagHandler::HandleTag(const wxHtmlTag
& tag
)
180 if (tag
.GetName() == wxT("UL"))
182 wxHtmlHelpDataItem
*oldparent
= m_parentItem
;
184 m_parentItem
= (m_count
> 0) ? &(*m_data
)[m_data
->size()-1] : NULL
;
187 m_parentItem
= oldparent
;
190 else if (tag
.GetName() == wxT("OBJECT"))
192 m_name
= m_page
= wxEmptyString
;
197 /* Valid HHW's file may contain only two object tags:
199 <OBJECT type="text/site properties">
200 <param name="ImageType" value="Folder">
205 <OBJECT type="text/sitemap">
206 <param name="Name" value="main page">
207 <param name="Local" value="another.htm">
210 We're interested in the latter. !page.IsEmpty() is valid
211 condition because text/site properties does not contain Local param
214 if (tag
.GetParam(wxT("TYPE")) == wxT("text/sitemap"))
216 wxHtmlHelpDataItem
*item
= new wxHtmlHelpDataItem();
217 item
->parent
= m_parentItem
;
218 item
->level
= m_level
;
232 if (m_name
.empty() && tag
.GetParam(wxT("NAME")) == wxT("Name"))
233 m_name
= tag
.GetParam(wxT("VALUE"));
234 if (tag
.GetParam(wxT("NAME")) == wxT("Local"))
235 m_page
= tag
.GetParam(wxT("VALUE"));
236 if (tag
.GetParam(wxT("NAME")) == wxT("ID"))
237 tag
.GetParamAsInt(wxT("VALUE"), &m_id
);
243 //-----------------------------------------------------------------------------
245 //-----------------------------------------------------------------------------
247 wxString
wxHtmlBookRecord::GetFullPath(const wxString
&page
) const
249 if (wxIsAbsolutePath(page
))
252 return m_BasePath
+ page
;
255 wxString
wxHtmlHelpDataItem::GetIndentedName() const
258 for (int i
= 1; i
< level
; i
++)
265 IMPLEMENT_DYNAMIC_CLASS(wxHtmlHelpData
, wxObject
)
267 wxHtmlHelpData::wxHtmlHelpData()
269 #if WXWIN_COMPATIBILITY_2_4
270 m_cacheContents
= NULL
;
275 wxHtmlHelpData::~wxHtmlHelpData()
277 #if WXWIN_COMPATIBILITY_2_4
278 CleanCompatibilityData();
282 bool wxHtmlHelpData::LoadMSProject(wxHtmlBookRecord
*book
, wxFileSystem
& fsys
,
283 const wxString
& indexfile
,
284 const wxString
& contentsfile
)
287 wxHtmlFilterHTML filter
;
292 HP_TagHandler
*handler
= new HP_TagHandler(book
);
293 parser
.AddTagHandler(handler
);
295 f
= ( contentsfile
.empty() ? (wxFSFile
*) NULL
: fsys
.OpenFile(contentsfile
) );
299 buf
= filter
.ReadFile(*f
);
301 handler
->Reset(m_contents
);
306 wxLogError(_("Cannot open contents file: %s"), contentsfile
.c_str());
309 f
= ( indexfile
.empty() ? (wxFSFile
*) NULL
: fsys
.OpenFile(indexfile
) );
313 buf
= filter
.ReadFile(*f
);
315 handler
->Reset(m_index
);
318 else if (!indexfile
.empty())
320 wxLogError(_("Cannot open index file: %s"), indexfile
.c_str());
325 inline static void CacheWriteInt32(wxOutputStream
*f
, wxInt32 value
)
327 wxInt32 x
= wxINT32_SWAP_ON_BE(value
);
328 f
->Write(&x
, sizeof(x
));
331 inline static wxInt32
CacheReadInt32(wxInputStream
*f
)
334 f
->Read(&x
, sizeof(x
));
335 return wxINT32_SWAP_ON_BE(x
);
338 inline static void CacheWriteString(wxOutputStream
*f
, const wxString
& str
)
340 const wxWX2MBbuf mbstr
= str
.mb_str(wxConvUTF8
);
341 size_t len
= strlen((const char*)mbstr
)+1;
342 CacheWriteInt32(f
, len
);
343 f
->Write((const char*)mbstr
, len
);
346 inline static wxString
CacheReadString(wxInputStream
*f
)
348 size_t len
= (size_t)CacheReadInt32(f
);
349 wxCharBuffer
str(len
-1);
350 f
->Read(str
.data(), len
);
351 return wxString(str
, wxConvUTF8
);
354 #define CURRENT_CACHED_BOOK_VERSION 5
356 // Additional flags to detect incompatibilities of the runtime environment:
357 #define CACHED_BOOK_FORMAT_FLAGS \
361 bool wxHtmlHelpData::LoadCachedBook(wxHtmlBookRecord
*book
, wxInputStream
*f
)
366 /* load header - version info : */
367 version
= CacheReadInt32(f
);
369 if (version
!= CURRENT_CACHED_BOOK_VERSION
)
371 // NB: We can just silently return false here and don't worry about
372 // it anymore, because AddBookParam will load the MS project in
373 // absence of (properly versioned) .cached file and automatically
374 // create new .cached file immediately afterward.
378 if (CacheReadInt32(f
) != CACHED_BOOK_FORMAT_FLAGS
)
381 /* load contents : */
382 st
= m_contents
.size();
383 newsize
= st
+ CacheReadInt32(f
);
384 m_contents
.Alloc(newsize
);
385 for (i
= st
; i
< newsize
; i
++)
387 wxHtmlHelpDataItem
*item
= new wxHtmlHelpDataItem
;
388 item
->level
= CacheReadInt32(f
);
389 item
->id
= CacheReadInt32(f
);
390 item
->name
= CacheReadString(f
);
391 item
->page
= CacheReadString(f
);
393 m_contents
.Add(item
);
398 newsize
= st
+ CacheReadInt32(f
);
399 m_index
.Alloc(newsize
);
400 for (i
= st
; i
< newsize
; i
++)
402 wxHtmlHelpDataItem
*item
= new wxHtmlHelpDataItem
;
403 item
->name
= CacheReadString(f
);
404 item
->page
= CacheReadString(f
);
405 item
->level
= CacheReadInt32(f
);
407 int parentShift
= CacheReadInt32(f
);
408 if (parentShift
!= 0)
409 item
->parent
= &m_index
[m_index
.size() - parentShift
];
416 bool wxHtmlHelpData::SaveCachedBook(wxHtmlBookRecord
*book
, wxOutputStream
*f
)
421 /* save header - version info : */
422 CacheWriteInt32(f
, CURRENT_CACHED_BOOK_VERSION
);
423 CacheWriteInt32(f
, CACHED_BOOK_FORMAT_FLAGS
);
425 /* save contents : */
426 int len
= m_contents
.size();
427 for (cnt
= 0, i
= 0; i
< len
; i
++)
428 if (m_contents
[i
].book
== book
&& m_contents
[i
].level
> 0)
430 CacheWriteInt32(f
, cnt
);
432 for (i
= 0; i
< len
; i
++)
434 if (m_contents
[i
].book
!= book
|| m_contents
[i
].level
== 0)
436 CacheWriteInt32(f
, m_contents
[i
].level
);
437 CacheWriteInt32(f
, m_contents
[i
].id
);
438 CacheWriteString(f
, m_contents
[i
].name
);
439 CacheWriteString(f
, m_contents
[i
].page
);
443 len
= m_index
.size();
444 for (cnt
= 0, i
= 0; i
< len
; i
++)
445 if (m_index
[i
].book
== book
&& m_index
[i
].level
> 0)
447 CacheWriteInt32(f
, cnt
);
449 for (i
= 0; i
< len
; i
++)
451 if (m_index
[i
].book
!= book
|| m_index
[i
].level
== 0)
453 CacheWriteString(f
, m_index
[i
].name
);
454 CacheWriteString(f
, m_index
[i
].page
);
455 CacheWriteInt32(f
, m_index
[i
].level
);
456 // save distance to parent item, if any:
457 if (m_index
[i
].parent
== NULL
)
459 CacheWriteInt32(f
, 0);
464 wxHtmlHelpDataItem
*parent
= m_index
[i
].parent
;
465 for (int j
= i
-1; j
>= 0; j
--)
467 if (m_index
[j
].book
== book
&& m_index
[j
].level
> 0)
469 if (&m_index
[j
] == parent
)
473 CacheWriteInt32(f
, cnt2
);
480 void wxHtmlHelpData::SetTempDir(const wxString
& path
)
486 if (wxIsAbsolutePath(path
)) m_tempPath
= path
;
487 else m_tempPath
= wxGetCwd() + _T("/") + path
;
489 if (m_tempPath
[m_tempPath
.length() - 1] != _T('/'))
490 m_tempPath
<< _T('/');
496 static wxString
SafeFileName(const wxString
& s
)
499 res
.Replace(wxT("#"), wxT("_"));
500 res
.Replace(wxT(":"), wxT("_"));
501 res
.Replace(wxT("\\"), wxT("_"));
502 res
.Replace(wxT("/"), wxT("_"));
506 bool wxHtmlHelpData::AddBookParam(const wxFSFile
& bookfile
,
507 wxFontEncoding encoding
,
508 const wxString
& title
, const wxString
& contfile
,
509 const wxString
& indexfile
, const wxString
& deftopic
,
510 const wxString
& path
)
514 wxHtmlBookRecord
*bookr
;
516 int IndexOld
= m_index
.size(),
517 ContentsOld
= m_contents
.size();
520 fsys
.ChangePathTo(path
, true);
522 size_t booksCnt
= m_bookRecords
.GetCount();
523 for (size_t i
= 0; i
< booksCnt
; i
++)
525 if ( m_bookRecords
[i
].GetBookFile() == bookfile
.GetLocation() )
526 return true; // book is (was) loaded
529 bookr
= new wxHtmlBookRecord(bookfile
.GetLocation(), fsys
.GetPath(), title
, deftopic
);
531 wxHtmlHelpDataItem
*bookitem
= new wxHtmlHelpDataItem
;
534 bookitem
->page
= deftopic
;
535 bookitem
->name
= title
;
536 bookitem
->book
= bookr
;
538 // store the contents index for later
539 int cont_start
= m_contents
.size();
541 m_contents
.Add(bookitem
);
543 // Try to find cached binary versions:
544 // 1. save file as book, but with .hhp.cached extension
545 // 2. same as 1. but in temp path
546 // 3. otherwise or if cache load failed, load it from MS.
548 fi
= fsys
.OpenFile(bookfile
.GetLocation() + wxT(".cached"));
552 fi
->GetModificationTime() < bookfile
.GetModificationTime() ||
553 #endif // wxUSE_DATETIME
554 !LoadCachedBook(bookr
, fi
->GetStream()))
556 if (fi
!= NULL
) delete fi
;
557 fi
= fsys
.OpenFile(m_tempPath
+ wxFileNameFromPath(bookfile
.GetLocation()) + wxT(".cached"));
558 if (m_tempPath
.empty() || fi
== NULL
||
560 fi
->GetModificationTime() < bookfile
.GetModificationTime() ||
561 #endif // wxUSE_DATETIME
562 !LoadCachedBook(bookr
, fi
->GetStream()))
564 LoadMSProject(bookr
, fsys
, indexfile
, contfile
);
565 if (!m_tempPath
.empty())
567 wxFileOutputStream
*outs
= new wxFileOutputStream(m_tempPath
+
568 SafeFileName(wxFileNameFromPath(bookfile
.GetLocation())) + wxT(".cached"));
569 SaveCachedBook(bookr
, outs
);
575 if (fi
!= NULL
) delete fi
;
577 // Now store the contents range
578 bookr
->SetContentsRange(cont_start
, m_contents
.size());
581 // MS HTML Help files [written by MS HTML Help Workshop] are broken
582 // in that the data are iso-8859-1 (including HTML entities), but must
583 // be interpreted as being in language's windows charset. Correct the
584 // differences here and also convert to wxConvLocal in ANSI build
585 if (encoding
!= wxFONTENCODING_SYSTEM
)
588 #define CORRECT_STR(str, conv) \
589 str = wxString((str).mb_str(wxConvISO8859_1), conv)
591 #define CORRECT_STR(str, conv) \
592 str = wxString((str).wc_str(conv), wxConvLocal)
594 wxCSConv
conv(encoding
);
595 size_t IndexCnt
= m_index
.size();
596 size_t ContentsCnt
= m_contents
.size();
598 for (i
= IndexOld
; i
< IndexCnt
; i
++)
600 CORRECT_STR(m_index
[i
].name
, conv
);
602 for (i
= ContentsOld
; i
< ContentsCnt
; i
++)
604 CORRECT_STR(m_contents
[i
].name
, conv
);
609 wxUnusedVar(IndexOld
);
610 wxUnusedVar(ContentsOld
);
611 wxASSERT_MSG(encoding
== wxFONTENCODING_SYSTEM
, wxT("Help files need charset conversion, but wxUSE_WCHAR_T is 0"));
612 #endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T
614 m_bookRecords
.Add(bookr
);
615 if (!m_index
.empty())
617 m_index
.Sort(wxHtmlHelpIndexCompareFunc
);
624 bool wxHtmlHelpData::AddBook(const wxString
& book
)
626 wxString
extension(book
.Right(4).Lower());
627 if (extension
== wxT(".zip") ||
629 extension
== wxT(".chm") /*compressed html help book*/ ||
631 extension
== wxT(".htb") /*html book*/)
638 if (extension
== wxT(".chm"))
639 s
= fsys
.FindFirst(book
+ wxT("#chm:*.hhp"), wxFILE
);
642 s
= fsys
.FindFirst(book
+ wxT("#zip:*.hhp"), wxFILE
);
646 if (AddBook(s
)) rt
= true;
656 wxString title
= _("noname"),
658 start
= wxEmptyString
,
659 contents
= wxEmptyString
,
660 index
= wxEmptyString
,
661 charset
= wxEmptyString
;
663 fi
= fsys
.OpenFile(book
);
666 wxLogError(_("Cannot open HTML help book: %s"), book
.c_str());
669 fsys
.ChangePathTo(book
);
671 const wxChar
*lineptr
;
674 wxHtmlFilterPlainText filter
;
675 tmp
= filter
.ReadFile(*fi
);
676 lineptr
= tmp
.c_str();
680 lineptr
= ReadLine(lineptr
, linebuf
, 300);
682 for (wxChar
*ch
= linebuf
; *ch
!= wxT('\0') && *ch
!= wxT('='); ch
++)
683 *ch
= (wxChar
)wxTolower(*ch
);
685 if (wxStrstr(linebuf
, _T("title=")) == linebuf
)
686 title
= linebuf
+ wxStrlen(_T("title="));
687 if (wxStrstr(linebuf
, _T("default topic=")) == linebuf
)
688 start
= linebuf
+ wxStrlen(_T("default topic="));
689 if (wxStrstr(linebuf
, _T("index file=")) == linebuf
)
690 index
= linebuf
+ wxStrlen(_T("index file="));
691 if (wxStrstr(linebuf
, _T("contents file=")) == linebuf
)
692 contents
= linebuf
+ wxStrlen(_T("contents file="));
693 if (wxStrstr(linebuf
, _T("charset=")) == linebuf
)
694 charset
= linebuf
+ wxStrlen(_T("charset="));
695 } while (lineptr
!= NULL
);
697 wxFontEncoding enc
= wxFONTENCODING_SYSTEM
;
699 if (charset
!= wxEmptyString
)
700 enc
= wxFontMapper::Get()->CharsetToEncoding(charset
);
703 bool rtval
= AddBookParam(*fi
, enc
,
704 title
, contents
, index
, start
, fsys
.GetPath());
707 #if WXWIN_COMPATIBILITY_2_4
708 CleanCompatibilityData();
714 wxString
wxHtmlHelpData::FindPageByName(const wxString
& x
)
721 /* 1. try to open given file: */
723 cnt
= m_bookRecords
.GetCount();
724 for (i
= 0; i
< cnt
; i
++)
726 f
= fsys
.OpenFile(m_bookRecords
[i
].GetFullPath(x
));
729 wxString url
= m_bookRecords
[i
].GetFullPath(x
);
736 /* 2. try to find a book: */
738 for (i
= 0; i
< cnt
; i
++)
740 if (m_bookRecords
[i
].GetTitle() == x
)
741 return m_bookRecords
[i
].GetFullPath(m_bookRecords
[i
].GetStart());
744 /* 3. try to find in contents: */
746 cnt
= m_contents
.size();
747 for (i
= 0; i
< cnt
; i
++)
749 if (m_contents
[i
].name
== x
)
750 return m_contents
[i
].GetFullPath();
754 /* 4. try to find in index: */
756 cnt
= m_index
.size();
757 for (i
= 0; i
< cnt
; i
++)
759 if (m_index
[i
].name
== x
)
760 return m_index
[i
].GetFullPath();
763 return wxEmptyString
;
766 wxString
wxHtmlHelpData::FindPageById(int id
)
768 size_t cnt
= m_contents
.size();
769 for (size_t i
= 0; i
< cnt
; i
++)
771 if (m_contents
[i
].id
== id
)
773 return m_contents
[i
].GetFullPath();
777 return wxEmptyString
;
780 #if WXWIN_COMPATIBILITY_2_4
781 wxHtmlContentsItem::wxHtmlContentsItem()
782 : m_Level(0), m_ID(wxID_ANY
), m_Name(NULL
), m_Page(NULL
), m_Book(NULL
),
787 wxHtmlContentsItem::wxHtmlContentsItem(const wxHtmlHelpDataItem
& d
)
792 m_Name
= wxStrdup(d
.name
.c_str());
793 m_Page
= wxStrdup(d
.page
.c_str());
797 wxHtmlContentsItem
& wxHtmlContentsItem::operator=(const wxHtmlContentsItem
& d
)
807 m_Name
= d
.m_Name
? wxStrdup(d
.m_Name
) : NULL
;
808 m_Page
= d
.m_Page
? wxStrdup(d
.m_Page
) : NULL
;
813 wxHtmlContentsItem::~wxHtmlContentsItem()
822 wxHtmlContentsItem
* wxHtmlHelpData::GetContents()
824 if (!m_cacheContents
&& !m_contents
.empty())
826 size_t len
= m_contents
.size();
827 m_cacheContents
= new wxHtmlContentsItem
[len
];
828 for (size_t i
= 0; i
< len
; i
++)
829 m_cacheContents
[i
] = m_contents
[i
];
831 return m_cacheContents
;
834 int wxHtmlHelpData::GetContentsCnt()
836 return m_contents
.size();
839 wxHtmlContentsItem
* wxHtmlHelpData::GetIndex()
841 if (!m_cacheContents
&& !m_index
.empty())
843 size_t len
= m_index
.size();
844 m_cacheContents
= new wxHtmlContentsItem
[len
];
845 for (size_t i
= 0; i
< len
; i
++)
846 m_cacheContents
[i
] = m_index
[i
];
848 return m_cacheContents
;
851 int wxHtmlHelpData::GetIndexCnt()
853 return m_index
.size();
856 void wxHtmlHelpData::CleanCompatibilityData()
858 delete[] m_cacheContents
;
859 m_cacheContents
= NULL
;
860 delete[] m_cacheIndex
;
863 #endif // WXWIN_COMPATIBILITY_2_4
865 //----------------------------------------------------------------------------------
866 // wxHtmlSearchStatus functions
867 //----------------------------------------------------------------------------------
869 wxHtmlSearchStatus::wxHtmlSearchStatus(wxHtmlHelpData
* data
, const wxString
& keyword
,
870 bool case_sensitive
, bool whole_words_only
,
871 const wxString
& book
)
875 wxHtmlBookRecord
* bookr
= NULL
;
876 if (book
!= wxEmptyString
)
878 // we have to search in a specific book. Find it first
879 int i
, cnt
= data
->m_bookRecords
.GetCount();
880 for (i
= 0; i
< cnt
; i
++)
881 if (data
->m_bookRecords
[i
].GetTitle() == book
)
883 bookr
= &(data
->m_bookRecords
[i
]);
884 m_CurIndex
= bookr
->GetContentsStart();
885 m_MaxIndex
= bookr
->GetContentsEnd();
888 // check; we won't crash if the book doesn't exist, but it's Bad Anyway.
893 // no book specified; search all books
895 m_MaxIndex
= m_Data
->m_contents
.size();
897 m_Engine
.LookFor(keyword
, case_sensitive
, whole_words_only
);
898 m_Active
= (m_CurIndex
< m_MaxIndex
);
901 #if WXWIN_COMPATIBILITY_2_4
902 wxHtmlContentsItem
* wxHtmlSearchStatus::GetContentsItem()
904 static wxHtmlContentsItem it
;
905 it
= wxHtmlContentsItem(*m_CurItem
);
910 bool wxHtmlSearchStatus::Search()
913 int i
= m_CurIndex
; // shortcut
919 // sanity check. Illegal use, but we'll try to prevent a crash anyway
924 m_Name
= wxEmptyString
;
926 thepage
= m_Data
->m_contents
[i
].page
;
928 m_Active
= (++m_CurIndex
< m_MaxIndex
);
929 // check if it is same page with different anchor:
930 if (!m_LastPage
.empty())
932 const wxChar
*p1
, *p2
;
933 for (p1
= thepage
.c_str(), p2
= m_LastPage
.c_str();
934 *p1
!= 0 && *p1
!= _T('#') && *p1
== *p2
; p1
++, p2
++) {}
936 m_LastPage
= thepage
;
938 if (*p1
== 0 || *p1
== _T('#'))
941 else m_LastPage
= thepage
;
944 file
= fsys
.OpenFile(m_Data
->m_contents
[i
].book
->GetFullPath(thepage
));
947 if (m_Engine
.Scan(*file
))
949 m_Name
= m_Data
->m_contents
[i
].name
;
950 m_CurItem
= &m_Data
->m_contents
[i
];
965 //--------------------------------------------------------------------------------
966 // wxHtmlSearchEngine
967 //--------------------------------------------------------------------------------
969 void wxHtmlSearchEngine::LookFor(const wxString
& keyword
, bool case_sensitive
, bool whole_words_only
)
971 m_CaseSensitive
= case_sensitive
;
972 m_WholeWords
= whole_words_only
;
975 if (!m_CaseSensitive
)
976 m_Keyword
.LowerCase();
980 static inline bool WHITESPACE(wxChar c
)
982 return c
== _T(' ') || c
== _T('\n') || c
== _T('\r') || c
== _T('\t');
985 bool wxHtmlSearchEngine::Scan(const wxFSFile
& file
)
987 wxASSERT_MSG(!m_Keyword
.empty(), wxT("wxHtmlSearchEngine::LookFor must be called before scanning!"));
990 int wrd
= m_Keyword
.length();
992 wxHtmlFilterHTML filter
;
993 wxString tmp
= filter
.ReadFile(file
);
994 int lng
= tmp
.length();
995 const wxChar
*buf
= tmp
.c_str();
997 if (!m_CaseSensitive
)
1000 const wxChar
*kwd
= m_Keyword
.c_str();
1004 for (i
= 0; i
< lng
- wrd
; i
++)
1006 if (WHITESPACE(buf
[i
])) continue;
1008 while ((j
< wrd
) && (buf
[i
+ j
] == kwd
[j
])) j
++;
1009 if (j
== wrd
&& WHITESPACE(buf
[i
+ j
])) { found
= true; break; }
1015 for (i
= 0; i
< lng
- wrd
; i
++)
1018 while ((j
< wrd
) && (buf
[i
+ j
] == kwd
[j
])) j
++;
1019 if (j
== wrd
) { found
= true; break; }