home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / src / html / helpdata.cpp < prev    next >
C/C++ Source or Header  |  2002-08-08  |  25KB  |  865 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        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
  7. // RCS-ID:      $Id: helpdata.cpp,v 1.59 2002/08/05 18:04:07 RR Exp $
  8. // Copyright:   (c) Harm van der Heijden and Vaclav Slavik
  9. // Licence:     wxWindows licence
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. #ifdef __GNUG__
  13. #pragma implementation "helpdata.h"
  14. #endif
  15.  
  16. // For compilers that support precompilation, includes "wx.h".
  17. #include "wx/wxprec.h"
  18.  
  19. #ifdef __BORLANDC__
  20. #pragma hdrstop
  21. #endif
  22.  
  23. #include "wx/defs.h"
  24.  
  25. #if wxUSE_HTML && wxUSE_STREAMS
  26.  
  27. #ifndef WXPRECOMP
  28.     #include "wx/intl.h"
  29.     #include "wx/log.h"
  30. #endif
  31.  
  32. #include <ctype.h>
  33.  
  34. #include "wx/html/helpdata.h"
  35. #include "wx/tokenzr.h"
  36. #include "wx/wfstream.h"
  37. #include "wx/busyinfo.h"
  38. #include "wx/encconv.h"
  39. #include "wx/fontmap.h"
  40. #include "wx/log.h"
  41. #include "wx/html/htmlpars.h"
  42. #include "wx/html/htmldefs.h"
  43. #include "wx/filename.h"
  44.  
  45. #include "wx/arrimpl.cpp"
  46. WX_DEFINE_OBJARRAY(wxHtmlBookRecArray)
  47.  
  48. //-----------------------------------------------------------------------------
  49. // static helper functions
  50. //-----------------------------------------------------------------------------
  51.  
  52. // Reads one line, stores it into buf and returns pointer to new line or NULL.
  53. static const wxChar* ReadLine(const wxChar *line, wxChar *buf, size_t bufsize)
  54. {
  55.     wxChar *writeptr = buf;
  56.     wxChar *endptr = buf + bufsize - 1;
  57.     const wxChar *readptr = line;
  58.  
  59.     while (*readptr != 0 && *readptr != _T('\r') && *readptr != _T('\n') &&
  60.            writeptr != endptr) 
  61.         *(writeptr++) = *(readptr++);
  62.     *writeptr = 0;
  63.     while (*readptr == _T('\r') || *readptr == _T('\n'))
  64.         readptr++;
  65.     if (*readptr == 0)
  66.         return NULL;
  67.     else 
  68.         return readptr;
  69. }
  70.  
  71.  
  72.  
  73. extern "C" int LINKAGEMODE
  74. wxHtmlHelpIndexCompareFunc(const void *a, const void *b)
  75. {
  76.     return wxStricmp(((wxHtmlContentsItem*)a)->m_Name, ((wxHtmlContentsItem*)b)->m_Name);
  77. }
  78.  
  79.  
  80. //-----------------------------------------------------------------------------
  81. // HP_Parser
  82. //-----------------------------------------------------------------------------
  83.  
  84. class HP_Parser : public wxHtmlParser
  85. {
  86. public:
  87.     wxObject* GetProduct() { return NULL; }
  88. protected:
  89.     virtual void AddText(const wxChar* WXUNUSED(txt)) {}
  90. };
  91.  
  92.  
  93. //-----------------------------------------------------------------------------
  94. // HP_TagHandler
  95. //-----------------------------------------------------------------------------
  96.  
  97. class HP_TagHandler : public wxHtmlTagHandler
  98. {
  99.     private:
  100.         wxString m_Name, m_Page;
  101.         int m_Level;
  102.         int m_ID;
  103.         int m_Index;
  104.         wxHtmlContentsItem *m_Items;
  105.         int m_ItemsCnt;
  106.         wxHtmlBookRecord *m_Book;
  107.  
  108.     public:
  109.         HP_TagHandler(wxHtmlBookRecord *b) : wxHtmlTagHandler()
  110.             { m_Book = b; m_Items = NULL; m_ItemsCnt = 0; m_Name = m_Page = wxEmptyString;
  111.               m_Level = 0; m_ID = -1; }
  112.         wxString GetSupportedTags() { return wxT("UL,OBJECT,PARAM"); }
  113.         bool HandleTag(const wxHtmlTag& tag);
  114.         void WriteOut(wxHtmlContentsItem*& array, int& size);
  115.         void ReadIn(wxHtmlContentsItem* array, int size);
  116. };
  117.  
  118.  
  119. bool HP_TagHandler::HandleTag(const wxHtmlTag& tag)
  120. {
  121.     if (tag.GetName() == wxT("UL"))
  122.     {
  123.         m_Level++;
  124.         ParseInner(tag);
  125.         m_Level--;
  126.         return TRUE;
  127.     }
  128.     else if (tag.GetName() == wxT("OBJECT"))
  129.     {
  130.         m_Name = m_Page = wxEmptyString;
  131.         ParseInner(tag);
  132.  
  133. #if 0
  134.          if (!m_Page.IsEmpty())
  135.         /* Valid HHW's file may contain only two object tags:
  136.  
  137.            <OBJECT type="text/site properties">
  138.                <param name="ImageType" value="Folder">
  139.            </OBJECT>
  140.  
  141.            or
  142.  
  143.            <OBJECT type="text/sitemap">
  144.                <param name="Name" value="main page">
  145.                <param name="Local" value="another.htm">
  146.            </OBJECT>
  147.  
  148.            We're interested in the latter. !m_Page.IsEmpty() is valid
  149.            condition because text/site properties does not contain Local param
  150.         */
  151. #endif
  152.         if (tag.GetParam(wxT("TYPE")) == wxT("text/sitemap"))
  153.         {
  154.             if (m_ItemsCnt % wxHTML_REALLOC_STEP == 0)
  155.                 m_Items = (wxHtmlContentsItem*) realloc(m_Items,
  156.                                        (m_ItemsCnt + wxHTML_REALLOC_STEP) *
  157.                                        sizeof(wxHtmlContentsItem));
  158.  
  159.             m_Items[m_ItemsCnt].m_Level = m_Level;
  160.             m_Items[m_ItemsCnt].m_ID = m_ID;
  161.             m_Items[m_ItemsCnt].m_Page = new wxChar[m_Page.Length() + 1];
  162.             wxStrcpy(m_Items[m_ItemsCnt].m_Page, m_Page.c_str());
  163.             m_Items[m_ItemsCnt].m_Name = new wxChar [m_Name.Length() + 1];
  164.             wxStrcpy(m_Items[m_ItemsCnt].m_Name, m_Name.c_str());
  165.             m_Items[m_ItemsCnt].m_Book = m_Book;
  166.             m_ItemsCnt++;
  167.         }
  168.  
  169.         return TRUE;
  170.     }
  171.     else
  172.     { // "PARAM"
  173.         if (m_Name == wxEmptyString && tag.GetParam(wxT("NAME")) == wxT("Name"))
  174.             m_Name = tag.GetParam(wxT("VALUE"));
  175.         if (tag.GetParam(wxT("NAME")) == wxT("Local"))
  176.             m_Page = tag.GetParam(wxT("VALUE"));
  177.         if (tag.GetParam(wxT("NAME")) == wxT("ID"))
  178.             tag.GetParamAsInt(wxT("VALUE"), &m_ID);
  179.         return FALSE;
  180.     }
  181. }
  182.  
  183.  
  184.  
  185. void HP_TagHandler::WriteOut(wxHtmlContentsItem*& array, int& size)
  186. {
  187.     array = m_Items;
  188.     size = m_ItemsCnt;
  189.     m_Items = NULL;
  190.     m_ItemsCnt = 0;
  191. }
  192.  
  193. void HP_TagHandler::ReadIn(wxHtmlContentsItem* array, int size)
  194. {
  195.     m_Items = array;
  196.     m_ItemsCnt = size;
  197. }
  198.  
  199.  
  200.  
  201.  
  202. //-----------------------------------------------------------------------------
  203. // wxHtmlHelpData
  204. //-----------------------------------------------------------------------------
  205.  
  206. wxString wxHtmlBookRecord::GetFullPath(const wxString &page) const
  207. {
  208.     if (wxIsAbsolutePath(page))
  209.         return page;
  210.     else
  211.         return m_BasePath + page;
  212. }
  213.  
  214.  
  215.  
  216. IMPLEMENT_DYNAMIC_CLASS(wxHtmlHelpData, wxObject)
  217.  
  218. wxHtmlHelpData::wxHtmlHelpData()
  219. {
  220.     m_TempPath = wxEmptyString;
  221.  
  222.     m_Contents = NULL;
  223.     m_ContentsCnt = 0;
  224.     m_Index = NULL;
  225.     m_IndexCnt = 0;
  226. }
  227.  
  228. wxHtmlHelpData::~wxHtmlHelpData()
  229. {
  230.     int i;
  231.  
  232.     m_BookRecords.Empty();
  233.     if (m_Contents)
  234.     {
  235.         for (i = 0; i < m_ContentsCnt; i++)
  236.         {
  237.             delete[] m_Contents[i].m_Page;
  238.             delete[] m_Contents[i].m_Name;
  239.         }
  240.         free(m_Contents);
  241.     }
  242.     if (m_Index)
  243.     {
  244.         for (i = 0; i < m_IndexCnt; i++)
  245.         {
  246.             delete[] m_Index[i].m_Page;
  247.             delete[] m_Index[i].m_Name;
  248.         }
  249.         free(m_Index);
  250.     }
  251. }
  252.  
  253. // defined in htmlfilt.cpp
  254. void wxPrivate_ReadString(wxString& str, wxInputStream* s);
  255.  
  256. bool wxHtmlHelpData::LoadMSProject(wxHtmlBookRecord *book, wxFileSystem& fsys, const wxString& indexfile, const wxString& contentsfile)
  257. {
  258.     wxFSFile *f;
  259.     wxString buf;
  260.     wxString string;
  261.  
  262.     HP_Parser parser;
  263.     HP_TagHandler *handler = new HP_TagHandler(book);
  264.     parser.AddTagHandler(handler);
  265.  
  266.     f = ( contentsfile.IsEmpty() ? (wxFSFile*) NULL : fsys.OpenFile(contentsfile) );
  267.     if (f)
  268.     {
  269.         buf.clear();
  270.         wxPrivate_ReadString(buf, f->GetStream());
  271.         delete f;
  272.         handler->ReadIn(m_Contents, m_ContentsCnt);
  273.         parser.Parse(buf);
  274.         handler->WriteOut(m_Contents, m_ContentsCnt);
  275.     }
  276.     else
  277.         wxLogError(_("Cannot open contents file: %s"), contentsfile.c_str());
  278.  
  279.     f = ( indexfile.IsEmpty() ? (wxFSFile*) NULL : fsys.OpenFile(indexfile) );
  280.     if (f)
  281.     {
  282.         buf.clear();
  283.         wxPrivate_ReadString(buf, f->GetStream());
  284.         delete f;
  285.         handler->ReadIn(m_Index, m_IndexCnt);
  286.         parser.Parse(buf);
  287.         handler->WriteOut(m_Index, m_IndexCnt);
  288.     }
  289.     else if (!indexfile.IsEmpty())
  290.         wxLogError(_("Cannot open index file: %s"), indexfile.c_str());
  291.     return TRUE;
  292. }
  293.  
  294.  
  295.  
  296. inline static void CacheWriteInt32(wxOutputStream *f, wxInt32 value)
  297. {
  298.     wxInt32 x = wxINT32_SWAP_ON_BE(value);
  299.     f->Write(&x, sizeof(x));
  300. }
  301.  
  302. inline static wxInt32 CacheReadInt32(wxInputStream *f)
  303. {
  304.     wxInt32 x;
  305.     f->Read(&x, sizeof(x));
  306.     return wxINT32_SWAP_ON_BE(x);
  307. }
  308.  
  309. inline static void CacheWriteString(wxOutputStream *f, const wxChar *str)
  310. {
  311.     size_t len = wxStrlen(str)+1;
  312.     CacheWriteInt32(f, len);
  313.     f->Write(str, len * sizeof(wxChar));
  314. }
  315.  
  316. inline static wxChar *CacheReadString(wxInputStream *f)
  317. {
  318.     wxChar *str;
  319.     size_t len = (size_t)CacheReadInt32(f);
  320.     str = new wxChar[len];
  321.     f->Read(str, len * sizeof(wxChar));
  322.     return str;
  323. }
  324.  
  325. #define CURRENT_CACHED_BOOK_VERSION     2
  326.  
  327. bool wxHtmlHelpData::LoadCachedBook(wxHtmlBookRecord *book, wxInputStream *f)
  328. {
  329.     int i, st;
  330.     wxInt32 version;
  331.  
  332.     /* load header - version info : */
  333.     version = CacheReadInt32(f);
  334.  
  335.     if (version != CURRENT_CACHED_BOOK_VERSION)
  336.     {
  337.         // NB: We can just silently return FALSE here and don't worry about
  338.         //     it anymore, because AddBookParam will load the MS project in
  339.         //     absence of (properly versioned) .cached file and automatically 
  340.         //     create new .cached file immediately afterward.
  341.         return FALSE;
  342.     }
  343.  
  344.     /* load contents : */
  345.     st = m_ContentsCnt;
  346.     m_ContentsCnt += CacheReadInt32(f);
  347.     m_Contents = (wxHtmlContentsItem*) realloc(m_Contents,
  348.                                                (m_ContentsCnt / wxHTML_REALLOC_STEP + 1) *
  349.                                                wxHTML_REALLOC_STEP * sizeof(wxHtmlContentsItem));
  350.     for (i = st; i < m_ContentsCnt; i++)
  351.     {
  352.         m_Contents[i].m_Level = CacheReadInt32(f);
  353.         m_Contents[i].m_ID = CacheReadInt32(f);
  354.         m_Contents[i].m_Name = CacheReadString(f);
  355.         m_Contents[i].m_Page = CacheReadString(f);
  356.         m_Contents[i].m_Book = book;
  357.     }
  358.  
  359.     /* load index : */
  360.     st = m_IndexCnt;
  361.     m_IndexCnt += CacheReadInt32(f);
  362.     m_Index = (wxHtmlContentsItem*) realloc(m_Index, (m_IndexCnt / wxHTML_REALLOC_STEP + 1) *
  363.                                                      wxHTML_REALLOC_STEP * sizeof(wxHtmlContentsItem));
  364.     for (i = st; i < m_IndexCnt; i++)
  365.     {
  366.         m_Index[i].m_Name = CacheReadString(f);
  367.         m_Index[i].m_Page = CacheReadString(f);
  368.         m_Index[i].m_Book = book;
  369.     }
  370.     return TRUE;
  371. }
  372.  
  373.  
  374. bool wxHtmlHelpData::SaveCachedBook(wxHtmlBookRecord *book, wxOutputStream *f)
  375. {
  376.     int i;
  377.     wxInt32 cnt;
  378.  
  379.     /* save header - version info : */
  380.     CacheWriteInt32(f, CURRENT_CACHED_BOOK_VERSION);
  381.  
  382.     /* save contents : */
  383.     for (cnt = 0, i = 0; i < m_ContentsCnt; i++) 
  384.         if (m_Contents[i].m_Book == book && m_Contents[i].m_Level > 0)
  385.             cnt++;
  386.     CacheWriteInt32(f, cnt);
  387.  
  388.     for (i = 0; i < m_ContentsCnt; i++)
  389.     {
  390.         if (m_Contents[i].m_Book != book || m_Contents[i].m_Level == 0) 
  391.             continue;
  392.         CacheWriteInt32(f, m_Contents[i].m_Level);
  393.         CacheWriteInt32(f, m_Contents[i].m_ID);
  394.         CacheWriteString(f, m_Contents[i].m_Name);
  395.         CacheWriteString(f, m_Contents[i].m_Page);
  396.     }
  397.  
  398.     /* save index : */
  399.     for (cnt = 0, i = 0; i < m_IndexCnt; i++) 
  400.         if (m_Index[i].m_Book == book && m_Index[i].m_Level > 0) 
  401.             cnt++;
  402.     CacheWriteInt32(f, cnt);
  403.  
  404.     for (i = 0; i < m_IndexCnt; i++)
  405.     {
  406.         if (m_Index[i].m_Book != book || m_Index[i].m_Level == 0) 
  407.             continue;
  408.         CacheWriteString(f, m_Index[i].m_Name);
  409.         CacheWriteString(f, m_Index[i].m_Page);
  410.     }
  411.     return TRUE;
  412. }
  413.  
  414.  
  415. void wxHtmlHelpData::SetTempDir(const wxString& path)
  416. {
  417.     if (path == wxEmptyString) m_TempPath = path;
  418.     else
  419.     {
  420.         if (wxIsAbsolutePath(path)) m_TempPath = path;
  421.         else m_TempPath = wxGetCwd() + _T("/") + path;
  422.  
  423.         if (m_TempPath[m_TempPath.Length() - 1] != _T('/'))
  424.             m_TempPath << _T('/');
  425.     }
  426. }
  427.  
  428.  
  429.  
  430. static wxString SafeFileName(const wxString& s)
  431. {
  432.     wxString res(s);
  433.     res.Replace(wxT("#"), wxT("_"));
  434.     res.Replace(wxT(":"), wxT("_"));
  435.     res.Replace(wxT("\\"), wxT("_"));
  436.     res.Replace(wxT("/"), wxT("_"));
  437.     return res;
  438. }
  439.  
  440. bool wxHtmlHelpData::AddBookParam(const wxFSFile& bookfile,
  441.                                   wxFontEncoding encoding,
  442.                                   const wxString& title, const wxString& contfile,
  443.                                   const wxString& indexfile, const wxString& deftopic,
  444.                                   const wxString& path)
  445. {
  446.     wxFileSystem fsys;
  447.     wxFSFile *fi;
  448.     wxHtmlBookRecord *bookr;
  449.  
  450.     int IndexOld = m_IndexCnt,
  451.         ContentsOld = m_ContentsCnt;
  452.  
  453.     if (!path.IsEmpty())
  454.         fsys.ChangePathTo(path, TRUE);
  455.  
  456.     size_t booksCnt = m_BookRecords.GetCount();
  457.     for (size_t i = 0; i < booksCnt; i++)
  458.     {
  459.         if ( m_BookRecords[i].GetBookFile() == bookfile.GetLocation() )
  460.             return TRUE; // book is (was) loaded
  461.     }
  462.  
  463.     bookr = new wxHtmlBookRecord(bookfile.GetLocation(), fsys.GetPath(), title, deftopic);
  464.     
  465.     if (m_ContentsCnt % wxHTML_REALLOC_STEP == 0)
  466.         m_Contents = (wxHtmlContentsItem*) realloc(m_Contents, (m_ContentsCnt + wxHTML_REALLOC_STEP) * sizeof(wxHtmlContentsItem));
  467.     m_Contents[m_ContentsCnt].m_Level = 0;
  468.     m_Contents[m_ContentsCnt].m_ID = 0;
  469.     m_Contents[m_ContentsCnt].m_Page = new wxChar[deftopic.Length() + 1];
  470.     wxStrcpy(m_Contents[m_ContentsCnt].m_Page, deftopic.c_str());
  471.     m_Contents[m_ContentsCnt].m_Name = new wxChar [title.Length() + 1];
  472.     wxStrcpy(m_Contents[m_ContentsCnt].m_Name, title.c_str());
  473.     m_Contents[m_ContentsCnt].m_Book = bookr;
  474.  
  475.     // store the contents index for later
  476.     int cont_start = m_ContentsCnt++;
  477.  
  478.     // Try to find cached binary versions:
  479.     // 1. save file as book, but with .hhp.cached extension
  480.     // 2. same as 1. but in temp path
  481.     // 3. otherwise or if cache load failed, load it from MS.
  482.  
  483.     fi = fsys.OpenFile(bookfile.GetLocation() + wxT(".cached"));
  484.  
  485.     if (fi == NULL ||
  486.           fi->GetModificationTime() < bookfile.GetModificationTime() ||
  487.           !LoadCachedBook(bookr, fi->GetStream()))
  488.     {
  489.         if (fi != NULL) delete fi;
  490.         fi = fsys.OpenFile(m_TempPath + wxFileNameFromPath(bookfile.GetLocation()) + wxT(".cached"));
  491.         if (m_TempPath == wxEmptyString || fi == NULL ||
  492.             fi->GetModificationTime() < bookfile.GetModificationTime() ||
  493.             !LoadCachedBook(bookr, fi->GetStream()))
  494.         {
  495.             LoadMSProject(bookr, fsys, indexfile, contfile);
  496.             if (m_TempPath != wxEmptyString)
  497.             {
  498.                 wxFileOutputStream *outs = new wxFileOutputStream(m_TempPath +
  499.                                                   SafeFileName(wxFileNameFromPath(bookfile.GetLocation())) + wxT(".cached"));
  500.                 SaveCachedBook(bookr, outs);
  501.                 delete outs;
  502.             }
  503.         }
  504.     }
  505.  
  506.     if (fi != NULL) delete fi;
  507.  
  508.     // Now store the contents range
  509.     bookr->SetContentsRange(cont_start, m_ContentsCnt);
  510.  
  511.     // Convert encoding, if neccessary:
  512.     if (encoding != wxFONTENCODING_SYSTEM)
  513.     {
  514.         wxFontEncodingArray a = wxEncodingConverter::GetPlatformEquivalents(encoding);
  515.         if (a.GetCount() != 0 && a[0] != encoding)
  516.         {
  517.             int i;
  518.             wxEncodingConverter conv;
  519.             conv.Init(encoding, a[0]);
  520.  
  521.             for (i = IndexOld; i < m_IndexCnt; i++)
  522.                 conv.Convert(m_Index[i].m_Name);
  523.             for (i = ContentsOld; i < m_ContentsCnt; i++)
  524.                 conv.Convert(m_Contents[i].m_Name);
  525.         }
  526.     }
  527.  
  528.     m_BookRecords.Add(bookr);
  529.     if (m_IndexCnt > 0)
  530.         qsort(m_Index, m_IndexCnt, sizeof(wxHtmlContentsItem), wxHtmlHelpIndexCompareFunc);
  531.  
  532.     return TRUE;
  533. }
  534.  
  535.  
  536. bool wxHtmlHelpData::AddBook(const wxString& book)
  537. {
  538.     if (book.Right(4).Lower() == wxT(".zip") ||
  539.         book.Right(4).Lower() == wxT(".htb") /*html book*/)
  540.     {
  541.         wxFileSystem fsys;
  542.         wxString s;
  543.         bool rt = FALSE;
  544.  
  545.         s = fsys.FindFirst(book + wxT("#zip:") + wxT("*.hhp"), wxFILE);
  546.         while (!s.IsEmpty())
  547.         {
  548.             if (AddBook(s)) rt = TRUE;
  549.             s = fsys.FindNext();
  550.         }
  551.  
  552.         return rt;
  553.     }
  554.     else
  555.     {
  556.         wxFSFile *fi;
  557.         wxFileSystem fsys;
  558.         wxInputStream *s;
  559.         wxString bookFull;
  560.  
  561.         wxString title = _("noname"),
  562.                  safetitle,
  563.                  start = wxEmptyString,
  564.                  contents = wxEmptyString,
  565.                  index = wxEmptyString,
  566.                  charset = wxEmptyString;
  567.  
  568. #if defined(__WXMAC__) && !defined(__DARWIN__)
  569.         if (wxIsAbsolutePath(book)) bookFull = book;
  570.         else bookFull = wxGetCwd() + book; // no slash or dot
  571.         wxFileName fn( bookFull );
  572.         bookFull = fn.GetFullPath( wxPATH_UNIX );
  573. #else
  574.         if (wxIsAbsolutePath(book)) bookFull = book;
  575.         else bookFull = wxGetCwd() + "/" + book;
  576. #endif
  577.  
  578.         fi = fsys.OpenFile(bookFull);
  579.         if (fi == NULL)
  580.         {
  581.             wxLogError(_("Cannot open HTML help book: %s"), bookFull.c_str());
  582.             return FALSE;
  583.         }
  584.         fsys.ChangePathTo(bookFull);
  585.         s = fi->GetStream();
  586.  
  587.         const wxChar *lineptr;
  588.         wxChar linebuf[300];
  589.         wxString tmp;
  590.  
  591.         wxPrivate_ReadString(tmp, s);
  592.         lineptr = tmp.c_str();
  593.  
  594.         do 
  595.         {
  596.             lineptr = ReadLine(lineptr, linebuf, 300);
  597.             
  598.             for (wxChar *ch = linebuf; *ch != '\0' && *ch != '='; ch++)
  599.                *ch = tolower(*ch);
  600.  
  601.             if (wxStrstr(linebuf, _T("title=")) == linebuf)
  602.                 title = linebuf + wxStrlen(_T("title="));
  603.             if (wxStrstr(linebuf, _T("default topic=")) == linebuf)
  604.                 start = linebuf + wxStrlen(_T("default topic="));
  605.             if (wxStrstr(linebuf, _T("index file=")) == linebuf)
  606.                 index = linebuf + wxStrlen(_T("index file="));
  607.             if (wxStrstr(linebuf, _T("contents file=")) == linebuf)
  608.                 contents = linebuf + wxStrlen(_T("contents file="));
  609.             if (wxStrstr(linebuf, _T("charset=")) == linebuf)
  610.                 charset = linebuf + wxStrlen(_T("charset="));
  611.         } while (lineptr != NULL);
  612.  
  613.         wxFontEncoding enc;
  614.         if (charset == wxEmptyString) enc = wxFONTENCODING_SYSTEM;
  615.         else enc = wxFontMapper::Get()->CharsetToEncoding(charset);
  616.         bool rtval = AddBookParam(*fi, enc,
  617.                                   title, contents, index, start, fsys.GetPath());
  618.         delete fi;
  619.         return rtval;
  620.     }
  621. }
  622.  
  623. wxString wxHtmlHelpData::FindPageByName(const wxString& x)
  624. {
  625.     int cnt;
  626.     int i;
  627.     wxFileSystem fsys;
  628.     wxFSFile *f;
  629.     wxString url(wxEmptyString);
  630.  
  631.     /* 1. try to open given file: */
  632.  
  633.     cnt = m_BookRecords.GetCount();
  634.     for (i = 0; i < cnt; i++)
  635.     {
  636.         f = fsys.OpenFile(m_BookRecords[i].GetFullPath(x));
  637.         if (f)
  638.         {
  639.             url = m_BookRecords[i].GetFullPath(x);
  640.             delete f;
  641.             return url;
  642.         }
  643.     }
  644.  
  645.  
  646.     /* 2. try to find a book: */
  647.  
  648.     for (i = 0; i < cnt; i++)
  649.     {
  650.         if (m_BookRecords[i].GetTitle() == x)
  651.         {
  652.             url = m_BookRecords[i].GetFullPath(m_BookRecords[i].GetStart());
  653.             return url;
  654.         }
  655.     }
  656.  
  657.     /* 3. try to find in contents: */
  658.  
  659.     cnt = m_ContentsCnt;
  660.     for (i = 0; i < cnt; i++)
  661.     {
  662.         if (wxStrcmp(m_Contents[i].m_Name, x) == 0)
  663.         {
  664.             url = m_Contents[i].GetFullPath();
  665.             return url;
  666.         }
  667.     }
  668.  
  669.  
  670.     /* 4. try to find in index: */
  671.  
  672.     cnt = m_IndexCnt;
  673.     for (i = 0; i < cnt; i++)
  674.     {
  675.         if (wxStrcmp(m_Index[i].m_Name, x) == 0)
  676.         {
  677.             url = m_Index[i].GetFullPath();
  678.             return url;
  679.         }
  680.     }
  681.  
  682.     return url;
  683. }
  684.  
  685. wxString wxHtmlHelpData::FindPageById(int id)
  686. {
  687.     int i;
  688.     wxString url(wxEmptyString);
  689.  
  690.     for (i = 0; i < m_ContentsCnt; i++)
  691.     {
  692.         if (m_Contents[i].m_ID == id)
  693.         {
  694.             url = m_Contents[i].GetFullPath();
  695.             return url;
  696.         }
  697.     }
  698.  
  699.     return url;
  700. }
  701.  
  702. //----------------------------------------------------------------------------------
  703. // wxHtmlSearchStatus functions
  704. //----------------------------------------------------------------------------------
  705.  
  706. wxHtmlSearchStatus::wxHtmlSearchStatus(wxHtmlHelpData* data, const wxString& keyword,
  707.                                        bool case_sensitive, bool whole_words_only,
  708.                                        const wxString& book)
  709. {
  710.     m_Data = data;
  711.     m_Keyword = keyword;
  712.     wxHtmlBookRecord* bookr = NULL;
  713.     if (book != wxEmptyString)
  714.     {
  715.         // we have to search in a specific book. Find it first
  716.         int i, cnt = data->m_BookRecords.GetCount();
  717.         for (i = 0; i < cnt; i++)
  718.             if (data->m_BookRecords[i].GetTitle() == book)
  719.             {
  720.                 bookr = &(data->m_BookRecords[i]);
  721.                 m_CurIndex = bookr->GetContentsStart();
  722.                 m_MaxIndex = bookr->GetContentsEnd();
  723.                 break;
  724.             }
  725.         // check; we won't crash if the book doesn't exist, but it's Bad Anyway.
  726.         wxASSERT(bookr);
  727.     }
  728.     if (! bookr)
  729.     {
  730.         // no book specified; search all books
  731.         m_CurIndex = 0;
  732.         m_MaxIndex = m_Data->m_ContentsCnt;
  733.     }
  734.     m_Engine.LookFor(keyword, case_sensitive, whole_words_only);
  735.     m_Active = (m_CurIndex < m_MaxIndex);
  736.     m_LastPage = NULL;
  737. }
  738.  
  739. bool wxHtmlSearchStatus::Search()
  740. {
  741.     wxFSFile *file;
  742.     int i = m_CurIndex;  // shortcut
  743.     bool found = FALSE;
  744.     wxChar *thepage;
  745.  
  746.     if (!m_Active)
  747.     {
  748.         // sanity check. Illegal use, but we'll try to prevent a crash anyway
  749.         wxASSERT(m_Active);
  750.         return FALSE;
  751.     }
  752.  
  753.     m_Name = wxEmptyString;
  754.     m_ContentsItem = NULL;
  755.     thepage = m_Data->m_Contents[i].m_Page;
  756.  
  757.     m_Active = (++m_CurIndex < m_MaxIndex);
  758.     // check if it is same page with different anchor:
  759.     if (m_LastPage != NULL)
  760.     {
  761.         wxChar *p1, *p2;
  762.         for (p1 = thepage, p2 = m_LastPage;
  763.              *p1 != 0 && *p1 != _T('#') && *p1 == *p2; p1++, p2++) {}
  764.  
  765.         m_LastPage = thepage;
  766.  
  767.         if (*p1 == 0 || *p1 == _T('#'))
  768.             return FALSE;
  769.     }
  770.     else m_LastPage = thepage;
  771.  
  772.     wxFileSystem fsys;
  773.     file = fsys.OpenFile(m_Data->m_Contents[i].m_Book->GetFullPath(thepage));
  774.     if (file)
  775.     {
  776.         if (m_Engine.Scan(file->GetStream()))
  777.         {
  778.             m_Name = m_Data->m_Contents[i].m_Name;
  779.             m_ContentsItem = m_Data->m_Contents + i;
  780.             found = TRUE;
  781.         }
  782.         delete file;
  783.     }
  784.     return found;
  785. }
  786.  
  787.  
  788.  
  789.  
  790.  
  791.  
  792.  
  793.  
  794. //--------------------------------------------------------------------------------
  795. // wxSearchEngine
  796. //--------------------------------------------------------------------------------
  797.  
  798. void wxSearchEngine::LookFor(const wxString& keyword, bool case_sensitive, bool whole_words_only)
  799. {
  800.     m_CaseSensitive = case_sensitive;
  801.     m_WholeWords = whole_words_only;
  802.     if (m_Keyword) delete[] m_Keyword;
  803.     m_Keyword = new wxChar[keyword.Length() + 1];
  804.     wxStrcpy(m_Keyword, keyword.c_str());
  805.  
  806.     if (!m_CaseSensitive)
  807.     {
  808.         for (int i = wxStrlen(m_Keyword) - 1; i >= 0; i--)
  809.         {
  810.             if ((m_Keyword[i] >= wxT('A')) && (m_Keyword[i] <= wxT('Z')))
  811.                 m_Keyword[i] += wxT('a') - wxT('A');
  812.         }
  813.     }
  814. }
  815.  
  816.  
  817. static inline bool WHITESPACE(wxChar c)
  818. {
  819.     return c == _T(' ') || c == _T('\n') || c == _T('\r') || c == _T('\t');
  820. }
  821.  
  822. bool wxSearchEngine::Scan(wxInputStream *stream)
  823. {
  824.     wxASSERT_MSG(m_Keyword != NULL, wxT("wxSearchEngine::LookFor must be called before scanning!"));
  825.  
  826.     int i, j;
  827.     int wrd = wxStrlen(m_Keyword);
  828.     bool found = FALSE;
  829.     wxString tmp;
  830.     wxPrivate_ReadString(tmp, stream);
  831.     int lng = tmp.length();
  832.     const wxChar *buf = tmp.c_str();
  833.  
  834.     if (!m_CaseSensitive)
  835.         for (i = 0; i < lng; i++)
  836.             tmp[(size_t)i] = (wxChar)wxTolower(tmp[(size_t)i]);
  837.  
  838.     if (m_WholeWords)
  839.     {
  840.         for (i = 0; i < lng - wrd; i++)
  841.         {
  842.             if (WHITESPACE(buf[i])) continue;
  843.             j = 0;
  844.             while ((j < wrd) && (buf[i + j] == m_Keyword[j])) j++;
  845.             if (j == wrd && WHITESPACE(buf[i + j])) { found = TRUE; break; }
  846.         }
  847.     }
  848.  
  849.     else
  850.     {
  851.         for (i = 0; i < lng - wrd; i++)
  852.         {
  853.             j = 0;
  854.             while ((j < wrd) && (buf[i + j] == m_Keyword[j])) j++;
  855.             if (j == wrd) { found = TRUE; break; }
  856.         }
  857.     }
  858.  
  859.     return found;
  860. }
  861.  
  862.  
  863.  
  864. #endif
  865.