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"
31 #include "wx/html/helpdata.h"
32 #include "wx/tokenzr.h"
33 #include "wx/wfstream.h"
34 #include "wx/busyinfo.h"
35 #include "wx/encconv.h"
36 #include "wx/fontmap.h"
37 #include "wx/html/htmlpars.h"
38 #include "wx/html/htmldefs.h"
40 #include "wx/arrimpl.cpp"
41 WX_DEFINE_OBJARRAY(wxHtmlBookRecArray
)
43 //-----------------------------------------------------------------------------
44 // static helper functions
45 //-----------------------------------------------------------------------------
47 // Reads one line, stores it into buf and returns pointer to new line or NULL.
48 static char* ReadLine(char *line
, char *buf
)
50 char *writeptr
= buf
, *readptr
= line
;
52 while (*readptr
!= 0 && *readptr
!= '\r' && *readptr
!= '\n') *(writeptr
++) = *(readptr
++);
54 while (*readptr
== '\r' || *readptr
== '\n') readptr
++;
55 if (*readptr
== 0) return NULL
;
61 static int LINKAGEMODE
IndexCompareFunc(const void *a
, const void *b
)
63 return wxStrcmp(((wxHtmlContentsItem
*)a
) -> m_Name
, ((wxHtmlContentsItem
*)b
) -> m_Name
);
67 //-----------------------------------------------------------------------------
69 //-----------------------------------------------------------------------------
71 class HP_Parser
: public wxHtmlParser
74 void AddText(const char* WXUNUSED(text
)) { }
75 wxObject
* GetProduct() { return NULL
; }
79 //-----------------------------------------------------------------------------
81 //-----------------------------------------------------------------------------
83 class HP_TagHandler
: public wxHtmlTagHandler
86 wxString m_Name
, m_Page
;
90 wxHtmlContentsItem
*m_Items
;
92 wxHtmlBookRecord
*m_Book
;
95 HP_TagHandler(wxHtmlBookRecord
*b
) : wxHtmlTagHandler() {m_Book
= b
; m_Items
= NULL
; m_ItemsCnt
= 0; m_Name
= m_Page
= wxEmptyString
; m_Level
= 0; }
96 wxString
GetSupportedTags() { return wxT("UL,OBJECT,PARAM"); }
97 bool HandleTag(const wxHtmlTag
& tag
);
98 void WriteOut(wxHtmlContentsItem
*& array
, int& size
);
99 void ReadIn(wxHtmlContentsItem
* array
, int size
);
103 bool HP_TagHandler::HandleTag(const wxHtmlTag
& tag
)
105 if (tag
.GetName() == wxT("UL")) {
111 else if (tag
.GetName() == wxT("OBJECT")) {
112 m_Name
= m_Page
= wxEmptyString
;
115 if (!m_Page
.IsEmpty())
116 /* should be 'if (tag.GetParam("TYPE") == "text/sitemap")'
117 but this works fine. Valid HHW's file may contain only two
120 <OBJECT type="text/site properties">
121 <param name="ImageType" value="Folder">
126 <OBJECT type="text/sitemap">
127 <param name="Name" value="main page">
128 <param name="Local" value="another.htm">
131 We're interested in the latter. !m_Page.IsEmpty() is valid
132 condition because text/site properties does not contain Local param
135 if (m_ItemsCnt
% wxHTML_REALLOC_STEP
== 0)
136 m_Items
= (wxHtmlContentsItem
*) realloc(m_Items
, (m_ItemsCnt
+ wxHTML_REALLOC_STEP
) * sizeof(wxHtmlContentsItem
));
137 m_Items
[m_ItemsCnt
].m_Level
= m_Level
;
138 m_Items
[m_ItemsCnt
].m_ID
= m_ID
;
139 m_Items
[m_ItemsCnt
].m_Page
= new wxChar
[m_Page
.Length() + 1];
140 wxStrcpy(m_Items
[m_ItemsCnt
].m_Page
, m_Page
.c_str());
141 m_Items
[m_ItemsCnt
].m_Name
= new wxChar
[m_Name
.Length() + 1];
142 wxStrcpy(m_Items
[m_ItemsCnt
].m_Name
, m_Name
.c_str());
143 m_Items
[m_ItemsCnt
].m_Book
= m_Book
;
150 if (m_Name
== wxEmptyString
&& tag
.GetParam(wxT("NAME")) == wxT("Name")) m_Name
= tag
.GetParam(wxT("VALUE"));
151 if (tag
.GetParam(wxT("NAME")) == wxT("Local")) m_Page
= tag
.GetParam(wxT("VALUE"));
152 if (tag
.GetParam(wxT("NAME")) == wxT("ID")) tag
.ScanParam(wxT("VALUE"), wxT("%i"), &m_ID
);
159 void HP_TagHandler::WriteOut(wxHtmlContentsItem
*& array
, int& size
)
167 void HP_TagHandler::ReadIn(wxHtmlContentsItem
* array
, int size
)
176 //-----------------------------------------------------------------------------
178 //-----------------------------------------------------------------------------
180 IMPLEMENT_DYNAMIC_CLASS(wxHtmlHelpData
, wxObject
)
182 wxHtmlHelpData::wxHtmlHelpData()
184 m_TempPath
= wxEmptyString
;
192 wxHtmlHelpData::~wxHtmlHelpData()
196 m_BookRecords
.Empty();
198 for (i
= 0; i
< m_ContentsCnt
; i
++) {
199 delete[] m_Contents
[i
].m_Page
;
200 delete[] m_Contents
[i
].m_Name
;
205 for (i
= 0; i
< m_IndexCnt
; i
++) {
206 delete[] m_Index
[i
].m_Page
;
207 delete[] m_Index
[i
].m_Name
;
213 bool wxHtmlHelpData::LoadMSProject(wxHtmlBookRecord
*book
, wxFileSystem
& fsys
, const wxString
& indexfile
, const wxString
& contentsfile
)
221 HP_TagHandler
*handler
= new HP_TagHandler(book
);
222 parser
.AddTagHandler(handler
);
224 f
= ( contentsfile
.IsEmpty() ? 0 : fsys
.OpenFile(contentsfile
) );
226 sz
= f
-> GetStream() -> GetSize();
227 buf
= new char[sz
+ 1];
229 f
-> GetStream() -> Read(buf
, sz
);
231 handler
-> ReadIn(m_Contents
, m_ContentsCnt
);
233 handler
-> WriteOut(m_Contents
, m_ContentsCnt
);
237 f
= ( indexfile
.IsEmpty() ? 0 : fsys
.OpenFile(indexfile
) );
239 sz
= f
-> GetStream() -> GetSize();
240 buf
= new char[sz
+ 1];
242 f
-> GetStream() -> Read(buf
, sz
);
244 handler
-> ReadIn(m_Index
, m_IndexCnt
);
246 handler
-> WriteOut(m_Index
, m_IndexCnt
);
257 #define READ_STRING(f, s, lng) { char tmpc; for (int i = 0; i < lng; i++) { f -> Read(&tmpc, 1); s[i] = (wxChar)tmpc;} }
258 #define WRITE_STRING(f, s, lng) { char tmpc; for (int i = 0; i < lng; i++) { tmpc = (char)s[i]; f -> Write(&tmpc, 1);} }
262 #define READ_STRING(f, s, lng) f -> Read(s, lng * sizeof(char));
263 #define WRITE_STRING(f, s, lng) f -> Write(s, lng * sizeof(char));
268 #define CURRENT_CACHED_BOOK_VERSION 1
270 bool wxHtmlHelpData::LoadCachedBook(wxHtmlBookRecord
*book
, wxInputStream
*f
)
276 /* load header - version info : */
278 f
-> Read(&x
, sizeof(x
));
279 version
= wxINT32_SWAP_ON_BE(x
);
281 if (version
!= CURRENT_CACHED_BOOK_VERSION
) return FALSE
;
282 // NOTE: when adding new version, please ensure backward compatibility!
284 /* load contents : */
286 f
-> Read(&x
, sizeof(x
));
288 m_ContentsCnt
+= wxINT32_SWAP_ON_BE(x
);
289 m_Contents
= (wxHtmlContentsItem
*) realloc(m_Contents
,
290 (m_ContentsCnt
/ wxHTML_REALLOC_STEP
+ 1) *
291 wxHTML_REALLOC_STEP
* sizeof(wxHtmlContentsItem
));
292 for (i
= st
; i
< m_ContentsCnt
; i
++) {
293 f
-> Read(&x
, sizeof(x
));
294 m_Contents
[i
].m_Level
= wxINT32_SWAP_ON_BE(x
);
295 f
-> Read(&x
, sizeof(x
));
296 m_Contents
[i
].m_ID
= wxINT32_SWAP_ON_BE(x
);
297 f
-> Read(&x
, sizeof(x
)); x
= wxINT32_SWAP_ON_BE(x
);
298 m_Contents
[i
].m_Name
= new wxChar
[x
];
299 READ_STRING(f
, m_Contents
[i
].m_Name
, x
);
300 f
-> Read(&x
, sizeof(x
)); x
= wxINT32_SWAP_ON_BE(x
);
301 m_Contents
[i
].m_Page
= new wxChar
[x
];
302 READ_STRING(f
, m_Contents
[i
].m_Page
, x
);
303 m_Contents
[i
].m_Book
= book
;
308 f
-> Read(&x
, sizeof(x
));
310 m_IndexCnt
+= wxINT32_SWAP_ON_BE(x
);
311 m_Index
= (wxHtmlContentsItem
*) realloc(m_Index
, (m_IndexCnt
/ wxHTML_REALLOC_STEP
+ 1) *
312 wxHTML_REALLOC_STEP
* sizeof(wxHtmlContentsItem
));
313 for (i
= st
; i
< m_IndexCnt
; i
++) {
314 f
-> Read(&x
, sizeof(x
)); x
= wxINT32_SWAP_ON_BE(x
);
315 m_Index
[i
].m_Name
= new wxChar
[x
];
316 READ_STRING(f
, m_Index
[i
].m_Name
, x
);
317 f
-> Read(&x
, sizeof(x
)); x
= wxINT32_SWAP_ON_BE(x
);
318 m_Index
[i
].m_Page
= new wxChar
[x
];
319 READ_STRING(f
, m_Index
[i
].m_Page
, x
);
320 m_Index
[i
].m_Book
= book
;
326 bool wxHtmlHelpData::SaveCachedBook(wxHtmlBookRecord
*book
, wxOutputStream
*f
)
331 /* save header - version info : */
333 x
= wxINT32_SWAP_ON_BE(CURRENT_CACHED_BOOK_VERSION
);
334 f
-> Write(&x
, sizeof(x
));
336 /* save contents : */
339 for (i
= 0; i
< m_ContentsCnt
; i
++) if (m_Contents
[i
].m_Book
== book
&& m_Contents
[i
].m_Level
> 0) x
++;
340 x
= wxINT32_SWAP_ON_BE(x
);
341 f
-> Write(&x
, sizeof(x
));
342 for (i
= 0; i
< m_ContentsCnt
; i
++) {
343 if (m_Contents
[i
].m_Book
!= book
|| m_Contents
[i
].m_Level
== 0) continue;
344 x
= wxINT32_SWAP_ON_BE(m_Contents
[i
].m_Level
);
345 f
-> Write(&x
, sizeof(x
));
346 x
= wxINT32_SWAP_ON_BE(m_Contents
[i
].m_ID
);
347 f
-> Write(&x
, sizeof(x
));
348 x
= wxINT32_SWAP_ON_BE(wxStrlen(m_Contents
[i
].m_Name
) + 1);
349 f
-> Write(&x
, sizeof(x
));
350 WRITE_STRING(f
, m_Contents
[i
].m_Name
, x
);
351 x
= wxINT32_SWAP_ON_BE(wxStrlen(m_Contents
[i
].m_Page
) + 1);
352 f
-> Write(&x
, sizeof(x
));
353 WRITE_STRING(f
, m_Contents
[i
].m_Page
, x
);
359 for (i
= 0; i
< m_IndexCnt
; i
++) if (m_Index
[i
].m_Book
== book
&& m_Index
[i
].m_Level
> 0) x
++;
360 x
= wxINT32_SWAP_ON_BE(x
);
361 f
-> Write(&x
, sizeof(x
));
362 for (i
= 0; i
< m_IndexCnt
; i
++) {
363 if (m_Index
[i
].m_Book
!= book
|| m_Index
[i
].m_Level
== 0) continue;
364 x
= wxINT32_SWAP_ON_BE(wxStrlen(m_Index
[i
].m_Name
) + 1);
365 f
-> Write(&x
, sizeof(x
));
366 WRITE_STRING(f
, m_Index
[i
].m_Name
, x
);
367 x
= wxINT32_SWAP_ON_BE(wxStrlen(m_Index
[i
].m_Page
) + 1);
368 f
-> Write(&x
, sizeof(x
));
369 WRITE_STRING(f
, m_Index
[i
].m_Page
, x
);
375 void wxHtmlHelpData::SetTempDir(const wxString
& path
)
377 if (path
== wxEmptyString
) m_TempPath
= path
;
379 if (wxIsAbsolutePath(path
)) m_TempPath
= path
;
380 else m_TempPath
= wxGetCwd() + _T("/") + path
;
382 if (m_TempPath
[m_TempPath
.Length() - 1] != _T('/'))
383 m_TempPath
<< _T('/');
388 bool wxHtmlHelpData::AddBookParam(const wxFSFile
& bookfile
,
389 wxFontEncoding encoding
,
390 const wxString
& title
, const wxString
& contfile
,
391 const wxString
& indexfile
, const wxString
& deftopic
,
392 const wxString
& path
)
396 wxHtmlBookRecord
*bookr
;
398 int IndexOld
= m_IndexCnt
,
399 ContentsOld
= m_ContentsCnt
;
401 if (! path
.IsEmpty())
402 fsys
.ChangePathTo(path
, TRUE
);
404 bookr
= new wxHtmlBookRecord(fsys
.GetPath(), title
, deftopic
);
406 if (m_ContentsCnt
% wxHTML_REALLOC_STEP
== 0)
407 m_Contents
= (wxHtmlContentsItem
*) realloc(m_Contents
, (m_ContentsCnt
+ wxHTML_REALLOC_STEP
) * sizeof(wxHtmlContentsItem
));
408 m_Contents
[m_ContentsCnt
].m_Level
= 0;
409 m_Contents
[m_ContentsCnt
].m_ID
= 0;
410 m_Contents
[m_ContentsCnt
].m_Page
= new wxChar
[deftopic
.Length() + 1];
411 wxStrcpy(m_Contents
[m_ContentsCnt
].m_Page
, deftopic
.c_str());
412 m_Contents
[m_ContentsCnt
].m_Name
= new wxChar
[title
.Length() + 1];
413 wxStrcpy(m_Contents
[m_ContentsCnt
].m_Name
, title
.c_str());
414 m_Contents
[m_ContentsCnt
].m_Book
= bookr
;
416 // store the contents index for later
417 int cont_start
= m_ContentsCnt
++;
419 // Try to find cached binary versions:
420 // 1. save file as book, but with .hhp.cached extension
421 // 2. same as 1. but in temp path
422 // 3. otherwise or if cache load failed, load it from MS.
424 fi
= fsys
.OpenFile(bookfile
.GetLocation() + wxT(".cached"));
427 fi
-> GetModificationTime() < bookfile
.GetModificationTime() ||
428 !LoadCachedBook(bookr
, fi
-> GetStream()))
430 if (fi
!= NULL
) delete fi
;
431 fi
= fsys
.OpenFile(m_TempPath
+ wxFileNameFromPath(bookfile
.GetLocation()) + wxT(".cached"));
432 if (m_TempPath
== wxEmptyString
|| fi
== NULL
||
433 fi
-> GetModificationTime() < bookfile
.GetModificationTime() ||
434 !LoadCachedBook(bookr
, fi
-> GetStream()))
436 LoadMSProject(bookr
, fsys
, indexfile
, contfile
);
437 if (m_TempPath
!= wxEmptyString
)
439 wxFileOutputStream
*outs
= new wxFileOutputStream(m_TempPath
+
440 wxFileNameFromPath(bookfile
.GetLocation()) + wxT(".cached"));
441 SaveCachedBook(bookr
, outs
);
447 if (fi
!= NULL
) delete fi
;
449 // Now store the contents range
450 bookr
->SetContentsRange(cont_start
, m_ContentsCnt
);
452 // Convert encoding, if neccessary:
453 if (encoding
!= wxFONTENCODING_SYSTEM
)
455 wxFontEncodingArray a
= wxEncodingConverter::GetPlatformEquivalents(encoding
);
456 if (a
.GetCount() != 0 && a
[0] != encoding
)
459 wxEncodingConverter conv
;
460 conv
.Init(encoding
, a
[0]);
462 for (i
= IndexOld
; i
< m_IndexCnt
; i
++)
463 conv
.Convert(m_Index
[i
].m_Name
);
464 for (i
= ContentsOld
; i
< m_ContentsCnt
; i
++)
465 conv
.Convert(m_Contents
[i
].m_Name
);
469 m_BookRecords
.Add(bookr
);
471 qsort(m_Index
, m_IndexCnt
, sizeof(wxHtmlContentsItem
), IndexCompareFunc
);
477 bool wxHtmlHelpData::AddBook(const wxString
& book
)
479 if (book
.Right(4).Lower() == wxT(".zip") ||
480 book
.Right(4).Lower() == wxT(".htb") /*html book*/)
487 s
= fsys
.FindFirst(book
+ wxT("#zip:") + wxT("*.hhp"), wxFILE
);
490 if (AddBook(s
)) rt
= TRUE
;
506 char *buff
, *lineptr
;
509 wxString title
= _("noname"),
511 start
= wxEmptyString
,
512 contents
= wxEmptyString
,
513 index
= wxEmptyString
,
514 charset
= wxEmptyString
;
516 if (wxIsAbsolutePath(book
)) bookFull
= book
;
517 else bookFull
= wxGetCwd() + "/" + book
;
519 fi
= fsys
.OpenFile(bookFull
);
520 if (fi
== NULL
) return FALSE
;
521 fsys
.ChangePathTo(bookFull
);
522 s
= fi
-> GetStream();
524 buff
= new char[sz
+ 1];
530 lineptr
= ReadLine(lineptr
, linebuf
);
532 if (strstr(linebuf
, "Title=") == linebuf
)
533 title
= linebuf
+ strlen("Title=");
534 if (strstr(linebuf
, "Default topic=") == linebuf
)
535 start
= linebuf
+ strlen("Default topic=");
536 if (strstr(linebuf
, "Index file=") == linebuf
)
537 index
= linebuf
+ strlen("Index file=");
538 if (strstr(linebuf
, "Contents file=") == linebuf
)
539 contents
= linebuf
+ strlen("Contents file=");
540 if (strstr(linebuf
, "Charset=") == linebuf
)
541 charset
= linebuf
+ strlen("Charset=");
542 } while (lineptr
!= NULL
);
546 if (charset
== wxEmptyString
) enc
= wxFONTENCODING_SYSTEM
;
547 else enc
= wxTheFontMapper
-> CharsetToEncoding(charset
);
548 bool rtval
= AddBookParam(*fi
, enc
,
549 title
, contents
, index
, start
, fsys
.GetPath());
555 wxString
wxHtmlHelpData::FindPageByName(const wxString
& x
)
561 wxString
url(wxEmptyString
);
563 /* 1. try to open given file: */
565 cnt
= m_BookRecords
.GetCount();
566 for (i
= 0; i
< cnt
; i
++) {
567 f
= fsys
.OpenFile(m_BookRecords
[i
].GetBasePath() + x
);
569 url
= m_BookRecords
[i
].GetBasePath() + x
;
576 /* 2. try to find a book: */
578 for (i
= 0; i
< cnt
; i
++) {
579 if (m_BookRecords
[i
].GetTitle() == x
) {
580 url
= m_BookRecords
[i
].GetBasePath() + m_BookRecords
[i
].GetStart();
585 /* 3. try to find in contents: */
588 for (i
= 0; i
< cnt
; i
++) {
589 if (wxStrcmp(m_Contents
[i
].m_Name
, x
) == 0) {
590 url
= m_Contents
[i
].m_Book
-> GetBasePath() + m_Contents
[i
].m_Page
;
596 /* 4. try to find in index: */
599 for (i
= 0; i
< cnt
; i
++) {
600 if (wxStrcmp(m_Index
[i
].m_Name
, x
) == 0) {
601 url
= m_Index
[i
].m_Book
-> GetBasePath() + m_Index
[i
].m_Page
;
609 wxString
wxHtmlHelpData::FindPageById(int id
)
612 wxString
url(wxEmptyString
);
614 for (i
= 0; i
< m_ContentsCnt
; i
++) {
615 if (m_Contents
[i
].m_ID
== id
) {
616 url
= m_Contents
[i
].m_Book
-> GetBasePath() + m_Contents
[i
].m_Page
;
624 //----------------------------------------------------------------------------------
625 // wxHtmlSearchStatus functions
626 //----------------------------------------------------------------------------------
628 wxHtmlSearchStatus::wxHtmlSearchStatus(wxHtmlHelpData
* data
, const wxString
& keyword
,
629 bool case_sensitive
, bool whole_words_only
,
630 const wxString
& book
)
634 wxHtmlBookRecord
* bookr
= NULL
;
635 if (book
!= wxEmptyString
) {
636 // we have to search in a specific book. Find it first
637 int i
, cnt
= data
->m_BookRecords
.GetCount();
638 for (i
= 0; i
< cnt
; i
++)
639 if (data
->m_BookRecords
[i
].GetTitle() == book
) {
640 bookr
= &(data
->m_BookRecords
[i
]);
641 m_CurIndex
= bookr
->GetContentsStart();
642 m_MaxIndex
= bookr
->GetContentsEnd();
645 // check; we won't crash if the book doesn't exist, but it's Bad Anyway.
649 // no book specified; search all books
651 m_MaxIndex
= m_Data
->m_ContentsCnt
;
653 m_Engine
.LookFor(keyword
, case_sensitive
, whole_words_only
);
654 m_Active
= (m_CurIndex
< m_MaxIndex
);
658 bool wxHtmlSearchStatus::Search()
661 int i
= m_CurIndex
; // shortcut
666 // sanity check. Illegal use, but we'll try to prevent a crash anyway
671 m_Name
= wxEmptyString
;
672 m_ContentsItem
= NULL
;
673 thepage
= m_Data
->m_Contents
[i
].m_Page
;
675 m_Active
= (++m_CurIndex
< m_MaxIndex
);
676 // check if it is same page with different anchor:
677 if (m_LastPage
!= NULL
)
680 for (p1
= thepage
, p2
= m_LastPage
;
681 *p1
!= 0 && *p1
!= _T('#') && *p1
== *p2
; p1
++, p2
++) {}
683 m_LastPage
= thepage
;
685 if (*p1
== 0 || *p1
== _T('#'))
688 else m_LastPage
= thepage
;
691 file
= fsys
.OpenFile(m_Data
->m_Contents
[i
].m_Book
-> GetBasePath() + thepage
);
694 if (m_Engine
.Scan(file
-> GetStream())) {
695 m_Name
= m_Data
->m_Contents
[i
].m_Name
;
696 m_ContentsItem
= m_Data
->m_Contents
+ i
;
711 //--------------------------------------------------------------------------------
713 //--------------------------------------------------------------------------------
715 void wxSearchEngine::LookFor(const wxString
& keyword
, bool case_sensitive
, bool whole_words_only
)
717 m_CaseSensitive
= case_sensitive
;
718 m_WholeWords
= whole_words_only
;
719 if (m_Keyword
) delete[] m_Keyword
;
720 m_Keyword
= new wxChar
[keyword
.Length() + 1];
721 wxStrcpy(m_Keyword
, keyword
.c_str());
723 if (!m_CaseSensitive
)
724 for (int i
= wxStrlen(m_Keyword
) - 1; i
>= 0; i
--)
725 if ((m_Keyword
[i
] >= wxT('A')) && (m_Keyword
[i
] <= wxT('Z')))
726 m_Keyword
[i
] += wxT('a') - wxT('A');
731 #define WHITESPACE(c) (c == ' ' || c == '\n' || c == '\r' || c == '\t')
733 bool wxSearchEngine::Scan(wxInputStream
*stream
)
735 wxASSERT_MSG(m_Keyword
!= NULL
, wxT("wxSearchEngine::LookFor must be called before scanning!"));
738 int lng
= stream
->GetSize();
739 int wrd
= wxStrlen(m_Keyword
);
741 char *buf
= new char[lng
+ 1];
742 stream
-> Read(buf
, lng
);
745 if (!m_CaseSensitive
)
746 for (i
= 0; i
< lng
; i
++)
747 if ((buf
[i
] >= 'A') && (buf
[i
] <= 'Z')) buf
[i
] += 'a' - 'A';
751 for (i
= 0; i
< lng
- wrd
; i
++) {
752 if (WHITESPACE(buf
[i
])) continue;
754 while ((j
< wrd
) && (buf
[i
+ j
] == m_Keyword
[j
])) j
++;
755 if (j
== wrd
&& WHITESPACE(buf
[i
+ j
])) {found
= TRUE
; break; }
761 for (i
= 0; i
< lng
- wrd
; i
++) {
763 while ((j
< wrd
) && (buf
[i
+ j
] == m_Keyword
[j
])) j
++;
764 if (j
== wrd
) {found
= TRUE
; break; }