]>
git.saurik.com Git - wxWidgets.git/blob - src/html/helpdata.cpp
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/html/htmlpars.h"
36 #include "wx/html/htmldefs.h"
38 #include "wx/arrimpl.cpp"
39 WX_DEFINE_OBJARRAY(wxHtmlBookRecArray
)
41 //-----------------------------------------------------------------------------
42 // static helper functions
43 //-----------------------------------------------------------------------------
45 // Reads one line, stores it into buf and returns pointer to new line or NULL.
46 static char* ReadLine(char *line
, char *buf
)
48 char *writeptr
= buf
, *readptr
= line
;
50 while (*readptr
!= 0 && *readptr
!= '\r' && *readptr
!= '\n') *(writeptr
++) = *(readptr
++);
52 while (*readptr
== '\r' || *readptr
== '\n') readptr
++;
53 if (*readptr
== 0) return NULL
;
58 static wxString
SafeFileName(const wxString
& s
)
61 res
.Replace(":", "_", TRUE
);
62 res
.Replace(" ", "_", TRUE
);
63 res
.Replace("/", "_", TRUE
);
64 res
.Replace("\\", "_", TRUE
);
65 res
.Replace("#", "_", TRUE
);
66 res
.Replace(".", "_", TRUE
);
71 static int IndexCompareFunc(const void *a
, const void *b
)
73 return strcmp(((wxHtmlContentsItem
*)a
) -> m_Name
, ((wxHtmlContentsItem
*)b
) -> m_Name
);
77 //-----------------------------------------------------------------------------
79 //-----------------------------------------------------------------------------
81 class HP_Parser
: public wxHtmlParser
84 void AddText(const char* WXUNUSED(text
)) { }
85 wxObject
* GetProduct() { return NULL
; }
89 //-----------------------------------------------------------------------------
91 //-----------------------------------------------------------------------------
93 class HP_TagHandler
: public wxHtmlTagHandler
96 wxString m_Name
, m_Page
;
100 wxHtmlContentsItem
*m_Items
;
102 wxHtmlBookRecord
*m_Book
;
105 HP_TagHandler(wxHtmlBookRecord
*b
) : wxHtmlTagHandler() {m_Book
= b
; m_Items
= NULL
; m_ItemsCnt
= 0; m_Name
= m_Page
= wxEmptyString
; m_Level
= 0;}
106 wxString
GetSupportedTags() {return "UL,OBJECT,PARAM";}
107 bool HandleTag(const wxHtmlTag
& tag
);
108 void WriteOut(wxHtmlContentsItem
*& array
, int& size
);
109 void ReadIn(wxHtmlContentsItem
* array
, int size
);
113 bool HP_TagHandler::HandleTag(const wxHtmlTag
& tag
)
115 if (tag
.GetName() == "UL") {
122 else if (tag
.GetName() == "OBJECT") {
123 m_Name
= m_Page
= wxEmptyString
;
125 if (m_Page
!= wxEmptyString
) {
126 if (m_ItemsCnt
% wxHTML_REALLOC_STEP
== 0)
127 m_Items
= (wxHtmlContentsItem
*) realloc(m_Items
, (m_ItemsCnt
+ wxHTML_REALLOC_STEP
) * sizeof(wxHtmlContentsItem
));
128 m_Items
[m_ItemsCnt
].m_Level
= m_Level
;
129 m_Items
[m_ItemsCnt
].m_ID
= m_ID
;
130 m_Items
[m_ItemsCnt
].m_Page
= new char[m_Page
.Length() + 1];
131 strcpy(m_Items
[m_ItemsCnt
].m_Page
, m_Page
.c_str());
132 m_Items
[m_ItemsCnt
].m_Name
= new char [m_Name
.Length() + 1];
133 strcpy(m_Items
[m_ItemsCnt
].m_Name
, m_Name
.c_str());
134 m_Items
[m_ItemsCnt
].m_Book
= m_Book
;
141 if (m_Name
== wxEmptyString
&& tag
.GetParam("NAME") == "Name") m_Name
= tag
.GetParam("VALUE");
142 if (tag
.GetParam("NAME") == "Local") m_Page
= tag
.GetParam("VALUE");
143 if (tag
.GetParam("NAME") == "ID") tag
.ScanParam("VALUE", "%i", &m_ID
);
150 void HP_TagHandler::WriteOut(wxHtmlContentsItem
*& array
, int& size
)
158 void HP_TagHandler::ReadIn(wxHtmlContentsItem
* array
, int size
)
164 //-----------------------------------------------------------------------------
166 //-----------------------------------------------------------------------------
168 IMPLEMENT_DYNAMIC_CLASS(wxHtmlHelpData
, wxObject
)
170 wxHtmlHelpData::wxHtmlHelpData()
172 m_TempPath
= wxEmptyString
;
180 wxHtmlHelpData::~wxHtmlHelpData()
184 m_BookRecords
.Empty();
186 for (i
= 0; i
< m_ContentsCnt
; i
++) {
187 delete[] m_Contents
[i
].m_Page
;
188 delete[] m_Contents
[i
].m_Name
;
193 for (i
= 0; i
< m_IndexCnt
; i
++) {
194 delete[] m_Index
[i
].m_Page
;
195 delete[] m_Index
[i
].m_Name
;
201 bool wxHtmlHelpData::LoadMSProject(wxHtmlBookRecord
*book
, wxFileSystem
& fsys
, const wxString
& indexfile
, const wxString
& contentsfile
)
209 HP_TagHandler
*handler
= new HP_TagHandler(book
);
210 parser
.AddTagHandler(handler
);
212 f
= ( contentsfile
.IsEmpty() ? NULL
: fsys
.OpenFile(contentsfile
) );
214 sz
= f
-> GetStream() -> GetSize();
215 buf
= new char[sz
+1];
217 f
-> GetStream() -> Read(buf
, sz
);
219 handler
-> ReadIn(m_Contents
, m_ContentsCnt
);
221 handler
-> WriteOut(m_Contents
, m_ContentsCnt
);
225 f
= ( indexfile
.IsEmpty() ? NULL
: fsys
.OpenFile(indexfile
) );
227 sz
= f
-> GetStream() -> GetSize();
228 buf
= new char[sz
+1];
230 f
-> GetStream() -> Read(buf
, sz
);
232 handler
-> ReadIn(m_Index
, m_IndexCnt
);
234 handler
-> WriteOut(m_Index
, m_IndexCnt
);
241 bool wxHtmlHelpData::LoadCachedBook(wxHtmlBookRecord
*book
, wxInputStream
*f
)
246 /* load contents : */
248 f
-> Read(&x
, sizeof(x
));
251 m_Contents
= (wxHtmlContentsItem
*) realloc(m_Contents
, (m_ContentsCnt
/ wxHTML_REALLOC_STEP
+ 1) * wxHTML_REALLOC_STEP
* sizeof(wxHtmlContentsItem
));
252 for (i
= st
; i
< m_ContentsCnt
; i
++) {
253 f
-> Read(&x
, sizeof(x
));
254 m_Contents
[i
].m_Level
= x
;
255 f
-> Read(&x
, sizeof(x
));
256 m_Contents
[i
].m_ID
= x
;
257 f
-> Read(&x
, sizeof(x
));
258 m_Contents
[i
].m_Name
= new char[x
];
259 f
-> Read(m_Contents
[i
].m_Name
, x
);
260 f
-> Read(&x
, sizeof(x
));
261 m_Contents
[i
].m_Page
= new char[x
];
262 f
-> Read(m_Contents
[i
].m_Page
, x
);
263 m_Contents
[i
].m_Book
= book
;
268 f
-> Read(&x
, sizeof(x
));
271 m_Index
= (wxHtmlContentsItem
*) realloc(m_Index
, (m_IndexCnt
/ wxHTML_REALLOC_STEP
+ 1) * wxHTML_REALLOC_STEP
* sizeof(wxHtmlContentsItem
));
272 for (i
= st
; i
< m_IndexCnt
; i
++) {
273 f
-> Read(&x
, sizeof(x
));
274 m_Index
[i
].m_Name
= new char[x
];
275 f
-> Read(m_Index
[i
].m_Name
, x
);
276 f
-> Read(&x
, sizeof(x
));
277 m_Index
[i
].m_Page
= new char[x
];
278 f
-> Read(m_Index
[i
].m_Page
, x
);
279 m_Index
[i
].m_Book
= book
;
285 bool wxHtmlHelpData::SaveCachedBook(wxHtmlBookRecord
*book
, wxOutputStream
*f
)
290 /* save contents : */
293 for (i
= 0; i
< m_ContentsCnt
; i
++) if (m_Contents
[i
].m_Book
== book
&& m_Contents
[i
].m_Level
> 0) x
++;
294 f
-> Write(&x
, sizeof(x
));
295 for (i
= 0; i
< m_ContentsCnt
; i
++) {
296 if (m_Contents
[i
].m_Book
!= book
|| m_Contents
[i
].m_Level
== 0) continue;
297 x
= m_Contents
[i
].m_Level
;
298 f
-> Write(&x
, sizeof(x
));
299 x
= m_Contents
[i
].m_ID
;
300 f
-> Write(&x
, sizeof(x
));
301 x
= strlen(m_Contents
[i
].m_Name
) + 1;
302 f
-> Write(&x
, sizeof(x
));
303 f
-> Write(m_Contents
[i
].m_Name
, x
);
304 x
= strlen(m_Contents
[i
].m_Page
) + 1;
305 f
-> Write(&x
, sizeof(x
));
306 f
-> Write(m_Contents
[i
].m_Page
, x
);
312 for (i
= 0; i
< m_IndexCnt
; i
++) if (m_Index
[i
].m_Book
== book
&& m_Index
[i
].m_Level
> 0) x
++;
313 f
-> Write(&x
, sizeof(x
));
314 for (i
= 0; i
< m_IndexCnt
; i
++) {
315 if (m_Index
[i
].m_Book
!= book
|| m_Index
[i
].m_Level
== 0) continue;
316 x
= strlen(m_Index
[i
].m_Name
) + 1;
317 f
-> Write(&x
, sizeof(x
));
318 f
-> Write(m_Index
[i
].m_Name
, x
);
319 x
= strlen(m_Index
[i
].m_Page
) + 1;
320 f
-> Write(&x
, sizeof(x
));
321 f
-> Write(m_Index
[i
].m_Page
, x
);
327 void wxHtmlHelpData::SetTempDir(const wxString
& path
)
329 if (path
== wxEmptyString
) m_TempPath
= path
;
331 if (wxIsAbsolutePath(path
)) m_TempPath
= path
;
332 else m_TempPath
= wxGetCwd() + "/" + path
;
334 if (m_TempPath
[m_TempPath
.Length() - 1] != '/')
340 bool wxHtmlHelpData::AddBookParam(const wxString
& title
, const wxString
& contfile
,
341 const wxString
& indexfile
, const wxString
& deftopic
,
342 const wxString
& path
)
346 wxHtmlBookRecord
*bookr
;
349 if (! path
.IsEmpty())
350 // workaround for bug in ChangePathTo(name, TRUE)
351 fsys
.ChangePathTo(path
+"/gaga");
353 bookr
= new wxHtmlBookRecord(path
+'/', title
, deftopic
);
355 if (m_ContentsCnt
% wxHTML_REALLOC_STEP
== 0)
356 m_Contents
= (wxHtmlContentsItem
*) realloc(m_Contents
, (m_ContentsCnt
+ wxHTML_REALLOC_STEP
) * sizeof(wxHtmlContentsItem
));
357 m_Contents
[m_ContentsCnt
].m_Level
= 0;
358 m_Contents
[m_ContentsCnt
].m_ID
= 0;
359 m_Contents
[m_ContentsCnt
].m_Page
= new char[deftopic
.Length() + 1];
360 strcpy(m_Contents
[m_ContentsCnt
].m_Page
, deftopic
.c_str());
361 m_Contents
[m_ContentsCnt
].m_Name
= new char [title
.Length() + 1];
362 strcpy(m_Contents
[m_ContentsCnt
].m_Name
, title
.c_str());
363 m_Contents
[m_ContentsCnt
].m_Book
= bookr
;
365 // store the contents index for later
366 int cont_start
= m_ContentsCnt
++;
368 // Try to find cached binary versions:
369 safetitle
= SafeFileName(title
);
370 fi
= fsys
.OpenFile(safetitle
+ ".cached");
371 if (fi
== NULL
) fi
= fsys
.OpenFile(m_TempPath
+ safetitle
+ ".cached");
372 if ((fi
== NULL
) || (m_TempPath
== wxEmptyString
)) {
373 LoadMSProject(bookr
, fsys
, indexfile
, contfile
);
374 if (m_TempPath
!= wxEmptyString
) {
375 wxFileOutputStream
*outs
= new wxFileOutputStream(m_TempPath
+ safetitle
+ ".cached");
376 SaveCachedBook(bookr
, outs
);
381 LoadCachedBook(bookr
, fi
-> GetStream());
385 // Now store the contents range
386 bookr
->SetContentsRange(cont_start
, m_ContentsCnt
);
388 m_BookRecords
.Add(bookr
);
390 qsort(m_Index
, m_IndexCnt
, sizeof(wxHtmlContentsItem
), IndexCompareFunc
);
396 bool wxHtmlHelpData::AddBook(const wxString
& book
)
404 char *buff
, *lineptr
;
407 wxString title
= _("noname"),
409 start
= wxEmptyString
,
410 contents
= wxEmptyString
, index
= wxEmptyString
;
412 if (wxIsAbsolutePath(book
)) bookFull
= book
;
413 else bookFull
= wxGetCwd() + "/" + book
;
415 fi
= fsys
.OpenFile(bookFull
);
416 if (fi
== NULL
) return FALSE
;
417 fsys
.ChangePathTo(bookFull
);
418 s
= fi
-> GetStream();
420 buff
= new char[sz
+1];
426 while ((lineptr
= ReadLine(lineptr
, linebuf
)) != NULL
) {
427 if (strstr(linebuf
, "Title=") == linebuf
)
428 title
= linebuf
+ strlen("Title=");
429 if (strstr(linebuf
, "Default topic=") == linebuf
)
430 start
= linebuf
+ strlen("Default topic=");
431 if (strstr(linebuf
, "Index file=") == linebuf
)
432 index
= linebuf
+ strlen("Index file=");
433 if (strstr(linebuf
, "Contents file=") == linebuf
)
434 contents
= linebuf
+ strlen("Contents file=");
438 return AddBookParam(title
, contents
, index
, start
, fsys
.GetPath());
441 wxString
wxHtmlHelpData::FindPageByName(const wxString
& x
)
447 wxString
url(wxEmptyString
);
449 /* 1. try to open given file: */
451 cnt
= m_BookRecords
.GetCount();
452 for (i
= 0; i
< cnt
; i
++) {
453 f
= fsys
.OpenFile(m_BookRecords
[i
].GetBasePath() + x
);
455 url
= m_BookRecords
[i
].GetBasePath() + x
;
462 /* 2. try to find a book: */
464 for (i
= 0; i
< cnt
; i
++) {
465 if (m_BookRecords
[i
].GetTitle() == x
) {
466 url
= m_BookRecords
[i
].GetBasePath() + m_BookRecords
[i
].GetStart();
471 /* 3. try to find in contents: */
474 for (i
= 0; i
< cnt
; i
++) {
475 if (strcmp(m_Contents
[i
].m_Name
, x
) == 0) {
476 url
= m_Contents
[i
].m_Book
-> GetBasePath() + m_Contents
[i
].m_Page
;
482 /* 4. try to find in index: */
485 for (i
= 0; i
< cnt
; i
++) {
486 if (strcmp(m_Index
[i
].m_Name
, x
) == 0) {
487 url
= m_Index
[i
].m_Book
-> GetBasePath() + m_Index
[i
].m_Page
;
495 wxString
wxHtmlHelpData::FindPageById(int id
)
498 wxString
url(wxEmptyString
);
500 for (i
= 0; i
< m_ContentsCnt
; i
++) {
501 if (m_Contents
[i
].m_ID
== id
) {
502 url
= m_Contents
[i
].m_Book
-> GetBasePath() + m_Contents
[i
].m_Page
;
510 //----------------------------------------------------------------------------------
511 // wxHtmlSearchStatus functions
512 //----------------------------------------------------------------------------------
514 wxHtmlSearchStatus::wxHtmlSearchStatus(wxHtmlHelpData
* data
, const wxString
& keyword
,
515 const wxString
& book
)
519 wxHtmlBookRecord
* bookr
= NULL
;
520 if (book
!= wxEmptyString
) {
521 // we have to search in a specific book. Find it first
522 int i
,cnt
= data
->m_BookRecords
.GetCount();
523 for (i
=0; i
<cnt
; i
++)
524 if (data
->m_BookRecords
[i
].GetTitle() == book
) {
525 bookr
= &(data
->m_BookRecords
[i
]);
526 m_CurIndex
= bookr
->GetContentsStart();
527 m_MaxIndex
= bookr
->GetContentsEnd();
530 // check; we won't crash if the book doesn't exist, but it's Bad Anyway.
534 // no book specified; search all books
536 m_MaxIndex
= m_Data
->m_ContentsCnt
;
538 m_Engine
.LookFor(keyword
);
539 m_Active
= (m_CurIndex
< m_MaxIndex
);
540 m_LastPage
= wxEmptyString
;
543 bool wxHtmlSearchStatus::Search()
547 int i
= m_CurIndex
; // shortcut
551 // sanity check. Illegal use, but we'll try to prevent a crash anyway
556 m_ContentsItem
= NULL
;
557 m_Name
= wxEmptyString
;
559 file
= fsys
.OpenFile(m_Data
->m_Contents
[i
].m_Book
-> GetBasePath() +
560 m_Data
->m_Contents
[i
].m_Page
);
562 if (m_LastPage
!= file
->GetLocation()) {
563 m_LastPage
= file
->GetLocation();
564 if (m_Engine
.Scan(file
-> GetStream())) {
565 m_Name
= m_Data
->m_Contents
[i
].m_Name
;
566 m_ContentsItem
= m_Data
->m_Contents
+ i
;
572 m_Active
= (++m_CurIndex
< m_MaxIndex
);