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 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
25 #if wxUSE_HTML && wxUSE_STREAMS
32 #include "wx/html/helpdata.h"
33 #include "wx/tokenzr.h"
34 #include "wx/wfstream.h"
35 #include "wx/busyinfo.h"
36 #include "wx/encconv.h"
37 #include "wx/fontmap.h"
39 #include "wx/html/htmlpars.h"
40 #include "wx/html/htmldefs.h"
41 #include "wx/filename.h"
43 #include "wx/arrimpl.cpp"
44 WX_DEFINE_OBJARRAY(wxHtmlBookRecArray
)
46 //-----------------------------------------------------------------------------
47 // static helper functions
48 //-----------------------------------------------------------------------------
50 // Reads one line, stores it into buf and returns pointer to new line or NULL.
51 static char* ReadLine(char *line
, char *buf
)
53 char *writeptr
= buf
, *readptr
= line
;
55 while (*readptr
!= 0 && *readptr
!= '\r' && *readptr
!= '\n') *(writeptr
++) = *(readptr
++);
57 while (*readptr
== '\r' || *readptr
== '\n') readptr
++;
58 if (*readptr
== 0) return NULL
;
64 static int LINKAGEMODE
IndexCompareFunc(const void *a
, const void *b
)
66 return wxStricmp(((wxHtmlContentsItem
*)a
)->m_Name
, ((wxHtmlContentsItem
*)b
)->m_Name
);
70 //-----------------------------------------------------------------------------
72 //-----------------------------------------------------------------------------
74 class HP_Parser
: public wxHtmlParser
77 wxObject
* GetProduct() { return NULL
; }
79 virtual void AddText(const wxChar
* WXUNUSED(txt
)) {}
83 //-----------------------------------------------------------------------------
85 //-----------------------------------------------------------------------------
87 class HP_TagHandler
: public wxHtmlTagHandler
90 wxString m_Name
, m_Page
;
94 wxHtmlContentsItem
*m_Items
;
96 wxHtmlBookRecord
*m_Book
;
99 HP_TagHandler(wxHtmlBookRecord
*b
) : wxHtmlTagHandler()
100 { m_Book
= b
; m_Items
= NULL
; m_ItemsCnt
= 0; m_Name
= m_Page
= wxEmptyString
;
101 m_Level
= 0; m_ID
= -1; }
102 wxString
GetSupportedTags() { return wxT("UL,OBJECT,PARAM"); }
103 bool HandleTag(const wxHtmlTag
& tag
);
104 void WriteOut(wxHtmlContentsItem
*& array
, int& size
);
105 void ReadIn(wxHtmlContentsItem
* array
, int size
);
109 bool HP_TagHandler::HandleTag(const wxHtmlTag
& tag
)
111 if (tag
.GetName() == wxT("UL"))
118 else if (tag
.GetName() == wxT("OBJECT"))
120 m_Name
= m_Page
= wxEmptyString
;
124 if (!m_Page
.IsEmpty())
125 /* Valid HHW's file may contain only two object tags:
127 <OBJECT type="text/site properties">
128 <param name="ImageType" value="Folder">
133 <OBJECT type="text/sitemap">
134 <param name="Name" value="main page">
135 <param name="Local" value="another.htm">
138 We're interested in the latter. !m_Page.IsEmpty() is valid
139 condition because text/site properties does not contain Local param
142 if (tag
.GetParam(wxT("TYPE")) == wxT("text/sitemap"))
144 if (m_ItemsCnt
% wxHTML_REALLOC_STEP
== 0)
145 m_Items
= (wxHtmlContentsItem
*) realloc(m_Items
,
146 (m_ItemsCnt
+ wxHTML_REALLOC_STEP
) *
147 sizeof(wxHtmlContentsItem
));
149 m_Items
[m_ItemsCnt
].m_Level
= m_Level
;
150 m_Items
[m_ItemsCnt
].m_ID
= m_ID
;
151 m_Items
[m_ItemsCnt
].m_Page
= new wxChar
[m_Page
.Length() + 1];
152 wxStrcpy(m_Items
[m_ItemsCnt
].m_Page
, m_Page
.c_str());
153 m_Items
[m_ItemsCnt
].m_Name
= new wxChar
[m_Name
.Length() + 1];
154 wxStrcpy(m_Items
[m_ItemsCnt
].m_Name
, m_Name
.c_str());
155 m_Items
[m_ItemsCnt
].m_Book
= m_Book
;
163 if (m_Name
== wxEmptyString
&& tag
.GetParam(wxT("NAME")) == wxT("Name"))
164 m_Name
= tag
.GetParam(wxT("VALUE"));
165 if (tag
.GetParam(wxT("NAME")) == wxT("Local"))
166 m_Page
= tag
.GetParam(wxT("VALUE"));
167 if (tag
.GetParam(wxT("NAME")) == wxT("ID"))
168 tag
.GetParamAsInt(wxT("VALUE"), &m_ID
);
175 void HP_TagHandler::WriteOut(wxHtmlContentsItem
*& array
, int& size
)
183 void HP_TagHandler::ReadIn(wxHtmlContentsItem
* array
, int size
)
192 //-----------------------------------------------------------------------------
194 //-----------------------------------------------------------------------------
196 wxString
wxHtmlBookRecord::GetFullPath(const wxString
&page
) const
198 if (wxIsAbsolutePath(page
))
201 return m_BasePath
+ page
;
206 IMPLEMENT_DYNAMIC_CLASS(wxHtmlHelpData
, wxObject
)
208 wxHtmlHelpData::wxHtmlHelpData()
210 m_TempPath
= wxEmptyString
;
218 wxHtmlHelpData::~wxHtmlHelpData()
222 m_BookRecords
.Empty();
225 for (i
= 0; i
< m_ContentsCnt
; i
++)
227 delete[] m_Contents
[i
].m_Page
;
228 delete[] m_Contents
[i
].m_Name
;
234 for (i
= 0; i
< m_IndexCnt
; i
++)
236 delete[] m_Index
[i
].m_Page
;
237 delete[] m_Index
[i
].m_Name
;
243 bool wxHtmlHelpData::LoadMSProject(wxHtmlBookRecord
*book
, wxFileSystem
& fsys
, const wxString
& indexfile
, const wxString
& contentsfile
)
251 HP_TagHandler
*handler
= new HP_TagHandler(book
);
252 parser
.AddTagHandler(handler
);
254 f
= ( contentsfile
.IsEmpty() ? (wxFSFile
*) NULL
: fsys
.OpenFile(contentsfile
) );
257 sz
= f
->GetStream()->GetSize();
258 buf
= new char[sz
+ 1];
260 f
->GetStream()->Read(buf
, sz
);
262 handler
->ReadIn(m_Contents
, m_ContentsCnt
);
264 handler
->WriteOut(m_Contents
, m_ContentsCnt
);
268 wxLogError(_("Cannot open contents file: %s"), contentsfile
.c_str());
270 f
= ( indexfile
.IsEmpty() ? (wxFSFile
*) NULL
: fsys
.OpenFile(indexfile
) );
273 sz
= f
->GetStream()->GetSize();
274 buf
= new char[sz
+ 1];
276 f
->GetStream()->Read(buf
, sz
);
278 handler
->ReadIn(m_Index
, m_IndexCnt
);
280 handler
->WriteOut(m_Index
, m_IndexCnt
);
283 else if (!indexfile
.IsEmpty())
284 wxLogError(_("Cannot open index file: %s"), indexfile
.c_str());
293 #define READ_STRING(f, s, lng) { char tmpc; for (int i = 0; i < lng; i++) { f->Read(&tmpc, 1); s[i] = (wxChar)tmpc;} }
294 #define WRITE_STRING(f, s, lng) { char tmpc; for (int i = 0; i < lng; i++) { tmpc = (char)s[i]; f->Write(&tmpc, 1);} }
298 #define READ_STRING(f, s, lng) f->Read(s, lng * sizeof(char));
299 #define WRITE_STRING(f, s, lng) f->Write(s, lng * sizeof(char));
304 #define CURRENT_CACHED_BOOK_VERSION 1
306 bool wxHtmlHelpData::LoadCachedBook(wxHtmlBookRecord
*book
, wxInputStream
*f
)
312 /* load header - version info : */
314 f
->Read(&x
, sizeof(x
));
315 version
= wxINT32_SWAP_ON_BE(x
);
317 if (version
!= CURRENT_CACHED_BOOK_VERSION
)
319 wxLogError(_("Incorrect version of HTML help book"));
321 // NOTE: when adding new version, please ensure backward compatibility!
324 /* load contents : */
326 f
->Read(&x
, sizeof(x
));
328 m_ContentsCnt
+= wxINT32_SWAP_ON_BE(x
);
329 m_Contents
= (wxHtmlContentsItem
*) realloc(m_Contents
,
330 (m_ContentsCnt
/ wxHTML_REALLOC_STEP
+ 1) *
331 wxHTML_REALLOC_STEP
* sizeof(wxHtmlContentsItem
));
332 for (i
= st
; i
< m_ContentsCnt
; i
++)
334 f
->Read(&x
, sizeof(x
));
335 m_Contents
[i
].m_Level
= wxINT32_SWAP_ON_BE(x
);
336 f
->Read(&x
, sizeof(x
));
337 m_Contents
[i
].m_ID
= wxINT32_SWAP_ON_BE(x
);
338 f
->Read(&x
, sizeof(x
)); x
= wxINT32_SWAP_ON_BE(x
);
339 m_Contents
[i
].m_Name
= new wxChar
[x
];
340 READ_STRING(f
, m_Contents
[i
].m_Name
, x
);
341 f
->Read(&x
, sizeof(x
)); x
= wxINT32_SWAP_ON_BE(x
);
342 m_Contents
[i
].m_Page
= new wxChar
[x
];
343 READ_STRING(f
, m_Contents
[i
].m_Page
, x
);
344 m_Contents
[i
].m_Book
= book
;
349 f
->Read(&x
, sizeof(x
));
351 m_IndexCnt
+= wxINT32_SWAP_ON_BE(x
);
352 m_Index
= (wxHtmlContentsItem
*) realloc(m_Index
, (m_IndexCnt
/ wxHTML_REALLOC_STEP
+ 1) *
353 wxHTML_REALLOC_STEP
* sizeof(wxHtmlContentsItem
));
354 for (i
= st
; i
< m_IndexCnt
; i
++)
356 f
->Read(&x
, sizeof(x
)); x
= wxINT32_SWAP_ON_BE(x
);
357 m_Index
[i
].m_Name
= new wxChar
[x
];
358 READ_STRING(f
, m_Index
[i
].m_Name
, x
);
359 f
->Read(&x
, sizeof(x
)); x
= wxINT32_SWAP_ON_BE(x
);
360 m_Index
[i
].m_Page
= new wxChar
[x
];
361 READ_STRING(f
, m_Index
[i
].m_Page
, x
);
362 m_Index
[i
].m_Book
= book
;
368 bool wxHtmlHelpData::SaveCachedBook(wxHtmlBookRecord
*book
, wxOutputStream
*f
)
373 /* save header - version info : */
375 x
= wxINT32_SWAP_ON_BE(CURRENT_CACHED_BOOK_VERSION
);
376 f
->Write(&x
, sizeof(x
));
378 /* save contents : */
381 for (i
= 0; i
< m_ContentsCnt
; i
++) if (m_Contents
[i
].m_Book
== book
&& m_Contents
[i
].m_Level
> 0) x
++;
382 x
= wxINT32_SWAP_ON_BE(x
);
383 f
->Write(&x
, sizeof(x
));
384 for (i
= 0; i
< m_ContentsCnt
; i
++)
386 if (m_Contents
[i
].m_Book
!= book
|| m_Contents
[i
].m_Level
== 0) continue;
387 x
= wxINT32_SWAP_ON_BE(m_Contents
[i
].m_Level
);
388 f
->Write(&x
, sizeof(x
));
389 x
= wxINT32_SWAP_ON_BE(m_Contents
[i
].m_ID
);
390 f
->Write(&x
, sizeof(x
));
391 x
= wxINT32_SWAP_ON_BE(wxStrlen(m_Contents
[i
].m_Name
) + 1);
392 f
->Write(&x
, sizeof(x
));
393 WRITE_STRING(f
, m_Contents
[i
].m_Name
, x
);
394 x
= wxINT32_SWAP_ON_BE(wxStrlen(m_Contents
[i
].m_Page
) + 1);
395 f
->Write(&x
, sizeof(x
));
396 WRITE_STRING(f
, m_Contents
[i
].m_Page
, x
);
402 for (i
= 0; i
< m_IndexCnt
; i
++) if (m_Index
[i
].m_Book
== book
&& m_Index
[i
].m_Level
> 0) x
++;
403 x
= wxINT32_SWAP_ON_BE(x
);
404 f
->Write(&x
, sizeof(x
));
405 for (i
= 0; i
< m_IndexCnt
; i
++)
407 if (m_Index
[i
].m_Book
!= book
|| m_Index
[i
].m_Level
== 0) continue;
408 x
= wxINT32_SWAP_ON_BE(wxStrlen(m_Index
[i
].m_Name
) + 1);
409 f
->Write(&x
, sizeof(x
));
410 WRITE_STRING(f
, m_Index
[i
].m_Name
, x
);
411 x
= wxINT32_SWAP_ON_BE(wxStrlen(m_Index
[i
].m_Page
) + 1);
412 f
->Write(&x
, sizeof(x
));
413 WRITE_STRING(f
, m_Index
[i
].m_Page
, x
);
419 void wxHtmlHelpData::SetTempDir(const wxString
& path
)
421 if (path
== wxEmptyString
) m_TempPath
= path
;
424 if (wxIsAbsolutePath(path
)) m_TempPath
= path
;
425 else m_TempPath
= wxGetCwd() + _T("/") + path
;
427 if (m_TempPath
[m_TempPath
.Length() - 1] != _T('/'))
428 m_TempPath
<< _T('/');
434 static wxString
SafeFileName(const wxString
& s
)
437 res
.Replace(wxT("#"), wxT("_"));
438 res
.Replace(wxT(":"), wxT("_"));
439 res
.Replace(wxT("\\"), wxT("_"));
440 res
.Replace(wxT("/"), wxT("_"));
444 bool wxHtmlHelpData::AddBookParam(const wxFSFile
& bookfile
,
445 wxFontEncoding encoding
,
446 const wxString
& title
, const wxString
& contfile
,
447 const wxString
& indexfile
, const wxString
& deftopic
,
448 const wxString
& path
)
452 wxHtmlBookRecord
*bookr
;
454 int IndexOld
= m_IndexCnt
,
455 ContentsOld
= m_ContentsCnt
;
457 if (! path
.IsEmpty())
458 fsys
.ChangePathTo(path
, TRUE
);
460 bookr
= new wxHtmlBookRecord(fsys
.GetPath(), title
, deftopic
);
462 if (m_ContentsCnt
% wxHTML_REALLOC_STEP
== 0)
463 m_Contents
= (wxHtmlContentsItem
*) realloc(m_Contents
, (m_ContentsCnt
+ wxHTML_REALLOC_STEP
) * sizeof(wxHtmlContentsItem
));
464 m_Contents
[m_ContentsCnt
].m_Level
= 0;
465 m_Contents
[m_ContentsCnt
].m_ID
= 0;
466 m_Contents
[m_ContentsCnt
].m_Page
= new wxChar
[deftopic
.Length() + 1];
467 wxStrcpy(m_Contents
[m_ContentsCnt
].m_Page
, deftopic
.c_str());
468 m_Contents
[m_ContentsCnt
].m_Name
= new wxChar
[title
.Length() + 1];
469 wxStrcpy(m_Contents
[m_ContentsCnt
].m_Name
, title
.c_str());
470 m_Contents
[m_ContentsCnt
].m_Book
= bookr
;
472 // store the contents index for later
473 int cont_start
= m_ContentsCnt
++;
475 // Try to find cached binary versions:
476 // 1. save file as book, but with .hhp.cached extension
477 // 2. same as 1. but in temp path
478 // 3. otherwise or if cache load failed, load it from MS.
480 fi
= fsys
.OpenFile(bookfile
.GetLocation() + wxT(".cached"));
483 fi
->GetModificationTime() < bookfile
.GetModificationTime() ||
484 !LoadCachedBook(bookr
, fi
->GetStream()))
486 if (fi
!= NULL
) delete fi
;
487 fi
= fsys
.OpenFile(m_TempPath
+ wxFileNameFromPath(bookfile
.GetLocation()) + wxT(".cached"));
488 if (m_TempPath
== wxEmptyString
|| fi
== NULL
||
489 fi
->GetModificationTime() < bookfile
.GetModificationTime() ||
490 !LoadCachedBook(bookr
, fi
->GetStream()))
492 LoadMSProject(bookr
, fsys
, indexfile
, contfile
);
493 if (m_TempPath
!= wxEmptyString
)
495 wxFileOutputStream
*outs
= new wxFileOutputStream(m_TempPath
+
496 SafeFileName(wxFileNameFromPath(bookfile
.GetLocation())) + wxT(".cached"));
497 SaveCachedBook(bookr
, outs
);
503 if (fi
!= NULL
) delete fi
;
505 // Now store the contents range
506 bookr
->SetContentsRange(cont_start
, m_ContentsCnt
);
508 // Convert encoding, if neccessary:
509 if (encoding
!= wxFONTENCODING_SYSTEM
)
511 wxFontEncodingArray a
= wxEncodingConverter::GetPlatformEquivalents(encoding
);
512 if (a
.GetCount() != 0 && a
[0] != encoding
)
515 wxEncodingConverter conv
;
516 conv
.Init(encoding
, a
[0]);
518 for (i
= IndexOld
; i
< m_IndexCnt
; i
++)
519 conv
.Convert(m_Index
[i
].m_Name
);
520 for (i
= ContentsOld
; i
< m_ContentsCnt
; i
++)
521 conv
.Convert(m_Contents
[i
].m_Name
);
525 m_BookRecords
.Add(bookr
);
527 qsort(m_Index
, m_IndexCnt
, sizeof(wxHtmlContentsItem
), IndexCompareFunc
);
533 bool wxHtmlHelpData::AddBook(const wxString
& book
)
535 if (book
.Right(4).Lower() == wxT(".zip") ||
536 book
.Right(4).Lower() == wxT(".htb") /*html book*/)
543 s
= fsys
.FindFirst(book
+ wxT("#zip:") + wxT("*.hhp"), wxFILE
);
546 if (AddBook(s
)) rt
= TRUE
;
562 char *buff
, *lineptr
;
565 wxString title
= _("noname"),
567 start
= wxEmptyString
,
568 contents
= wxEmptyString
,
569 index
= wxEmptyString
,
570 charset
= wxEmptyString
;
572 #if defined(__WXMAC__) && !defined(__DARWIN__)
573 if (wxIsAbsolutePath(book
)) bookFull
= book
;
574 else bookFull
= wxGetCwd() + book
; // no slash or dot
575 wxFileName
fn( bookFull
);
576 bookFull
= fn
.GetFullPath( wxPATH_UNIX
);
578 if (wxIsAbsolutePath(book
)) bookFull
= book
;
579 else bookFull
= wxGetCwd() + "/" + book
;
582 fi
= fsys
.OpenFile(bookFull
);
585 wxLogError(_("Cannot open HTML help book: %s"), bookFull
.c_str());
588 fsys
.ChangePathTo(bookFull
);
591 buff
= new char[sz
+ 1];
597 lineptr
= ReadLine(lineptr
, linebuf
);
599 if (strstr(linebuf
, "Title=") == linebuf
)
600 title
= linebuf
+ strlen("Title=");
601 if (strstr(linebuf
, "Default topic=") == linebuf
)
602 start
= linebuf
+ strlen("Default topic=");
603 if (strstr(linebuf
, "Index file=") == linebuf
)
604 index
= linebuf
+ strlen("Index file=");
605 if (strstr(linebuf
, "Contents file=") == linebuf
)
606 contents
= linebuf
+ strlen("Contents file=");
607 if (strstr(linebuf
, "Charset=") == linebuf
)
608 charset
= linebuf
+ strlen("Charset=");
609 } while (lineptr
!= NULL
);
613 if (charset
== wxEmptyString
) enc
= wxFONTENCODING_SYSTEM
;
614 else enc
= wxTheFontMapper
->CharsetToEncoding(charset
);
615 bool rtval
= AddBookParam(*fi
, enc
,
616 title
, contents
, index
, start
, fsys
.GetPath());
622 wxString
wxHtmlHelpData::FindPageByName(const wxString
& x
)
628 wxString
url(wxEmptyString
);
630 /* 1. try to open given file: */
632 cnt
= m_BookRecords
.GetCount();
633 for (i
= 0; i
< cnt
; i
++)
635 f
= fsys
.OpenFile(m_BookRecords
[i
].GetFullPath(x
));
638 url
= m_BookRecords
[i
].GetFullPath(x
);
645 /* 2. try to find a book: */
647 for (i
= 0; i
< cnt
; i
++)
649 if (m_BookRecords
[i
].GetTitle() == x
)
651 url
= m_BookRecords
[i
].GetFullPath(m_BookRecords
[i
].GetStart());
656 /* 3. try to find in contents: */
659 for (i
= 0; i
< cnt
; i
++)
661 if (wxStrcmp(m_Contents
[i
].m_Name
, x
) == 0)
663 url
= m_Contents
[i
].GetFullPath();
669 /* 4. try to find in index: */
672 for (i
= 0; i
< cnt
; i
++)
674 if (wxStrcmp(m_Index
[i
].m_Name
, x
) == 0)
676 url
= m_Index
[i
].GetFullPath();
684 wxString
wxHtmlHelpData::FindPageById(int id
)
687 wxString
url(wxEmptyString
);
689 for (i
= 0; i
< m_ContentsCnt
; i
++)
691 if (m_Contents
[i
].m_ID
== id
)
693 url
= m_Contents
[i
].GetFullPath();
701 //----------------------------------------------------------------------------------
702 // wxHtmlSearchStatus functions
703 //----------------------------------------------------------------------------------
705 wxHtmlSearchStatus::wxHtmlSearchStatus(wxHtmlHelpData
* data
, const wxString
& keyword
,
706 bool case_sensitive
, bool whole_words_only
,
707 const wxString
& book
)
711 wxHtmlBookRecord
* bookr
= NULL
;
712 if (book
!= wxEmptyString
)
714 // we have to search in a specific book. Find it first
715 int i
, cnt
= data
->m_BookRecords
.GetCount();
716 for (i
= 0; i
< cnt
; i
++)
717 if (data
->m_BookRecords
[i
].GetTitle() == book
)
719 bookr
= &(data
->m_BookRecords
[i
]);
720 m_CurIndex
= bookr
->GetContentsStart();
721 m_MaxIndex
= bookr
->GetContentsEnd();
724 // check; we won't crash if the book doesn't exist, but it's Bad Anyway.
729 // no book specified; search all books
731 m_MaxIndex
= m_Data
->m_ContentsCnt
;
733 m_Engine
.LookFor(keyword
, case_sensitive
, whole_words_only
);
734 m_Active
= (m_CurIndex
< m_MaxIndex
);
738 bool wxHtmlSearchStatus::Search()
741 int i
= m_CurIndex
; // shortcut
747 // sanity check. Illegal use, but we'll try to prevent a crash anyway
752 m_Name
= wxEmptyString
;
753 m_ContentsItem
= NULL
;
754 thepage
= m_Data
->m_Contents
[i
].m_Page
;
756 m_Active
= (++m_CurIndex
< m_MaxIndex
);
757 // check if it is same page with different anchor:
758 if (m_LastPage
!= NULL
)
761 for (p1
= thepage
, p2
= m_LastPage
;
762 *p1
!= 0 && *p1
!= _T('#') && *p1
== *p2
; p1
++, p2
++) {}
764 m_LastPage
= thepage
;
766 if (*p1
== 0 || *p1
== _T('#'))
769 else m_LastPage
= thepage
;
772 file
= fsys
.OpenFile(m_Data
->m_Contents
[i
].m_Book
->GetFullPath(thepage
));
775 if (m_Engine
.Scan(file
->GetStream()))
777 m_Name
= m_Data
->m_Contents
[i
].m_Name
;
778 m_ContentsItem
= m_Data
->m_Contents
+ i
;
793 //--------------------------------------------------------------------------------
795 //--------------------------------------------------------------------------------
797 void wxSearchEngine::LookFor(const wxString
& keyword
, bool case_sensitive
, bool whole_words_only
)
799 m_CaseSensitive
= case_sensitive
;
800 m_WholeWords
= whole_words_only
;
801 if (m_Keyword
) delete[] m_Keyword
;
802 m_Keyword
= new wxChar
[keyword
.Length() + 1];
803 wxStrcpy(m_Keyword
, keyword
.c_str());
805 if (!m_CaseSensitive
)
807 for (int i
= wxStrlen(m_Keyword
) - 1; i
>= 0; i
--)
809 if ((m_Keyword
[i
] >= wxT('A')) && (m_Keyword
[i
] <= wxT('Z')))
810 m_Keyword
[i
] += wxT('a') - wxT('A');
817 #define WHITESPACE(c) (c == ' ' || c == '\n' || c == '\r' || c == '\t')
819 bool wxSearchEngine::Scan(wxInputStream
*stream
)
821 wxASSERT_MSG(m_Keyword
!= NULL
, wxT("wxSearchEngine::LookFor must be called before scanning!"));
824 int lng
= stream
->GetSize();
825 int wrd
= wxStrlen(m_Keyword
);
827 char *buf
= new char[lng
+ 1];
828 stream
->Read(buf
, lng
);
831 if (!m_CaseSensitive
)
832 for (i
= 0; i
< lng
; i
++)
833 if ((buf
[i
] >= 'A') && (buf
[i
] <= 'Z')) buf
[i
] += 'a' - 'A';
837 for (i
= 0; i
< lng
- wrd
; i
++)
839 if (WHITESPACE(buf
[i
])) continue;
841 while ((j
< wrd
) && (buf
[i
+ j
] == m_Keyword
[j
])) j
++;
842 if (j
== wrd
&& WHITESPACE(buf
[i
+ j
])) { found
= TRUE
; break; }
848 for (i
= 0; i
< lng
- wrd
; i
++)
851 while ((j
< wrd
) && (buf
[i
+ j
] == m_Keyword
[j
])) j
++;
852 if (j
== wrd
) { found
= TRUE
; break; }