]>
git.saurik.com Git - wxWidgets.git/blob - src/html/helpdata.cpp
b3c25e134dcfe59acaa89b72d089522b8a879fe8
   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 
   9 // Copyright:   (c) Harm van der Heijden and Vaclav Slavik 
  10 // Licence:     wxWindows licence 
  11 ///////////////////////////////////////////////////////////////////////////// 
  14 #pragma implementation "helpdata.h" 
  17 // For compilers that support precompilation, includes "wx.h". 
  18 #include "wx/wxprec.h" 
  32 #include "wx/html/helpdata.h" 
  33 #include "wx/tokenzr.h" 
  34 #include "wx/wfstream.h" 
  35 #include "wx/busyinfo.h" 
  36 #include "wx/html/htmlparser.h" 
  37 #include "wx/html/htmldefs.h" 
  39 #include "wx/arrimpl.cpp" 
  40 WX_DEFINE_OBJARRAY(wxHtmlBookRecArray
) 
  42 //----------------------------------------------------------------------------- 
  43 // static helper functions 
  44 //----------------------------------------------------------------------------- 
  46 // Reads one line, stores it into buf and returns pointer to new line or NULL. 
  47 static char* ReadLine(char *line
, char *buf
) 
  49     char *writeptr 
= buf
, *readptr 
= line
; 
  51     while (*readptr 
!= 0 && *readptr 
!= '\r' && *readptr 
!= '\n') *(writeptr
++) = *(readptr
++); 
  53     while (*readptr 
== '\r' || *readptr 
== '\n') readptr
++; 
  54     if (*readptr 
== 0) return NULL
; 
  59 static wxString 
SafeFileName(const wxString
& s
) 
  62     res
.Replace(":", "_", TRUE
); 
  63     res
.Replace(" ", "_", TRUE
); 
  64     res
.Replace("/", "_", TRUE
); 
  65     res
.Replace("\\", "_", TRUE
); 
  66     res
.Replace("#", "_", TRUE
); 
  67     res
.Replace(".", "_", TRUE
); 
  72 static int IndexCompareFunc(const void *a
, const void *b
) 
  74     return strcmp(((wxHtmlContentsItem
*)a
) -> m_Name
, ((wxHtmlContentsItem
*)b
) -> m_Name
); 
  78 //----------------------------------------------------------------------------- 
  80 //----------------------------------------------------------------------------- 
  82 class HP_Parser 
: public wxHtmlParser
 
  85         void AddText(const char* text
) {} 
  86         wxObject
* GetProduct() {return NULL
;} 
  90 //----------------------------------------------------------------------------- 
  92 //----------------------------------------------------------------------------- 
  94 class HP_TagHandler 
: public wxHtmlTagHandler
 
  97         wxString m_Name
, m_Page
; 
 101         wxHtmlContentsItem 
*m_Items
; 
 103         wxHtmlBookRecord 
*m_Book
; 
 106         HP_TagHandler(wxHtmlBookRecord 
*b
) : wxHtmlTagHandler() {m_Book 
= b
; m_Items 
= NULL
; m_ItemsCnt 
= 0; m_Name 
= m_Page 
= wxEmptyString
; m_Level 
= 0;} 
 107         wxString 
GetSupportedTags() {return "UL,OBJECT,PARAM";} 
 108         bool HandleTag(const wxHtmlTag
& tag
); 
 109         void WriteOut(wxHtmlContentsItem
*& array
, int& size
); 
 110         void ReadIn(wxHtmlContentsItem
* array
, int size
); 
 114 bool HP_TagHandler::HandleTag(const wxHtmlTag
& tag
) 
 116     if (tag
.GetName() == "UL") { 
 123     else if (tag
.GetName() == "OBJECT") { 
 124         m_Name 
= m_Page 
= wxEmptyString
; 
 126         if (m_Page 
!= wxEmptyString
) { 
 127             if (m_ItemsCnt 
% HTML_REALLOC_STEP 
== 0) 
 128                 m_Items 
= (wxHtmlContentsItem
*) realloc(m_Items
, (m_ItemsCnt 
+ HTML_REALLOC_STEP
) * sizeof(wxHtmlContentsItem
)); 
 129             m_Items
[m_ItemsCnt
].m_Level 
= m_Level
; 
 130             m_Items
[m_ItemsCnt
].m_ID 
= m_ID
; 
 131             m_Items
[m_ItemsCnt
].m_Page 
= new char[m_Page
.Length() + 1]; 
 132             strcpy(m_Items
[m_ItemsCnt
].m_Page
, m_Page
.c_str()); 
 133             m_Items
[m_ItemsCnt
].m_Name 
= new char [m_Name
.Length() + 1]; 
 134             strcpy(m_Items
[m_ItemsCnt
].m_Name
, m_Name
.c_str()); 
 135             m_Items
[m_ItemsCnt
].m_Book 
= m_Book
; 
 142         if (m_Name 
== wxEmptyString 
&& tag
.GetParam("NAME") == "Name") m_Name 
= tag
.GetParam("VALUE"); 
 143         if (tag
.GetParam("NAME") == "Local") m_Page 
= tag
.GetParam("VALUE"); 
 144         if (tag
.GetParam("NAME") == "ID") tag
.ScanParam("VALUE", "%i", &m_ID
); 
 151 void HP_TagHandler::WriteOut(wxHtmlContentsItem
*& array
, int& size
) 
 159 void HP_TagHandler::ReadIn(wxHtmlContentsItem
* array
, int size
) 
 165 //----------------------------------------------------------------------------- 
 167 //----------------------------------------------------------------------------- 
 169 IMPLEMENT_DYNAMIC_CLASS(wxHtmlHelpData
, wxObject
) 
 171 wxHtmlHelpData::wxHtmlHelpData() 
 173     m_TempPath 
= wxEmptyString
; 
 181 wxHtmlHelpData::~wxHtmlHelpData() 
 185     m_BookRecords
.Empty(); 
 187         for (i 
= 0; i 
< m_ContentsCnt
; i
++) { 
 188             delete[] m_Contents
[i
].m_Page
; 
 189             delete[] m_Contents
[i
].m_Name
; 
 194         for (i 
= 0; i 
< m_IndexCnt
; i
++) { 
 195             delete[] m_Index
[i
].m_Page
; 
 196             delete[] m_Index
[i
].m_Name
; 
 202 bool wxHtmlHelpData::LoadMSProject(wxHtmlBookRecord 
*book
, wxFileSystem
& fsys
, const wxString
& indexfile
, const wxString
& contentsfile
) 
 210     HP_TagHandler 
*handler 
= new HP_TagHandler(book
); 
 211     parser
.AddTagHandler(handler
); 
 213     f 
= ( contentsfile
.IsEmpty() ? NULL 
: fsys
.OpenFile(contentsfile
) ); 
 215         sz 
= f 
-> GetStream() -> GetSize(); 
 216         buf 
= new char[sz
+1]; 
 218         f 
-> GetStream() -> Read(buf
, sz
); 
 220         handler 
-> ReadIn(m_Contents
, m_ContentsCnt
); 
 222         handler 
-> WriteOut(m_Contents
, m_ContentsCnt
); 
 226     f 
= ( indexfile
.IsEmpty() ? NULL 
: fsys
.OpenFile(indexfile
) ); 
 228         sz 
= f 
-> GetStream() -> GetSize(); 
 229         buf 
= new  char[sz
+1]; 
 231         f 
-> GetStream() -> Read(buf
, sz
); 
 233         handler 
-> ReadIn(m_Index
, m_IndexCnt
); 
 235         handler 
-> WriteOut(m_Index
, m_IndexCnt
); 
 242 bool wxHtmlHelpData::LoadCachedBook(wxHtmlBookRecord 
*book
, wxInputStream 
*f
) 
 247     /* load contents : */ 
 249     f 
-> Read(&x
, sizeof(x
)); 
 252     m_Contents 
= (wxHtmlContentsItem
*) realloc(m_Contents
, (m_ContentsCnt 
/ HTML_REALLOC_STEP 
+ 1) * HTML_REALLOC_STEP 
* sizeof(wxHtmlContentsItem
)); 
 253     for (i 
= st
; i 
< m_ContentsCnt
; i
++) { 
 254         f 
-> Read(&x
, sizeof(x
)); 
 255         m_Contents
[i
].m_Level 
= x
; 
 256         f 
-> Read(&x
, sizeof(x
)); 
 257         m_Contents
[i
].m_ID 
= x
; 
 258         f 
-> Read(&x
, sizeof(x
)); 
 259         m_Contents
[i
].m_Name 
= new char[x
]; 
 260         f 
-> Read(m_Contents
[i
].m_Name
, x
); 
 261         f 
-> Read(&x
, sizeof(x
)); 
 262         m_Contents
[i
].m_Page 
= new char[x
]; 
 263         f 
-> Read(m_Contents
[i
].m_Page
, x
); 
 264         m_Contents
[i
].m_Book 
= book
; 
 269     f 
-> Read(&x
, sizeof(x
)); 
 272     m_Index 
= (wxHtmlContentsItem
*) realloc(m_Index
, (m_IndexCnt 
/ HTML_REALLOC_STEP 
+ 1) * HTML_REALLOC_STEP 
* sizeof(wxHtmlContentsItem
)); 
 273     for (i 
= st
; i 
< m_IndexCnt
; i
++) { 
 274         f 
-> Read(&x
, sizeof(x
)); 
 275         m_Index
[i
].m_Name 
= new char[x
]; 
 276         f 
-> Read(m_Index
[i
].m_Name
, x
); 
 277         f 
-> Read(&x
, sizeof(x
)); 
 278         m_Index
[i
].m_Page 
= new char[x
]; 
 279         f 
-> Read(m_Index
[i
].m_Page
, x
); 
 280         m_Index
[i
].m_Book 
= book
; 
 286 bool wxHtmlHelpData::SaveCachedBook(wxHtmlBookRecord 
*book
, wxOutputStream 
*f
) 
 291     /* save contents : */ 
 294     for (i 
= 0; i 
< m_ContentsCnt
; i
++) if (m_Contents
[i
].m_Book 
== book 
&& m_Contents
[i
].m_Level 
> 0) x
++; 
 295     f 
-> Write(&x
, sizeof(x
)); 
 296     for (i 
= 0; i 
< m_ContentsCnt
; i
++) { 
 297         if (m_Contents
[i
].m_Book 
!= book 
|| m_Contents
[i
].m_Level 
== 0) continue; 
 298         x 
= m_Contents
[i
].m_Level
; 
 299         f 
-> Write(&x
, sizeof(x
)); 
 300         x 
= m_Contents
[i
].m_ID
; 
 301         f 
-> Write(&x
, sizeof(x
)); 
 302         x 
= strlen(m_Contents
[i
].m_Name
) + 1; 
 303         f 
-> Write(&x
, sizeof(x
)); 
 304         f 
-> Write(m_Contents
[i
].m_Name
, x
); 
 305         x 
= strlen(m_Contents
[i
].m_Page
) + 1; 
 306         f 
-> Write(&x
, sizeof(x
)); 
 307         f 
-> Write(m_Contents
[i
].m_Page
, x
); 
 313     for (i 
= 0; i 
< m_IndexCnt
; i
++) if (m_Index
[i
].m_Book 
== book 
&& m_Index
[i
].m_Level 
> 0) x
++; 
 314     f 
-> Write(&x
, sizeof(x
)); 
 315     for (i 
= 0; i 
< m_IndexCnt
; i
++) { 
 316         if (m_Index
[i
].m_Book 
!= book 
|| m_Index
[i
].m_Level 
== 0) continue; 
 317         x 
= strlen(m_Index
[i
].m_Name
) + 1; 
 318         f 
-> Write(&x
, sizeof(x
)); 
 319         f 
-> Write(m_Index
[i
].m_Name
, x
); 
 320         x 
= strlen(m_Index
[i
].m_Page
) + 1; 
 321         f 
-> Write(&x
, sizeof(x
)); 
 322         f 
-> Write(m_Index
[i
].m_Page
, x
); 
 328 void wxHtmlHelpData::SetTempDir(const wxString
& path
) 
 330     if (path 
== wxEmptyString
) m_TempPath 
= path
; 
 332         if (wxIsAbsolutePath(path
)) m_TempPath 
= path
; 
 333         else m_TempPath 
= wxGetCwd() + "/" + path
; 
 335         if (m_TempPath
[m_TempPath
.Length() - 1] != '/') 
 341 bool wxHtmlHelpData::AddBookParam(const wxString
& title
, const wxString
& contfile
, 
 342                                   const wxString
& indexfile
, const wxString
& deftopic
, 
 343                                   const wxString
& path
) 
 347     wxHtmlBookRecord 
*bookr
; 
 350     if (! path
.IsEmpty()) 
 351             // workaround for bug in ChangePathTo(name, TRUE) 
 352             fsys
.ChangePathTo(path
+"/gaga"); 
 354     bookr 
= new wxHtmlBookRecord(path
+'/', title
, deftopic
); 
 356     if (m_ContentsCnt 
% HTML_REALLOC_STEP 
== 0) 
 357         m_Contents 
= (wxHtmlContentsItem
*) realloc(m_Contents
, (m_ContentsCnt 
+ HTML_REALLOC_STEP
) * sizeof(wxHtmlContentsItem
)); 
 358     m_Contents
[m_ContentsCnt
].m_Level 
= 0; 
 359     m_Contents
[m_ContentsCnt
].m_ID 
= 0; 
 360     m_Contents
[m_ContentsCnt
].m_Page 
= new char[deftopic
.Length() + 1]; 
 361     strcpy(m_Contents
[m_ContentsCnt
].m_Page
, deftopic
.c_str()); 
 362     m_Contents
[m_ContentsCnt
].m_Name 
= new char [title
.Length() + 1]; 
 363     strcpy(m_Contents
[m_ContentsCnt
].m_Name
, title
.c_str()); 
 364     m_Contents
[m_ContentsCnt
].m_Book 
= bookr
; 
 366     // store the contents index for later 
 367     int cont_start 
= m_ContentsCnt
++; 
 369     // Try to find cached binary versions: 
 370     safetitle 
= SafeFileName(title
); 
 371     fi 
= fsys
.OpenFile(safetitle 
+ ".cached"); 
 372     if (fi 
== NULL
) fi 
= fsys
.OpenFile(m_TempPath 
+ safetitle 
+ ".cached"); 
 373     if ((fi 
== NULL
) || (m_TempPath 
== wxEmptyString
)) { 
 374         LoadMSProject(bookr
, fsys
, indexfile
, contfile
); 
 375         if (m_TempPath 
!= wxEmptyString
) { 
 376                 wxFileOutputStream 
*outs 
= new wxFileOutputStream(m_TempPath 
+ safetitle 
+ ".cached"); 
 377             SaveCachedBook(bookr
, outs
); 
 382         LoadCachedBook(bookr
, fi 
-> GetStream()); 
 386     // Now store the contents range 
 387     bookr
->SetContentsRange(cont_start
, m_ContentsCnt
); 
 389     m_BookRecords
.Add(bookr
); 
 391         qsort(m_Index
, m_IndexCnt
, sizeof(wxHtmlContentsItem
), IndexCompareFunc
); 
 397 bool wxHtmlHelpData::AddBook(const wxString
& book
) 
 405     char *buff
, *lineptr
; 
 408     wxString title 
= _("noname"), 
 410              start 
= wxEmptyString
, 
 411              contents 
= wxEmptyString
, index 
= wxEmptyString
; 
 413     if (wxIsAbsolutePath(book
)) bookFull 
= book
; 
 414     else bookFull 
= wxGetCwd() + "/" + book
; 
 416     fi 
= fsys
.OpenFile(bookFull
); 
 417     if (fi 
== NULL
) return FALSE
; 
 418     fsys
.ChangePathTo(bookFull
); 
 419     s 
= fi 
-> GetStream(); 
 421     buff 
= new char[sz
+1]; 
 427     while ((lineptr 
= ReadLine(lineptr
, linebuf
)) != NULL
) { 
 428         if (strstr(linebuf
, "Title=") == linebuf
) 
 429             title 
= linebuf 
+ strlen("Title="); 
 430         if (strstr(linebuf
, "Default topic=") == linebuf
) 
 431             start 
= linebuf 
+ strlen("Default topic="); 
 432         if (strstr(linebuf
, "Index file=") == linebuf
) 
 433             index 
= linebuf 
+ strlen("Index file="); 
 434         if (strstr(linebuf
, "Contents file=") == linebuf
) 
 435             contents 
= linebuf 
+ strlen("Contents file="); 
 439     return AddBookParam(title
, contents
, index
, start
, fsys
.GetPath()); 
 442 wxString 
wxHtmlHelpData::FindPageByName(const wxString
& x
) 
 448     wxString 
url(wxEmptyString
); 
 450     /* 1. try to open given file: */ 
 452     cnt 
= m_BookRecords
.GetCount(); 
 453     for (i 
= 0; i 
< cnt
; i
++) { 
 454         f 
= fsys
.OpenFile(m_BookRecords
[i
].GetBasePath() + x
); 
 456             url 
= m_BookRecords
[i
].GetBasePath() + x
; 
 463     /* 2. try to find a book: */ 
 465     for (i 
= 0; i 
< cnt
; i
++) { 
 466         if (m_BookRecords
[i
].GetTitle() == x
) { 
 467             url 
= m_BookRecords
[i
].GetBasePath() + m_BookRecords
[i
].GetStart(); 
 472     /* 3. try to find in contents: */ 
 475     for (i 
= 0; i 
< cnt
; i
++) { 
 476         if (strcmp(m_Contents
[i
].m_Name
, x
) == 0) { 
 477             url 
= m_Contents
[i
].m_Book 
-> GetBasePath() + m_Contents
[i
].m_Page
; 
 483     /* 4. try to find in index: */ 
 486     for (i 
= 0; i 
< cnt
; i
++) { 
 487         if (strcmp(m_Index
[i
].m_Name
, x
) == 0) { 
 488             url 
= m_Index
[i
].m_Book 
-> GetBasePath() + m_Index
[i
].m_Page
; 
 496 wxString 
wxHtmlHelpData::FindPageById(int id
) 
 499     wxString 
url(wxEmptyString
); 
 501     for (i 
= 0; i 
< m_ContentsCnt
; i
++) { 
 502         if (m_Contents
[i
].m_ID 
== id
) { 
 503             url 
= m_Contents
[i
].m_Book 
-> GetBasePath() + m_Contents
[i
].m_Page
; 
 511 //---------------------------------------------------------------------------------- 
 512 // wxHtmlSearchStatus functions 
 513 //---------------------------------------------------------------------------------- 
 515 wxHtmlSearchStatus::wxHtmlSearchStatus(wxHtmlHelpData
* data
, const wxString
& keyword
, 
 516                                        const wxString
& book
) 
 520     wxHtmlBookRecord
* bookr 
= NULL
; 
 521     if (book 
!= wxEmptyString
) { 
 522         // we have to search in a specific book. Find it first 
 523         int i
,cnt 
= data
->m_BookRecords
.GetCount(); 
 524         for (i
=0; i
<cnt
; i
++) 
 525             if (data
->m_BookRecords
[i
].GetTitle() == book
) { 
 526                 bookr 
= &(data
->m_BookRecords
[i
]); 
 527                 m_CurIndex 
= bookr
->GetContentsStart(); 
 528                 m_MaxIndex 
= bookr
->GetContentsEnd(); 
 531         // check; we won't crash if the book doesn't exist, but it's Bad Anyway. 
 535         // no book specified; search all books 
 537         m_MaxIndex 
= m_Data
->m_ContentsCnt
; 
 539     m_Engine
.LookFor(keyword
); 
 540     m_Active 
= (m_CurIndex 
< m_MaxIndex
); 
 541     m_LastPage 
= wxEmptyString
; 
 544 bool wxHtmlSearchStatus::Search() 
 548     int i 
= m_CurIndex
; // shortcut 
 552         // sanity check. Illegal use, but we'll try to prevent a crash anyway 
 557     m_ContentsItem 
= NULL
; 
 558     m_Name 
= wxEmptyString
; 
 560     file 
= fsys
.OpenFile(m_Data
->m_Contents
[i
].m_Book 
-> GetBasePath() + 
 561                          m_Data
->m_Contents
[i
].m_Page
); 
 563         if (m_LastPage 
!= file
->GetLocation()) { 
 564             m_LastPage 
= file
->GetLocation(); 
 565             if (m_Engine
.Scan(file 
-> GetStream())) { 
 566                 m_Name 
= m_Data
->m_Contents
[i
].m_Name
; 
 567                 m_ContentsItem 
= m_Data
->m_Contents 
+ i
; 
 573     m_Active 
= (++m_CurIndex 
< m_MaxIndex
);