Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1119 lines
38 KiB

  1. // This module is for reading binary files out of a compiled HTML file
  2. #include "header.h"
  3. #include "system.h"
  4. #include "htmlhelp.h"
  5. #include "strtable.h"
  6. #include "fts.h"
  7. #include "TCHAR.h"
  8. #include "parserhh.h"
  9. #include "collect.h"
  10. #include "hhtypes.h"
  11. #include "toc.h"
  12. #include "secwin.h" // Only included for SetWinType....
  13. enum {
  14. TYPE_STRINGS,
  15. TYPE_URLS,
  16. };
  17. #include "sysnames.h"
  18. CHmData** g_phmData;
  19. BOOL AddTitleToGlobalList(PCSTR pszITSSFile);
  20. /////////////////////////////////////////////////////////////////////////////////////////////
  21. // Darwin Stuff
  22. //
  23. // REVIEW: These must be tied to the calling process. If we ever support
  24. // multiple processes in a single OCX, this will break big time.
  25. PSTR g_pszDarwinGuid;
  26. PSTR g_pszDarwinBackupGuid;
  27. /////////////////////////////////////////////////////////////////////////////////////////////
  28. // CTitleInformation - read in the title informaton file (#SYSTEM) settings for each title
  29. //
  30. #ifndef SEEK_SET
  31. #define SEEK_CUR 1
  32. #define SEEK_END 2
  33. #define SEEK_SET 0
  34. #endif
  35. unsigned short CharsetFromLangID(unsigned short uLangID)
  36. {
  37. unsigned short uCharset;
  38. switch (uLangID)
  39. {
  40. case LANG_RUSSIAN: uCharset = RUSSIAN_CHARSET; break;
  41. case LANG_ENGLISH: uCharset = ANSI_CHARSET; break;
  42. case LANG_JAPANESE: uCharset = SHIFTJIS_CHARSET; break;
  43. case LANG_KOREAN: uCharset = HANGEUL_CHARSET; break;
  44. case LANG_ARABIC: uCharset = ARABIC_CHARSET; break;
  45. case LANG_GREEK: uCharset = GREEK_CHARSET; break;
  46. case LANG_THAI: uCharset = THAI_CHARSET; break;
  47. case LANG_HEBREW: uCharset = HEBREW_CHARSET; break;
  48. case LANG_TURKISH: uCharset = TURKISH_CHARSET; break;
  49. case LANG_VIETNAMESE: uCharset = VIETNAMESE_CHARSET; break;
  50. case LANG_CHINESE:
  51. if ( (SUBLANGID(uLangID) == SUBLANG_CHINESE_TRADITIONAL) || (SUBLANGID(uLangID) == SUBLANG_CHINESE_HONGKONG) )
  52. uCharset = CHINESEBIG5_CHARSET;
  53. else
  54. uCharset = GB2312_CHARSET;
  55. break;
  56. default:
  57. uCharset = DEFAULT_CHARSET;
  58. }
  59. return uCharset;
  60. }
  61. CTitleInformation::CTitleInformation( CFileSystem* pFileSystem )
  62. {
  63. ClearMemory( this, sizeof( CTitleInformation ) );
  64. m_pFileSystem = pFileSystem;
  65. m_iCharset = -1;
  66. }
  67. CTitleInformation::~CTitleInformation()
  68. {
  69. if (m_pszCompilerVersion)
  70. lcFree (m_pszCompilerVersion); // leak fix
  71. CHECK_AND_FREE( m_pszDefToc );
  72. CHECK_AND_FREE( m_pszDefIndex );
  73. CHECK_AND_FREE( m_pszDefHtml );
  74. CHECK_AND_FREE( m_pszDefCaption );
  75. CHECK_AND_FREE( m_pszDefWindow );
  76. CHECK_AND_FREE( m_pszShortName );
  77. if( m_pdInfoTypes )
  78. lcFree(m_pdInfoTypes );
  79. if (m_paExtTabs) {
  80. for (DWORD i = 0; i < m_cExtTabs; i++) {
  81. lcFree(m_paExtTabs[i].pszTabName);
  82. lcFree(m_paExtTabs[i].pszProgId);
  83. }
  84. lcFree(m_paExtTabs);
  85. }
  86. if ( m_hFontAccessableContent && (m_hFontAccessableContent != m_hFont) )
  87. DeleteObject(m_hFontAccessableContent);
  88. if (m_hFont)
  89. DeleteObject(m_hFont);
  90. }
  91. HRESULT CTitleInformation::Initialize()
  92. {
  93. if( !m_pFileSystem )
  94. return S_FALSE;
  95. // open the title information file (#SYSTEM)
  96. CSubFileSystem* pSubFileSystem = new CSubFileSystem(m_pFileSystem);
  97. HRESULT hr = pSubFileSystem->OpenSub(txtSystemFile);
  98. if( FAILED(hr))
  99. return S_FALSE;
  100. // check the version of the title information file (#SYSTEM)
  101. DWORD dwVersion;
  102. DWORD cbRead;
  103. hr = pSubFileSystem->ReadSub(&dwVersion, sizeof(dwVersion), &cbRead);
  104. if( FAILED(hr) || cbRead != sizeof(dwVersion) ) {
  105. delete pSubFileSystem;
  106. return STG_E_READFAULT;
  107. }
  108. if( dwVersion > VERSION_SYSTEM ) {
  109. // BUGBUG: This will fail if we allow more then one process to attach
  110. // to us -- meaning we won't put up a warning for each process
  111. static BOOL fWarned = FALSE;
  112. if (!fWarned) {
  113. MsgBox(IDS_NEWER_VERSION);
  114. fWarned = TRUE;
  115. }
  116. return STG_E_OLDDLL;
  117. }
  118. // read in each and every item (skip those tags we don't care about)
  119. SYSTEM_TAG tag;
  120. for(;;) {
  121. // get the tag type
  122. hr = pSubFileSystem->ReadSub(&tag, sizeof(SYSTEM_TAG), &cbRead);
  123. if( FAILED(hr) || cbRead != sizeof(SYSTEM_TAG))
  124. break;
  125. // handle each tag according to it's type
  126. switch( tag.tag ) {
  127. // where all of our simple settings are stored
  128. case TAG_SYSTEM_FLAGS: {
  129. ZERO_STRUCTURE( m_Settings );
  130. DWORD cbSettings = sizeof(m_Settings);
  131. DWORD cbTag = tag.cbTag;
  132. DWORD cbReadIn = 0;
  133. if( cbTag > cbSettings )
  134. cbReadIn = cbSettings;
  135. else
  136. cbReadIn = cbTag;
  137. hr = pSubFileSystem->ReadSub( &m_Settings, cbReadIn, &cbRead );
  138. if( cbTag > cbSettings )
  139. hr = pSubFileSystem->SeekSub( cbTag-cbSettings, SEEK_CUR );
  140. break;
  141. }
  142. // where the short name of the title is stored
  143. case TAG_SHORT_NAME:
  144. m_pszShortName = (PCSTR) lcMalloc(tag.cbTag);
  145. hr = pSubFileSystem->ReadSub((void*) m_pszShortName, tag.cbTag, &cbRead);
  146. break;
  147. case TAG_DEFAULT_TOC:
  148. m_pszDefToc = (PCSTR) lcMalloc(tag.cbTag);
  149. hr = pSubFileSystem->ReadSub((void*) m_pszDefToc, tag.cbTag, &cbRead);
  150. break;
  151. case TAG_DEFAULT_INDEX:
  152. m_pszDefIndex = (PCSTR) lcMalloc(tag.cbTag);
  153. hr = pSubFileSystem->ReadSub((void*) m_pszDefIndex, tag.cbTag, &cbRead);
  154. break;
  155. case TAG_DEFAULT_HTML:
  156. m_pszDefHtml = (PCSTR) lcMalloc(tag.cbTag);
  157. hr = pSubFileSystem->ReadSub((void*) m_pszDefHtml, tag.cbTag, &cbRead);
  158. break;
  159. case TAG_DEFAULT_CAPTION:
  160. m_pszDefCaption = (PCSTR) lcMalloc(tag.cbTag);
  161. hr = pSubFileSystem->ReadSub((void*) m_pszDefCaption, tag.cbTag, &cbRead);
  162. break;
  163. case TAG_DEFAULT_WINDOW:
  164. m_pszDefWindow = (PCSTR) lcMalloc(tag.cbTag);
  165. hr = pSubFileSystem->ReadSub((void*) m_pszDefWindow, tag.cbTag, &cbRead);
  166. break;
  167. case TAG_HASH_BINARY_TOC:
  168. hr = pSubFileSystem->ReadSub((void*) &m_hashBinaryTocName, tag.cbTag, &cbRead);
  169. break;
  170. case TAG_HASH_BINARY_INDEX:
  171. hr = pSubFileSystem->ReadSub((void*) &m_hashBinaryIndexName, tag.cbTag, &cbRead);
  172. break;
  173. case TAG_INFO_TYPES:
  174. ASSERT(!m_pdInfoTypes);
  175. m_pdInfoTypes = (INFOTYPE_DATA*) lcMalloc(tag.cbTag);
  176. hr = pSubFileSystem->ReadSub((void*) m_pdInfoTypes, tag.cbTag, &cbRead);
  177. break;
  178. case TAG_COMPILER_VERSION:
  179. m_pszCompilerVersion = (PCSTR) lcMalloc(tag.cbTag);
  180. hr = pSubFileSystem->ReadSub((void*) m_pszCompilerVersion, tag.cbTag, &cbRead);
  181. break;
  182. case TAG_INFOTYPE_COUNT:
  183. hr = pSubFileSystem->ReadSub((void*)&m_iCntInfoTypes, tag.cbTag, &cbRead);
  184. break;
  185. case TAG_IDXHEADER:
  186. hr = pSubFileSystem->ReadSub((void*)&m_idxhdr, tag.cbTag, &cbRead);
  187. m_bGotHeader = TRUE;
  188. break;
  189. case TAG_EXT_TABS:
  190. {
  191. ASSERT_COMMENT(!m_ptblExtTabs, "TAG_EXT_TABS appears in the system file twice.");
  192. hr = pSubFileSystem->ReadSub((void*) &m_cExtTabs, sizeof(DWORD), &cbRead);
  193. CMem mem(tag.cbTag);
  194. hr = pSubFileSystem->ReadSub((void*) mem.pb,
  195. tag.cbTag - sizeof(DWORD), &cbRead);
  196. PCSTR psz = (PCSTR) mem.pb;
  197. m_paExtTabs = (EXTENSIBLE_TAB*) lcMalloc(m_cExtTabs * sizeof(EXTENSIBLE_TAB));
  198. for (DWORD iTab = 0; iTab < m_cExtTabs; iTab++) {
  199. m_paExtTabs[iTab].pszTabName = lcStrDup(psz);
  200. psz += strlen(psz) + 1;
  201. m_paExtTabs[iTab].pszProgId = lcStrDup(psz);
  202. psz += strlen(psz) + 1;
  203. //--- Add the accelerator to the global accelerator list.
  204. char* p = strchr(m_paExtTabs[iTab].pszTabName , '&') ;
  205. if (p != NULL)
  206. {
  207. _Resource.TabCtrlKeys(HH_TAB_CUSTOM_FIRST + iTab, tolower(*(p+1))) ;
  208. }
  209. }
  210. }
  211. break;
  212. case TAG_DEFAULT_FONT:
  213. m_pszDefaultFont = (PCSTR) lcMalloc(tag.cbTag);
  214. hr = pSubFileSystem->ReadSub((void*) m_pszDefaultFont, tag.cbTag, &cbRead);
  215. ASSERT_COMMENT(!m_hFont, "Compiler should never allow two font tags");
  216. m_hFont = (HFONT)1; // just to say we've been here before...
  217. break;
  218. case TAG_NEVER_PROMPT_ON_MERGE:
  219. hr = pSubFileSystem->ReadSub( (void*) &m_bNeverPromptOnMerge, tag.cbTag, &cbRead);
  220. break;
  221. // skip those we don't care about or don't know about
  222. default:
  223. hr = pSubFileSystem->SeekSub( tag.cbTag, SEEK_CUR );
  224. break;
  225. }
  226. if( FAILED(hr) ) {
  227. delete pSubFileSystem;
  228. return STG_E_READFAULT;
  229. }
  230. }
  231. delete pSubFileSystem;
  232. //
  233. // Init title charset.
  234. //
  235. unsigned short uLangID = PRIMARYLANGID(LANGIDFROMLCID(m_Settings.lcid));
  236. m_iCharset = CharsetFromLangID(uLangID);
  237. //
  238. // Init the title font...
  239. //
  240. _Module.SetCodePage(CodePageFromLCID(m_Settings.lcid));
  241. #ifndef CHIINDEX
  242. InitContentFont(m_pszDefaultFont);
  243. #endif
  244. m_bInit = TRUE;
  245. return S_OK;
  246. }
  247. void CTitleInformation::InitContentFont(PCSTR pszFontSpec)
  248. {
  249. TCHAR szLocal[MAX_PATH];
  250. PSTR pszComma;
  251. LOGFONT lf;
  252. NONCLIENTMETRICS ncm;
  253. //
  254. // We're only going to trust the charset specification if it came from the title!
  255. //
  256. if ( !pszFontSpec || !(*pszFontSpec) )
  257. {
  258. // if Win9X on Japaneese system. AsPer Achimru Bug# 7012
  259. //
  260. if ( (GetVersion() >= 0x80000000) && ( (_Module.m_Language.GetUiLanguage() & 0x00FF) == LANG_JAPANESE) )
  261. pszFontSpec = "MS P Gothic,9,128";
  262. else
  263. {
  264. #ifndef HHUTIL
  265. pszFontSpec = (PSTR)GetStringResource(IDS_DEFAULT_CONTENT_FONT);
  266. #endif
  267. // HH bugs 7859 and 7707:
  268. //
  269. // It turns out that on Win9x, using DEFAULT_CHARSET means I don't care about the char set. Soooo, the
  270. // last thing we want to do is use a blank facename with default charset on Win9x. On NT, default_charset
  271. // has a reasonable meaning, i.e. use an appropiate charset based on system locale. So, to fix the above
  272. // bugs, I'm only going to execute this logic on NT. <mc>
  273. //
  274. if( g_fSysWinNT )
  275. {
  276. // lang != english AND the resID charset does NOT match the .CHM charset then use a blank facename
  277. // but retain the pointsize specified in the resource string.
  278. //
  279. char* pszFS = StrChr(pszFontSpec, ',');
  280. int iCharSet = Atoi(pszFontSpec + 1);
  281. if ( pszFontSpec && ((m_iCharset != ANSI_CHARSET) || (m_iCharset != DEFAULT_CHARSET)) && (iCharSet != m_iCharset) )
  282. pszFontSpec = pszFS;
  283. }
  284. }
  285. if ( !pszFontSpec )
  286. {
  287. // nothing specified in the .res file. Go with hardcoded defaults?
  288. //
  289. lstrcpy(szLocal, "MS Shell Dlg,8");
  290. }
  291. else
  292. lstrcpy(szLocal, pszFontSpec);
  293. }
  294. else
  295. {
  296. //
  297. // We have a specification from the .HHP file, insure it matches the LCID specified in the .HHP
  298. // The specification string is formatted as followes:
  299. // Facename, point size, charset, (BOLD | ITALIC | UNDERLINE) | 0x???? colorspec | #rrggbb colorspec
  300. //
  301. // We'll override the charset selected from the title LCID if we have a valid one specified in the title font.
  302. //
  303. lstrcpy(szLocal, pszFontSpec);
  304. if ( (pszComma = StrChr(szLocal, ',')) )
  305. {
  306. pszComma++;
  307. if ( (pszComma = StrChr(pszComma, ',')) )
  308. {
  309. pszComma++;
  310. m_iCharset = atoi(pszComma);
  311. }
  312. }
  313. }
  314. // We (Doug and Mikecole) have decided to override the ANSI charset (english) with the current user charset
  315. // in the event we find we're viweing an english chm on a non englist system on Win9X...
  316. //
  317. if ( (m_iCharset == ANSI_CHARSET) )
  318. {
  319. LANGID lid = _Module.m_Language.GetUiLanguage();
  320. m_iCharset = CharsetFromLangID(lid);
  321. }
  322. if(g_fSysWinNT)
  323. {
  324. char wchLocale[10];
  325. // Check to see if the system understands the LCID of the title. If not, we have no way of
  326. // accurately processing the text in szLocal (it's in an encoding the OS doesn't understand).
  327. // The only safe thing we can do is to default to MS Shell Dlg and hope for the best.
  328. //
  329. if (!GetLocaleInfoA(m_Settings.lcid, LOCALE_IDEFAULTANSICODEPAGE, wchLocale, sizeof(wchLocale)))
  330. lstrcpy(szLocal, "MS Shell Dlg,8");
  331. WCHAR *pwcLocal = MakeWideStr(szLocal,CodePageFromLCID(m_Settings.lcid));
  332. if(pwcLocal)
  333. {
  334. m_hFont = CreateUserFontW(pwcLocal, NULL, NULL, m_iCharset);
  335. free(pwcLocal);
  336. }
  337. }
  338. else
  339. m_hFont = CreateUserFont(szLocal, NULL, NULL, m_iCharset);
  340. ASSERT(m_hFont);
  341. BOOL bRet1 = GetObject(m_hFont, sizeof(lf), &lf) ;
  342. ncm.cbSize = sizeof(NONCLIENTMETRICS);
  343. BOOL bRet2 = SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), (void*)&ncm, 0);
  344. if ( bRet1 && bRet2 && (ncm.lfMenuFont.lfHeight < lf.lfHeight) )
  345. {
  346. lf.lfHeight = ncm.lfMenuFont.lfHeight;
  347. m_hFontAccessableContent = CreateFontIndirect(&lf);
  348. }
  349. else
  350. m_hFontAccessableContent = m_hFont;
  351. }
  352. /////////////////////////////////////////////////////////////////////////////////////////////
  353. // CTitleInformation2 - get title informaton without going through the file system
  354. //
  355. CTitleInformation2::CTitleInformation2( LPCTSTR pszPathName )
  356. {
  357. ClearMemory( this, sizeof(CTitleInformation2) );
  358. m_pszPathName = pszPathName;
  359. }
  360. CTitleInformation2::~CTitleInformation2()
  361. {
  362. if( m_pszShortName )
  363. delete [] (PSTR) m_pszShortName;
  364. }
  365. HRESULT CTitleInformation2::Initialize()
  366. {
  367. HANDLE hFile = CreateFile( m_pszPathName, GENERIC_READ, FILE_SHARE_READ,
  368. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL );
  369. if( hFile == INVALID_HANDLE_VALUE )
  370. return S_FALSE;
  371. DWORD dwFileStamp = 0;
  372. LCID FileLocale = 0;
  373. DWORD dwRead = 0;
  374. SetFilePointer( hFile, 4*sizeof(UINT), NULL, FILE_BEGIN );
  375. ReadFile( hFile, (void*) &dwFileStamp, sizeof( dwFileStamp ), &dwRead, NULL );
  376. ReadFile( hFile, (void*) &FileLocale, sizeof( FileLocale ), &dwRead, NULL );
  377. CloseHandle( hFile );
  378. m_FileTime.dwLowDateTime = dwFileStamp;
  379. m_FileTime.dwHighDateTime = dwFileStamp;
  380. m_lcid = FileLocale;
  381. TCHAR szShortName[MAX_PATH];
  382. LPTSTR pszShortName = szShortName;
  383. GetFullPathName( m_pszPathName, MAX_PATH, szShortName, &pszShortName );
  384. LPTSTR pszShortNameEnd = StrRChr( pszShortName, '.' );
  385. *pszShortNameEnd = 0;
  386. m_pszShortName = new char[ strlen(pszShortName)+1 ];
  387. strcpy( (PSTR) m_pszShortName, pszShortName );
  388. m_bInit = TRUE;
  389. return S_OK;
  390. }
  391. /////////////////////////////////////////////////////////////////////////////////////////////
  392. // CHmData
  393. //
  394. #ifdef _WIN64
  395. typedef struct tagHH_DISK_WINTYPE {
  396. int cbStruct; // IN: size of this structure including all Information Types
  397. BOOL fUniCodeStrings; // IN/OUT: TRUE if all strings are in UNICODE
  398. DWORD /*LPCTSTR*/ pszType;// IN/OUT: Name of a type of window
  399. DWORD fsValidMembers; // IN: Bit flag of valid members (HHWIN_PARAM_)
  400. DWORD fsWinProperties; // IN/OUT: Properties/attributes of the window (HHWIN_)
  401. DWORD /*LPCTSTR*/ pszCaption;// IN/OUT: Window title
  402. DWORD dwStyles; // IN/OUT: Window styles
  403. DWORD dwExStyles; // IN/OUT: Extended Window styles
  404. RECT rcWindowPos; // IN: Starting position, OUT: current position
  405. int nShowState; // IN: show state (e.g., SW_SHOW)
  406. LONG /*HWND*/ hwndHelp; // OUT: window handle
  407. LONG /*HWND*/ hwndCaller; // OUT: who called this window
  408. DWORD /*HH_INFOTYPE* */ paInfoTypes; // IN: Pointer to an array of Information Types
  409. // The following members are only valid if HHWIN_PROP_TRI_PANE is set
  410. LONG /*HWND*/ hwndToolBar; // OUT: toolbar window in tri-pane window
  411. LONG /*HWND*/ hwndNavigation; // OUT: navigation window in tri-pane window
  412. LONG /*HWND*/ hwndHTML; // OUT: window displaying HTML in tri-pane window
  413. int iNavWidth; // IN/OUT: width of navigation window
  414. RECT rcHTML; // OUT: HTML window coordinates
  415. DWORD /*LPCTSTR*/ pszToc; // IN: Location of the table of contents file
  416. DWORD /*LPCTSTR*/ pszIndex; // IN: Location of the index file
  417. DWORD /*LPCTSTR*/ pszFile; // IN: Default location of the html file
  418. DWORD /*LPCTSTR*/ pszHome; // IN/OUT: html file to display when Home button is clicked
  419. DWORD fsToolBarFlags; // IN: flags controling the appearance of the toolbar
  420. BOOL fNotExpanded; // IN: TRUE/FALSE to contract or expand, OUT: current state
  421. int curNavType; // IN/OUT: UI to display in the navigational pane
  422. int tabpos; // IN/OUT: HHWIN_NAVTAB_TOP, HHWIN_NAVTAB_LEFT, or HHWIN_NAVTAB_BOTTOM
  423. int idNotify; // IN: ID to use for WM_NOTIFY messages
  424. BYTE tabOrder[HH_MAX_TABS + 1]; // IN/OUT: tab order: Contents, Index, Search, History, Favorites, Reserved 1-5, Custom tabs
  425. int cHistory; // IN/OUT: number of history items to keep (default is 30)
  426. DWORD /*LPCTSTR*/ pszJump1; // Text for HHWIN_BUTTON_JUMP1
  427. DWORD /*LPCTSTR*/ pszJump2; // Text for HHWIN_BUTTON_JUMP2
  428. DWORD /*LPCTSTR*/ pszUrlJump1; // URL for HHWIN_BUTTON_JUMP1
  429. DWORD /*LPCTSTR*/ pszUrlJump2; // URL for HHWIN_BUTTON_JUMP2
  430. RECT rcMinSize; // Minimum size for window (ignored in version 1)
  431. int cbInfoTypes; // size of paInfoTypes;
  432. DWORD /*LPCTSTR*/ pszCustomTabs; // multiple zero-terminated strings
  433. } HH_DISK_WINTYPE, *PHH_DISK_WINTYPE;
  434. static
  435. void ConvertToWin64HHWinType( HH_WINTYPE& rWinType , const HH_DISK_WINTYPE& rDiskWinType )
  436. {
  437. rWinType.cbStruct = sizeof(HH_WINTYPE); // ???
  438. rWinType.fUniCodeStrings = rDiskWinType.fUniCodeStrings;
  439. // LPCTSTR pszType; // IN/OUT: Name of a type of window
  440. rWinType.fsValidMembers = rDiskWinType.fsValidMembers;
  441. rWinType.fsWinProperties = rDiskWinType.fsWinProperties;
  442. // LPCTSTR pszCaption; // IN/OUT: Window title
  443. rWinType.dwStyles = rDiskWinType.dwStyles;
  444. rWinType.dwExStyles = rDiskWinType.dwExStyles;
  445. CopyRect( &rWinType.rcWindowPos, &rDiskWinType.rcWindowPos );
  446. rWinType.nShowState = rDiskWinType.nShowState;
  447. // HWND hwndHelp; // OUT: window handle
  448. // HWND hwndCaller; // OUT: who called this window
  449. // HH_INFOTYPE* paInfoTypes; // IN: Pointer to an array of Information Types
  450. // HWND hwndToolBar; // OUT: toolbar window in tri-pane window
  451. // HWND hwndNavigation; // OUT: navigation window in tri-pane window
  452. // HWND hwndHTML; // OUT: window displaying HTML in tri-pane window
  453. rWinType.iNavWidth = rDiskWinType.iNavWidth;
  454. CopyRect( &rWinType.rcHTML, &rDiskWinType.rcHTML );
  455. // LPCTSTR pszToc; // IN: Location of the table of contents file
  456. // LPCTSTR pszIndex; // IN: Location of the index file
  457. // LPCTSTR pszFile; // IN: Default location of the html file
  458. // LPCTSTR pszHome; // IN/OUT: html file to display when Home button is clicked
  459. rWinType.fsToolBarFlags = rDiskWinType.fsToolBarFlags;
  460. rWinType.fNotExpanded = rDiskWinType.fNotExpanded;
  461. rWinType.curNavType = rDiskWinType.curNavType;
  462. rWinType.tabpos = rDiskWinType.tabpos;
  463. rWinType.idNotify = rDiskWinType.idNotify;
  464. memcpy( rWinType.tabOrder, rDiskWinType.tabOrder, sizeof(rWinType.tabOrder) );
  465. rWinType.cHistory = rDiskWinType.cHistory;
  466. // LPCTSTR pszJump1; // Text for HHWIN_BUTTON_JUMP1
  467. // LPCTSTR pszJump2; // Text for HHWIN_BUTTON_JUMP2
  468. // LPCTSTR pszUrlJump1; // URL for HHWIN_BUTTON_JUMP1
  469. // LPCTSTR pszUrlJump2; // URL for HHWIN_BUTTON_JUMP2
  470. CopyRect( &rWinType.rcMinSize, &rDiskWinType.rcMinSize );
  471. rWinType.cbInfoTypes = rDiskWinType.cbInfoTypes;
  472. // LPCTSTR pszCustomTabs; // multiple zero-terminated strings
  473. }
  474. #endif
  475. CHmData::CHmData()
  476. {
  477. ClearMemory(this, sizeof(CHmData));
  478. }
  479. CHmData::~CHmData()
  480. {
  481. if( m_pszDefToc )
  482. lcFree( m_pszDefToc );
  483. if( m_pszDefIndex )
  484. lcFree( m_pszDefIndex );
  485. if (m_pTitleCollection)
  486. delete m_pTitleCollection;
  487. if (m_pdSubSets)
  488. lcFree(m_pdSubSets);
  489. if (m_pszITSSFile)
  490. lcFree(m_pszITSSFile);
  491. }
  492. int CHmData::Release(void)
  493. {
  494. if ( cRef )
  495. cRef--;
  496. if (! cRef )
  497. {
  498. delete this;
  499. return 0;
  500. }
  501. else
  502. return cRef;
  503. }
  504. HFONT CHmData::GetContentFont()
  505. {
  506. return (m_pTitleCollection->GetMasterTitle()->GetInfo()->GetContentFont());
  507. }
  508. // BUGBUG: This is broken! We cannot pass in any random offset and use GetFirstTitle() to fetch a string. <mc>
  509. PCSTR CHmData::GetString(DWORD offset)
  510. {
  511. ASSERT(m_pTitleCollection);
  512. ASSERT(m_pTitleCollection->GetFirstTitle());
  513. ASSERT(m_pTitleCollection->GetFirstTitle()->GetString(offset));
  514. return m_pTitleCollection->GetFirstTitle()->GetString(offset);
  515. }
  516. CExTitle* CHmData::GetExTitle(void)
  517. {
  518. ASSERT(m_pTitleCollection);
  519. ASSERT(m_pTitleCollection->GetFirstTitle());
  520. return m_pTitleCollection->GetFirstTitle();
  521. }
  522. BOOL CHmData::ReadSubSets( CExTitle *pTitle )
  523. {
  524. ULONG cbRead;
  525. HRESULT hr;
  526. SYSTEM_TAG tag;
  527. CFSClient fsclient(pTitle->GetFileSystem(), txtSubSetFile);
  528. if (!fsclient.isStreamOpen())
  529. return TRUE;
  530. hr = fsclient.Read(&tag, sizeof(SYSTEM_TAG), &cbRead);
  531. if (FAILED(hr) || cbRead != sizeof(SYSTEM_TAG))
  532. {
  533. fsclient.CloseStream();
  534. return STG_E_READFAULT;
  535. }
  536. m_pdSubSets = (SUBSET_DATA *)lcMalloc(tag.cbTag);
  537. hr = fsclient.Read(m_pdSubSets, tag.cbTag, &cbRead);
  538. if (FAILED(hr) || cbRead != tag.cbTag)
  539. {
  540. fsclient.CloseStream();
  541. return STG_E_READFAULT;
  542. }
  543. return S_OK;
  544. }
  545. BOOL CHmData::ReadSystemFiles(PCSTR pszITSSFile)
  546. {
  547. TCHAR szScratch[MAX_PATH];
  548. m_pTitleCollection = new CExCollection(this, pszITSSFile, !IsCollectionFile(pszITSSFile));
  549. if (m_pTitleCollection->InitCollection() == FALSE)
  550. return FALSE;
  551. CTitleInformation *pInfo = m_pTitleCollection->GetMasterTitle()->GetInfo();
  552. LANGID MasterLangId;
  553. if (pInfo)
  554. MasterLangId = LANGIDFROMLCID(pInfo->GetLanguage());
  555. else
  556. return FALSE;
  557. //
  558. // Determine if we are running a bidi title or collection
  559. //
  560. // This is the place where we turn on/off bi-di settings for the help system
  561. //
  562. if(PRIMARYLANGID(MasterLangId) == LANG_HEBREW || PRIMARYLANGID(MasterLangId) == LANG_ARABIC)
  563. {
  564. g_fuBiDiMessageBox = MB_RIGHT | MB_RTLREADING;
  565. // Turn on the Bi-Di "Mirroring" style when running on Bi-Di system and Win98 or NT5
  566. //
  567. if(g_bWinNT5 || g_bWin98)
  568. {
  569. // MessageBox(NULL,"Bidi Enabled NT5/Win98","Notice",MB_OK);
  570. g_RTL_Mirror_Style = WS_EX_LAYOUT_RTL | WS_EX_LTRREADING | WS_EX_RIGHT;
  571. g_RTL_Style = WS_EX_RTLREADING | WS_EX_RIGHT;
  572. }
  573. else
  574. {
  575. // MessageBox(NULL,"Bidi Under NT4/Win95","Notice",MB_OK);
  576. g_RTL_Mirror_Style = 0;
  577. g_RTL_Style = WS_EX_RTLREADING | WS_EX_RIGHT;
  578. }
  579. g_fBiDi = TRUE;
  580. }
  581. else
  582. {
  583. // MessageBox(NULL,"Bidi Not Enabled","Notice",MB_OK);
  584. g_fuBiDiMessageBox = 0;
  585. g_RTL_Style = 0;
  586. g_fBiDi = FALSE;
  587. }
  588. CExTitle* pTitle = m_pTitleCollection->GetMasterTitle();
  589. CStr cszCompiledFile(pTitle->GetIndexFileName());
  590. if (ReadSystemFile(pTitle) == FALSE)
  591. return FALSE;
  592. m_pInfo = pTitle->GetInfo();
  593. // init fts and keyword
  594. m_pTitleCollection->InitFTSKeyword();
  595. // init structural subsetting if appropiate.
  596. //
  597. m_pTitleCollection->InitStructuralSubsets();
  598. // Read the SubSets
  599. ReadSubSets ( pTitle ); //from the #SUBSETS subfile
  600. // Init the Infotypes and predefined subsets objects from the master title...
  601. if ( pTitle && pTitle->GetInfo() )
  602. {
  603. int iCntITBytes = ((pTitle->GetInfo()->GetInfoTypeCount() / 8) + 1);
  604. if ( ( m_pTitleCollection->m_pSubSets = new CSubSets(iCntITBytes, this, FALSE)) )
  605. m_pTitleCollection->m_pSubSets->CopyTo(this);
  606. //
  607. // Add "Entire Collection" to the list since all subset users (FTS, TOC and Index) use it.
  608. //
  609. CSubSet* pS = m_pTitleCollection->m_pSubSets->AddSubSet();
  610. pS->m_bIsEntireCollection = TRUE;
  611. pS->m_cszSubSetName = (PCSTR)GetStringResource(IDS_ADVSEARCH_SEARCHIN_ENTIRE);
  612. memset(pS->m_pInclusive, 0xFF, pS->m_pIT->InfoTypeSize());
  613. // Mask out all the hidden ITs from entire contents.
  614. INFOTYPE HiddenIT;
  615. for ( int i=0; i< pS->m_pIT->m_itTables.m_cITSize; i++)
  616. { HiddenIT = (*pS->m_pInclusive)+i & ~(*pS->m_pIT->m_itTables.m_pHidden)+i;
  617. memcpy( &(*pS->m_pInclusive)+i, &HiddenIT, sizeof(INFOTYPE) ); // flip the Hidden bits in the filter mask
  618. }
  619. pS->m_bPredefined = TRUE;
  620. //
  621. // Restore persisted subset selections for FTS, Index anf TOC.
  622. //
  623. CState* pstate = m_pTitleCollection->GetState();
  624. DWORD cb;
  625. if ( SUCCEEDED(pstate->Open(g_szFTSKey,STGM_READ)) && SUCCEEDED(pstate->Read(szScratch,MAX_PATH,&cb)) && cb > 0 )
  626. m_pTitleCollection->m_pSubSets->SetFTSMask(szScratch);
  627. else
  628. m_pTitleCollection->m_pSubSets->SetFTSMask(pS->m_cszSubSetName); // Entire Collection.
  629. pstate->Close();
  630. if ( SUCCEEDED(pstate->Open(g_szIndexKey,STGM_READ)) && SUCCEEDED(pstate->Read(szScratch,MAX_PATH,&cb)) && cb > 0 )
  631. m_pTitleCollection->m_pSubSets->SetIndexMask(szScratch);
  632. else
  633. m_pTitleCollection->m_pSubSets->SetIndexMask(pS->m_cszSubSetName); // Entire Collection.
  634. pstate->Close();
  635. if ( SUCCEEDED(pstate->Open(g_szTOCKey,STGM_READ)) && SUCCEEDED(pstate->Read(szScratch,MAX_PATH,&cb)) && cb > 0 )
  636. m_pTitleCollection->m_pSubSets->SetTocMask(szScratch, NULL);
  637. else
  638. m_pTitleCollection->m_pSubSets->SetTocMask(pS->m_cszSubSetName, NULL); // Entire Collection.
  639. pstate->Close();
  640. }
  641. // Read all the window definitions
  642. CFSClient fsclient(pTitle->GetFileSystem(), txtWindowsFile);
  643. if (!fsclient.isStreamOpen())
  644. return TRUE;
  645. DWORD cWindows;
  646. DWORD cbStruct;
  647. ULONG cbRead;
  648. CStr csz;
  649. HRESULT hr = fsclient.Read(&cWindows, sizeof(DWORD), &cbRead);
  650. if (FAILED(hr) || cbRead != sizeof(DWORD))
  651. goto ForgetIt;
  652. hr = fsclient.Read(&cbStruct, sizeof(DWORD), &cbRead);
  653. if (FAILED(hr) || cbRead != sizeof(DWORD))
  654. goto ForgetIt;
  655. HH_WINTYPE hhWinType;
  656. #ifdef _WIN64
  657. HH_DISK_WINTYPE hhDiskWinType;
  658. #else
  659. #define hhDiskWinType hhWinType
  660. #endif
  661. DWORD i;
  662. for (i = 0; i < cWindows; i++)
  663. {
  664. ZERO_STRUCTURE(hhWinType);
  665. #ifdef _WIN64
  666. ZERO_STRUCTURE(hhDiskWinType);
  667. #endif
  668. hr = fsclient.Read(&hhDiskWinType, cbStruct, &cbRead);
  669. #ifdef _WIN64
  670. ConvertToWin64HHWinType( hhWinType, hhDiskWinType );
  671. #endif
  672. if (FAILED(hr) || cbRead != cbStruct)
  673. goto ForgetIt;
  674. if (SUCCEEDED(m_pTitleCollection->GetFirstTitle()->GetString(
  675. (DWORD) hhDiskWinType.pszType, &csz)))
  676. csz.TransferPointer(&hhWinType.pszType);
  677. if (SUCCEEDED(m_pTitleCollection->GetFirstTitle()->GetString(
  678. (DWORD) hhDiskWinType.pszCaption, &csz)))
  679. csz.TransferPointer(&hhWinType.pszCaption);
  680. if (SUCCEEDED(m_pTitleCollection->GetFirstTitle()->GetString(
  681. (DWORD) hhDiskWinType.pszJump1, &csz)))
  682. csz.TransferPointer(&hhWinType.pszJump1);
  683. if (SUCCEEDED(m_pTitleCollection->GetFirstTitle()->GetString(
  684. (DWORD) hhDiskWinType.pszJump2, &csz)))
  685. csz.TransferPointer(&hhWinType.pszJump2);
  686. // BUGBUG: needs to match compiler which should be using URL store
  687. if (SUCCEEDED(m_pTitleCollection->GetFirstTitle()->GetString((DWORD) hhDiskWinType.pszToc, &csz)))
  688. {
  689. if (csz.IsNonEmpty()) // BUGBUG: GetString should fail on Empty strings.
  690. {
  691. if (!m_pszDefToc)
  692. m_pszDefToc = lcStrDup(csz.psz);
  693. if (!stristr(csz, txtDoubleColonSep) &&
  694. !stristr(csz, txtFileHeader) && !stristr(csz, txtHttpHeader)) {
  695. cszCompiledFile = GetCompiledFile();
  696. cszCompiledFile += txtSepBack;
  697. cszCompiledFile += csz.psz;
  698. cszCompiledFile.TransferPointer(&hhWinType.pszToc);
  699. }
  700. else
  701. csz.TransferPointer(&hhWinType.pszToc);
  702. }
  703. }
  704. if (SUCCEEDED(m_pTitleCollection->GetFirstTitle()->GetString((DWORD) hhDiskWinType.pszIndex, &csz)))
  705. {
  706. if (csz.IsNonEmpty()) // BUGBUG: GetString should fail on Empty strings.
  707. {
  708. if (!m_pszDefIndex)
  709. m_pszDefIndex = lcStrDup(csz.psz);
  710. if (!stristr(csz, txtDoubleColonSep) &&
  711. !stristr(csz, txtFileHeader) && !stristr(csz, txtHttpHeader))
  712. {
  713. cszCompiledFile = GetCompiledFile();
  714. cszCompiledFile += txtSepBack;
  715. cszCompiledFile += csz.psz;
  716. cszCompiledFile.TransferPointer(&hhWinType.pszIndex);
  717. }
  718. else
  719. csz.TransferPointer(&hhWinType.pszIndex);
  720. }
  721. }
  722. if (SUCCEEDED(m_pTitleCollection->GetFirstTitle()->GetString(
  723. (DWORD) hhDiskWinType.pszFile, &csz))) {
  724. #if 0
  725. if (!stristr(csz, txtDoubleColonSep) &&
  726. !stristr(csz, txtFileHeader) && !stristr(csz, txtHttpHeader)) {
  727. cszCompiledFile = GetCompiledFile();
  728. cszCompiledFile += txtSepBack;
  729. cszCompiledFile += csz.psz;
  730. cszCompiledFile.TransferPointer(&hhWinType.pszFile);
  731. }
  732. else
  733. #endif
  734. csz.TransferPointer(&hhWinType.pszFile);
  735. }
  736. if (SUCCEEDED(m_pTitleCollection->GetFirstTitle()->GetString(
  737. (DWORD) hhDiskWinType.pszHome, &csz))) {
  738. if (!stristr(csz, txtDoubleColonSep) &&
  739. !stristr(csz, txtFileHeader) && !stristr(csz, txtHttpHeader)) {
  740. cszCompiledFile = GetCompiledFile();
  741. cszCompiledFile += txtSepBack;
  742. cszCompiledFile += csz.psz;
  743. cszCompiledFile.TransferPointer(&hhWinType.pszHome);
  744. }
  745. else
  746. csz.TransferPointer(&hhWinType.pszHome);
  747. }
  748. if (SUCCEEDED(m_pTitleCollection->GetFirstTitle()->GetString(
  749. (DWORD) hhDiskWinType.pszUrlJump1, &csz))) {
  750. if (!stristr(csz, txtDoubleColonSep) &&
  751. !stristr(csz, txtFileHeader) && !stristr(csz, txtHttpHeader)) {
  752. cszCompiledFile = GetCompiledFile();
  753. cszCompiledFile += txtSepBack;
  754. cszCompiledFile += csz.psz;
  755. cszCompiledFile.TransferPointer(&hhWinType.pszUrlJump1);
  756. }
  757. else
  758. csz.TransferPointer(&hhWinType.pszUrlJump1);
  759. }
  760. if (SUCCEEDED(m_pTitleCollection->GetFirstTitle()->GetString(
  761. (DWORD) hhDiskWinType.pszUrlJump2, &csz))) {
  762. if (!stristr(csz, txtDoubleColonSep) &&
  763. !stristr(csz, txtFileHeader) && !stristr(csz, txtHttpHeader)) {
  764. cszCompiledFile = GetCompiledFile();
  765. cszCompiledFile += txtSepBack;
  766. cszCompiledFile += csz.psz;
  767. cszCompiledFile.TransferPointer(&hhWinType.pszUrlJump2);
  768. }
  769. else
  770. csz.TransferPointer(&hhWinType.pszUrlJump2);
  771. }
  772. // Set the window type, but don't call FindCurFileData...
  773. SetWinType(pszITSSFile, &hhWinType, this);
  774. CHECK_AND_FREE(hhWinType.pszType) ;
  775. CHECK_AND_FREE(hhWinType.pszCaption) ;
  776. CHECK_AND_FREE(hhWinType.pszToc) ;
  777. CHECK_AND_FREE(hhWinType.pszIndex) ;
  778. CHECK_AND_FREE(hhWinType.pszFile) ;
  779. CHECK_AND_FREE(hhWinType.pszHome) ;
  780. CHECK_AND_FREE(hhWinType.pszJump1) ;
  781. CHECK_AND_FREE(hhWinType.pszJump2) ;
  782. CHECK_AND_FREE(hhWinType.pszUrlJump1) ;
  783. CHECK_AND_FREE(hhWinType.pszUrlJump2) ;
  784. }
  785. #ifndef _WIN64
  786. #undef hhDiskWinType
  787. #endif
  788. ForgetIt:
  789. fsclient.CloseStream();
  790. return TRUE;
  791. }
  792. BOOL CHmData::ReadSystemFile(CExTitle* pTitle)
  793. {
  794. ASSERT(pTitle);
  795. CTitleInformation *pInfo = pTitle->GetInfo();
  796. if (!pInfo)
  797. return FALSE;
  798. m_sysflags = pInfo->GetSystemFlags();
  799. m_pszDefToc = lcStrDup( pInfo->GetDefaultToc() );
  800. m_pszDefIndex = lcStrDup( pInfo->GetDefaultIndex() );
  801. m_pszDefHtml = pInfo->GetDefaultHtml();
  802. m_pszDefCaption = pInfo->GetDefaultCaption();
  803. m_pszDefWindow = pInfo->GetDefaultWindow();
  804. m_pszShortName = pInfo->GetShortName();
  805. m_hashBinaryTocName = pInfo->GetBinaryTocNameHash();
  806. m_hashBinaryIndexName = pInfo->GetBinaryIndexNameHash();
  807. m_pdInfoTypes = pInfo->GetInfoTypeData();
  808. return TRUE;
  809. }
  810. void CHmData::PopulateUNICODETables( void )
  811. {
  812. if ( !m_ptblIT )
  813. {
  814. ASSERT(!m_ptblIT_Desc);
  815. ASSERT(!m_ptblCat);
  816. ASSERT(!m_ptblCat_Desc);
  817. if ( !m_pInfoType )
  818. {
  819. m_pInfoType = new CInfoType();
  820. m_pInfoType->CopyTo( this );
  821. }
  822. // populate the unicode CTables for Info Type and Catagory strings.
  823. m_ptblIT = new CTable(16 * 1024 * 2);
  824. m_ptblIT_Desc = new CTable(64 * 1024 * 2);
  825. m_ptblCat = new CTable(16 * 1024 * 2);
  826. m_ptblCat_Desc = new CTable(64 * 1024 * 2);
  827. for ( int i=1; i <= m_pInfoType->HowManyInfoTypes(); i++ )
  828. {
  829. CWStr cwsz( (PCSTR)m_pInfoType->GetInfoTypeName(i) );
  830. m_ptblIT->AddString( cwsz.pw );
  831. cwsz = (PCSTR)m_pInfoType->GetInfoTypeDescription(i);
  832. m_ptblIT_Desc->AddString( cwsz.pw );
  833. }
  834. for ( i=1; i <= m_pInfoType->HowManyCategories(); i++ )
  835. {
  836. CWStr cwsz( (PCSTR)m_pInfoType->GetCategoryString(i) );
  837. m_ptblCat->AddString( cwsz.pw );
  838. cwsz = (PCSTR)m_pInfoType->GetCategoryDescription(i);
  839. m_ptblCat_Desc->AddString( cwsz.pw );
  840. }
  841. }
  842. }
  843. /////////////////////////////////////////////////////////////////////////////////////////////
  844. // CHmData Helper functions
  845. //
  846. void DeleteAllHmData()
  847. {
  848. for (int i = 0; i < g_cHmSlots; i++)
  849. {
  850. if (g_phmData[i])
  851. {
  852. CHmData* p = g_phmData[i];
  853. g_phmData[i] = NULL;
  854. delete p;
  855. }
  856. }
  857. }
  858. CHmData* FindCurFileData(PCSTR pszITSSFile)
  859. {
  860. CStr csz;
  861. if (!FindThisFile(NULL, pszITSSFile, &csz, FALSE))
  862. return NULL;
  863. if (!g_phmData)
  864. goto NeverSeen;
  865. if (IsCollectionFile(csz))
  866. {
  867. // Check current system data first
  868. if (g_phmData[g_curHmData] &&
  869. g_phmData[g_curHmData]->m_pTitleCollection &&
  870. lstrcmpi(csz, g_phmData[g_curHmData]->m_pTitleCollection->m_csFile) == 0) {
  871. return g_phmData[g_curHmData];
  872. }
  873. // Not current, so check our cache
  874. for (int i = 0; i < g_cHmSlots; i++) {
  875. if (g_phmData[i] &&
  876. g_phmData[i]->m_pTitleCollection &&
  877. lstrcmpi(csz,g_phmData[i]->m_pTitleCollection->m_csFile) == 0) {
  878. return g_phmData[i];
  879. }
  880. }
  881. }
  882. else
  883. {
  884. if (g_phmData[g_curHmData] &&
  885. lstrcmpi(csz, g_phmData[g_curHmData]->GetCompiledFile()) == 0) {
  886. return g_phmData[g_curHmData];
  887. }
  888. // Not current, so check our cache
  889. for (int i = 0; i < g_cHmSlots; i++) {
  890. if (g_phmData[i] &&
  891. lstrcmpi(csz, g_phmData[i]->GetCompiledFile()) == 0) {
  892. return g_phmData[i];
  893. }
  894. }
  895. }
  896. NeverSeen:
  897. // If we get here, then either we haven't seen the file before, or it
  898. // isn't cached.
  899. if (!AddTitleToGlobalList(csz))
  900. return NULL;
  901. else
  902. {
  903. return g_phmData[g_curHmData];
  904. }
  905. }
  906. /***************************************************************************
  907. FUNCTION: AddTitleToGlobalList
  908. PURPOSE: Read the various system files into memory
  909. PARAMETERS:
  910. pszITSSFile
  911. RETURNS:
  912. COMMENTS:
  913. MODIFICATION DATES:
  914. 30-Apr-1997 [ralphw]
  915. 03-Mar-1998 [dalero] no more process ids
  916. ***************************************************************************/
  917. BOOL AddTitleToGlobalList(PCSTR pszITSSFile)
  918. {
  919. // HH BUG 2428
  920. // Make sure that we can read the file in before we put it in the array.
  921. if (IsFile(pszITSSFile) == FALSE)
  922. return FALSE;
  923. CHmData* pHmData = new CHmData;
  924. BOOL bResult = pHmData->ReadSystemFiles(pszITSSFile);
  925. if (!bResult)
  926. {
  927. // The ReadSystemFiles call failed. Cleanup and get out.
  928. delete pHmData ;
  929. }
  930. else
  931. {
  932. // We have valid data. Get us a place to store it.
  933. if (!g_phmData) {
  934. g_cHmSlots = 5;
  935. g_phmData = (CHmData**) lcCalloc(g_cHmSlots * sizeof(CHmData*));
  936. for (int i = 0; i < g_cHmSlots; i++) // just in case
  937. g_phmData[i] = NULL;
  938. }
  939. // Find an open slot to store the file data
  940. for (int pos = 0; pos < g_cHmSlots; pos++) {
  941. if (!g_phmData[pos])
  942. break;
  943. }
  944. if (pos == g_cHmSlots) {
  945. g_cHmSlots += 5;
  946. g_phmData = (CHmData**) lcReAlloc(g_phmData, g_cHmSlots * sizeof(CHmData*));
  947. for (int i = pos; i < g_cHmSlots; i++)
  948. g_phmData[i] = NULL;
  949. }
  950. // Store the new data.
  951. g_phmData[pos] = pHmData;
  952. // Change the current global data pointer.
  953. g_curHmData = pos ;
  954. }
  955. return bResult ;
  956. }