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.

2969 lines
71 KiB

  1. //*********************************************************************************************************************************************
  2. //
  3. // File: collect.cpp
  4. // Author: Donald Drake
  5. // Purpose: Implements classes to support collections
  6. #include "header.h"
  7. #include "string.h"
  8. #ifdef HHCTRL
  9. #include "parserhh.h"
  10. #include "toc.h"
  11. #else
  12. #include "stdio.h"
  13. #include "windows.h"
  14. #include "parser.h"
  15. extern DWORD GetTitleVersion(const CHAR *szFileName);
  16. extern LANGID GetLangId(const CHAR *szFileName);
  17. #endif
  18. #include "collect.h"
  19. // Use CRT version in hhsetup
  20. // Instance count checking:
  21. AUTO_CLASS_COUNT_CHECK(CFolder);
  22. AUTO_CLASS_COUNT_CHECK(CTitle);
  23. #ifndef HHCTRL
  24. #define Atoi atoi
  25. #undef _splitpath
  26. #endif
  27. char gszColReg[MAX_PATH];
  28. WCHAR *CreateUnicodeFromAnsi(LPSTR psz);
  29. class CAnsi {
  30. public:
  31. char *m_pszChar;
  32. CAnsi(WCHAR *);
  33. ~CAnsi();
  34. operator CHAR *() { return (CHAR *) m_pszChar; }
  35. };
  36. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  37. // Helper functions
  38. DWORD AllocSetValue(const CHAR *value, CHAR **dest)
  39. {
  40. if (*dest)
  41. delete [] *dest;
  42. // REVIEW: confirm that len gets optimized out of existence
  43. int len = (int)strlen(value) + 1;
  44. *dest = new CHAR[len];
  45. if (*dest == NULL)
  46. return F_MEMORY;
  47. strcpy(*dest, value);
  48. return F_OK;
  49. }
  50. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  51. // CPointerList implementation
  52. void foo(void)
  53. {
  54. }
  55. void CPointerList::RemoveAll()
  56. {
  57. LISTITEM *p;
  58. while (m_pHead)
  59. {
  60. p = m_pHead->Next;
  61. delete m_pHead;
  62. m_pHead = p;
  63. }
  64. }
  65. CPointerList::~CPointerList()
  66. {
  67. RemoveAll();
  68. }
  69. LISTITEM *CPointerList::Add(void *p)
  70. {
  71. LISTITEM *pItem = new LISTITEM;
  72. if (pItem)
  73. {
  74. pItem->pItem = p;
  75. pItem->Next = m_pHead;
  76. m_pHead = pItem;
  77. return pItem;
  78. }
  79. return NULL;
  80. }
  81. LISTITEM *CPointerList::First()
  82. {
  83. return m_pHead;
  84. }
  85. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  86. // CColList implementation
  87. CColList::CColList()
  88. {
  89. m_dwColNo = 0;
  90. m_szFileName = NULL;
  91. m_pNext = NULL;
  92. }
  93. void CColList::SetFileName(CHAR *sz)
  94. {
  95. if (sz)
  96. AllocSetValue(sz, &m_szFileName);
  97. }
  98. CColList::~CColList()
  99. {
  100. if (m_szFileName)
  101. delete m_szFileName;
  102. }
  103. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  104. // CCollection implementation
  105. CCollection::CCollection()
  106. {
  107. m_bRemoved = FALSE;
  108. m_pwcSampleLocation = NULL;
  109. m_pwcMasterCHM = NULL;
  110. m_bFailNoFile = FALSE;
  111. m_bDirty = FALSE;
  112. m_szSampleLocation = NULL;
  113. m_szFileName = NULL;
  114. m_pwcFileName = NULL;
  115. m_szMasterCHM = NULL;
  116. m_pFirstTitle = NULL;
  117. m_pTitleTail = NULL;
  118. m_pColListHead = NULL;
  119. m_pColListTail = NULL;
  120. m_pLocationTail = NULL;
  121. m_pFirstLocation = NULL;
  122. m_pRootFolder = NULL;
  123. m_locationnum = 0;
  124. m_dwNextColNo = 1;
  125. m_dwColNo = 0;
  126. m_dwTitleRefCount = 0;
  127. m_dwRef = 0;
  128. m_dwVersion = 0;
  129. m_bFindMergedChms = FALSE;
  130. for (int i = 0; i < MAX_LEVELS; i++)
  131. m_pParents[i] = NULL;
  132. m_dwCurLevel = 0;
  133. m_dwLastLevel = 0;
  134. m_bConfirmTitles = FALSE;
  135. m_MasterLangId = ENGLANGID;
  136. gszColReg[0] = NULL;
  137. #ifdef HHSETUP
  138. CoInitialize(NULL);
  139. #endif
  140. }
  141. CCollection::~CCollection()
  142. {
  143. Close();
  144. #ifdef HHSETUP
  145. CoUninitialize();
  146. #endif
  147. }
  148. DWORD CCollection::Release()
  149. {
  150. if (m_dwRef == 0)
  151. return 0;
  152. m_dwRef--;
  153. return m_dwRef;
  154. }
  155. void CCollection::DeleteChildren(CFolder **p)
  156. {
  157. if (!p || !(*p))
  158. return;
  159. CFolder *pChild, *pNext;
  160. if (pChild = (*p)->GetFirstChildFolder())
  161. DeleteChildren(&pChild);
  162. pNext = (*p)->GetNextFolder();
  163. delete (*p);
  164. *p = NULL;
  165. do {
  166. if (pNext)
  167. DeleteChildren(&pNext);
  168. } while (pNext && (pNext = pNext->GetNextFolder()));
  169. }
  170. void CCollection::SetSampleLocation(const CHAR *sz)
  171. {
  172. if (!sz)
  173. return;
  174. Dirty();
  175. AllocSetValue(sz, &m_szSampleLocation);
  176. }
  177. CHAR *CCollection::GetSampleLocation()
  178. {
  179. return m_szSampleLocation;
  180. }
  181. BOOL CCollection::GetMasterCHM(CHAR **szName, LANGID *pLang)
  182. {
  183. *pLang = m_MasterLangId;
  184. *szName = m_szMasterCHM;
  185. if (m_szMasterCHM == NULL)
  186. return FALSE;
  187. return ((strlen(m_szMasterCHM) ? TRUE : FALSE));
  188. }
  189. void CCollection::SetMasterCHM(const CHAR *sz, LANGID lang)
  190. {
  191. if (!sz)
  192. return;
  193. Dirty();
  194. m_MasterLangId = lang;
  195. AllocSetValue(sz, &m_szMasterCHM);
  196. }
  197. // Opens and loads the contents of the file into data structures
  198. DWORD CCollection::Open(const CHAR * FileName)
  199. {
  200. DWORD dw;
  201. BOOL bOld = FALSE;
  202. BOOL bTryAgain = FALSE;
  203. if (m_pRootFolder == NULL)
  204. {
  205. m_pRootFolder = new CFolder;
  206. if (m_pRootFolder == NULL)
  207. return F_MEMORY;
  208. m_pParents[0] = m_pRootFolder;
  209. }
  210. CHAR szBuffer[MAX_PATH];
  211. const CHAR *sz = szBuffer;
  212. BOOL bNewPath;
  213. HHGetGlobalCollectionPathname(szBuffer, sizeof(szBuffer), &bNewPath);
  214. dw = ParseFile(sz);
  215. #ifdef HHCTRL // hhsetup should only be concerned about the good location for this file
  216. if (dw == F_NOFILE && bNewPath)
  217. {
  218. // try windows dir for backward compatibity
  219. try_again:
  220. bNewPath=FALSE;
  221. HHGetOldGlobalCollectionPathname(szBuffer, sizeof(szBuffer));
  222. dw = ParseFile(sz);
  223. bOld = TRUE;
  224. }
  225. #endif
  226. if (dw != F_OK && dw != F_NOFILE)
  227. return dw;
  228. if (dw == F_NOFILE && m_bFailNoFile)
  229. return F_NOFILE;
  230. // save the hhcolreg file and path for save calls...
  231. strcpy(gszColReg, sz);
  232. if (bNewPath && m_dwNextColNo < STARTINGCOLNO)
  233. m_dwNextColNo += STARTINGCOLNO;
  234. if (FileName)
  235. dw = ParseFile(FileName);
  236. if (dw != F_OK && dw != F_NOFILE)
  237. return dw;
  238. if (dw == F_NOFILE && m_bFailNoFile)
  239. return F_NOFILE;
  240. // now that we moved the file, if we did not get any titles found for the collection at runtime
  241. // and we have not looked at the old hhcolreg location let try it.
  242. #ifdef HHCTRL // runtime only, I really hate this
  243. if (m_RefTitles.First() == NULL && bOld == FALSE && bTryAgain == FALSE)
  244. {
  245. Close();
  246. ConfirmTitles();
  247. m_bFailNoFile = TRUE;
  248. bTryAgain = TRUE;
  249. if (m_pRootFolder == NULL)
  250. {
  251. m_pRootFolder = new CFolder;
  252. if (m_pRootFolder == NULL)
  253. return F_MEMORY;
  254. m_pParents[0] = m_pRootFolder;
  255. }
  256. goto try_again;
  257. }
  258. // did we find any titles that matched
  259. if (m_RefTitles.First() == NULL)
  260. {
  261. return F_REFERENCED;
  262. }
  263. #endif
  264. dw = AllocSetValue(FileName, &m_szFileName);
  265. m_bDirty = FALSE;
  266. CColList *pCol;
  267. if ((pCol = FindCollection(m_szFileName)) == NULL)
  268. {
  269. // collection has never been added
  270. pCol = AddCollection();
  271. pCol->SetFileName(m_szFileName);
  272. #ifdef HHCTRL
  273. if (m_dwColNo)
  274. pCol->SetColNo(m_dwColNo);
  275. else
  276. {
  277. pCol->SetColNo(m_dwNextColNo);
  278. m_dwNextColNo++;
  279. if (bNewPath && m_dwNextColNo < STARTINGCOLNO)
  280. m_dwNextColNo += STARTINGCOLNO;
  281. }
  282. #else
  283. pCol->SetColNo(m_dwNextColNo);
  284. m_dwNextColNo++;
  285. if (bNewPath && m_dwNextColNo < STARTINGCOLNO)
  286. m_dwNextColNo += STARTINGCOLNO;
  287. #endif
  288. m_bDirty = TRUE;
  289. }
  290. m_dwColNo = pCol->GetColNo();
  291. return dw;
  292. }
  293. CColList * CCollection::FindCollection(CHAR *szFileName)
  294. {
  295. CColList *p = m_pColListHead;
  296. while (p)
  297. {
  298. if (stricmp(p->GetFileName(), szFileName) == 0)
  299. return p;
  300. p = p->GetNext();
  301. }
  302. return NULL;
  303. }
  304. CColList * CCollection::AddCollection()
  305. {
  306. CColList *newCol = new CColList;
  307. if (!newCol)
  308. {
  309. return NULL;
  310. }
  311. if (m_pColListHead == NULL)
  312. {
  313. m_pColListHead = newCol;
  314. }
  315. else
  316. {
  317. m_pColListTail->SetNext(newCol);
  318. }
  319. m_pColListTail = newCol;
  320. return newCol;
  321. }
  322. void CCollection::RemoveCollectionEntry(CHAR *szFileName)
  323. {
  324. CColList *p = m_pColListHead;
  325. CColList *pPrev = NULL;
  326. while (p)
  327. {
  328. if (stricmp(p->GetFileName(), szFileName) == 0)
  329. {
  330. if (pPrev)
  331. {
  332. pPrev->SetNext(p->GetNext());
  333. }
  334. else
  335. {
  336. m_pColListHead = p->GetNext();
  337. }
  338. if (m_pColListTail == p)
  339. m_pColListTail = pPrev;
  340. delete p;
  341. break;
  342. }
  343. pPrev = p;
  344. p = p->GetNext();
  345. }
  346. }
  347. DWORD CCollection::AllocCopyValue(CParseXML *parser, CHAR *token, CHAR **dest)
  348. {
  349. CHAR *sz;
  350. if (!parser || !token || !dest)
  351. return F_NULL;
  352. sz = parser->GetValue(token);
  353. if (*dest)
  354. delete [] *dest;
  355. int len = (int)strlen(sz) + 1;
  356. *dest = new CHAR[len];
  357. if (*dest == NULL)
  358. return F_MEMORY;
  359. strcpy(*dest, sz);
  360. return F_OK;
  361. }
  362. DWORD CCollection::ParseFile(const CHAR *FileName)
  363. {
  364. CParseXML parser;
  365. CHAR *token;
  366. CHAR *sz;
  367. DWORD dw;
  368. if (!FileName)
  369. return F_NULL;
  370. if ((dw = parser.Start(FileName)) != F_OK)
  371. return dw;
  372. for (token = parser.GetToken(); token;)
  373. {
  374. if (token[0] == '/')
  375. {
  376. dw = m_Strings.GetTail(&sz);
  377. if (dw != F_OK)
  378. {
  379. parser.End();
  380. return dw;
  381. }
  382. if (strcmp(sz, &token[1]) != 0)
  383. {
  384. parser.End();
  385. delete sz;
  386. return F_TAGMISSMATCH;
  387. }
  388. delete sz;
  389. if (strcmp(token, "/Folder") == 0)
  390. m_dwCurLevel--;
  391. token = parser.GetToken();
  392. continue;
  393. }
  394. else if (stricmp(parser.GetFirstWord(token), "XML") == 0)
  395. {
  396. dw = m_Strings.AddTail(parser.GetFirstWord(token));
  397. if (dw != F_OK)
  398. {
  399. parser.End();
  400. return dw;
  401. }
  402. token = parser.GetToken();
  403. continue;
  404. }
  405. else if (stricmp(parser.GetFirstWord(token), "Collections") == 0)
  406. {
  407. dw = m_Strings.AddTail(parser.GetFirstWord(token));
  408. if (dw != F_OK)
  409. {
  410. parser.End();
  411. return dw;
  412. }
  413. token = parser.GetToken();
  414. continue;
  415. }
  416. else if (stricmp(parser.GetFirstWord(token), "Collection") == 0)
  417. {
  418. dw = m_Strings.AddTail(parser.GetFirstWord(token));
  419. if (dw != F_OK)
  420. {
  421. parser.End();
  422. return dw;
  423. }
  424. if ((dw = HandleCollectionEntry(&parser, token)) != F_OK)
  425. {
  426. parser.End();
  427. return dw;
  428. }
  429. continue;
  430. }
  431. else if (stricmp(parser.GetFirstWord(token), "HTMLHelpCollection") == 0)
  432. {
  433. dw = m_Strings.AddTail(parser.GetFirstWord(token));
  434. if (dw != F_OK)
  435. {
  436. parser.End();
  437. return dw;
  438. }
  439. if ((dw = HandleCollection(&parser, token)) != F_OK)
  440. {
  441. parser.End();
  442. return dw;
  443. }
  444. continue;
  445. }
  446. else if (stricmp(parser.GetFirstWord(token), "NextCollectionId") == 0)
  447. {
  448. m_dwNextColNo = atoi(parser.GetValue(token));
  449. token = parser.GetToken();
  450. continue;
  451. }
  452. else if (stricmp(parser.GetFirstWord(token), "Folders") == 0)
  453. {
  454. dw = m_Strings.AddTail(parser.GetFirstWord(token));
  455. if (dw != F_OK)
  456. {
  457. parser.End();
  458. return dw;
  459. }
  460. token = parser.GetToken();
  461. continue;
  462. }
  463. else if (stricmp(parser.GetFirstWord(token), "Folder") == 0)
  464. {
  465. dw = m_Strings.AddTail(parser.GetFirstWord(token));
  466. if (dw != F_OK)
  467. {
  468. parser.End();
  469. return dw;
  470. }
  471. if ((dw = HandleFolder(&parser, token)) != F_OK)
  472. {
  473. parser.End();
  474. return dw;
  475. }
  476. continue;
  477. }
  478. else if (stricmp(parser.GetFirstWord(token), "HTMLHelpDocInfo") == 0)
  479. {
  480. dw = m_Strings.AddTail(parser.GetFirstWord(token));
  481. if (dw != F_OK)
  482. {
  483. parser.End();
  484. return dw;
  485. }
  486. token = parser.GetToken();
  487. continue;
  488. }
  489. else if (stricmp(parser.GetFirstWord(token), "Locations") == 0)
  490. {
  491. dw = m_Strings.AddTail(parser.GetFirstWord(token));
  492. if (dw != F_OK)
  493. {
  494. parser.End();
  495. return dw;
  496. }
  497. token = parser.GetToken();
  498. continue;
  499. }
  500. else if (stricmp(parser.GetFirstWord(token), "Location") == 0)
  501. {
  502. dw = m_Strings.AddTail(parser.GetFirstWord(token));
  503. if (dw != F_OK)
  504. {
  505. parser.End();
  506. return dw;
  507. }
  508. if ((dw = HandleLocation(&parser, token)) != F_OK)
  509. {
  510. parser.End();
  511. return dw;
  512. }
  513. continue;
  514. }
  515. else if (strcmp(parser.GetFirstWord(token), "DocCompilations") == 0)
  516. {
  517. dw = m_Strings.AddTail(parser.GetFirstWord(token));
  518. if (dw != F_OK)
  519. {
  520. parser.End();
  521. return dw;
  522. }
  523. token = parser.GetToken();
  524. continue;
  525. }
  526. else if (strcmp(parser.GetFirstWord(token), "DocCompilation") == 0)
  527. {
  528. dw = m_Strings.AddTail(parser.GetFirstWord(token));
  529. if (dw != F_OK)
  530. {
  531. parser.End();
  532. return dw;
  533. }
  534. if ((dw = HandleTitle(&parser, token)) != F_OK)
  535. {
  536. parser.End();
  537. return dw;
  538. }
  539. continue;
  540. }
  541. else
  542. {
  543. dw = m_Strings.AddTail(parser.GetFirstWord(token));
  544. if (dw != F_OK)
  545. {
  546. parser.End();
  547. return dw;
  548. }
  549. token = parser.GetToken();
  550. }
  551. }
  552. // make sure all tags have been popped
  553. dw = F_OK;
  554. while (m_Strings.GetTail(&sz) == F_OK)
  555. {
  556. delete sz;
  557. dw = F_MISSINGENDTAG;
  558. }
  559. parser.End();
  560. return dw;
  561. }
  562. DWORD CCollection::HandleCollectionEntry(CParseXML *parser, CHAR *token)
  563. {
  564. if (!parser || !token)
  565. return F_NULL;
  566. CColList *newCol = AddCollection();
  567. if (!newCol)
  568. {
  569. return F_MEMORY;
  570. }
  571. while (TRUE)
  572. {
  573. token = parser->GetToken();
  574. if (stricmp(parser->GetFirstWord(token), "colname") == 0)
  575. {
  576. newCol->SetFileName(parser->GetValue(token));
  577. }
  578. else if (stricmp(parser->GetFirstWord(token), "colnum") == 0)
  579. {
  580. newCol->SetColNo( atoi(parser->GetValue(token)));
  581. }
  582. else
  583. break;
  584. }
  585. return F_OK;
  586. }
  587. DWORD CCollection::HandleCollection(CParseXML *parser, CHAR *token)
  588. {
  589. if (!parser || !token)
  590. return F_NULL;
  591. while (TRUE)
  592. {
  593. token = parser->GetToken();
  594. if (stricmp(parser->GetFirstWord(token), "homepage") == 0)
  595. {
  596. // need to be backward compatable with this tag
  597. }
  598. else if (stricmp(parser->GetFirstWord(token), "masterchm") == 0)
  599. {
  600. SetMasterCHM( parser->GetValue(token), ENGLANGID);
  601. }
  602. else if (stricmp(parser->GetFirstWord(token), "samplelocation") == 0)
  603. {
  604. SetSampleLocation( parser->GetValue(token));
  605. }
  606. else if (stricmp(parser->GetFirstWord(token), "masterlangid") == 0)
  607. {
  608. m_MasterLangId = (LANGID)atoi(parser->GetValue(token));
  609. }
  610. else if (stricmp(parser->GetFirstWord(token), "refcount") == 0)
  611. {
  612. m_dwRef = atoi(parser->GetValue(token));
  613. }
  614. else if (stricmp(parser->GetFirstWord(token), "version") == 0)
  615. {
  616. m_dwVersion = atoi(parser->GetValue(token));
  617. }
  618. else if (stricmp(parser->GetFirstWord(token), "showhomepage") == 0)
  619. {
  620. // need to be backward compatable with this tag
  621. }
  622. else if (stricmp(parser->GetFirstWord(token), "findmergedchms") == 0)
  623. {
  624. m_bFindMergedChms = atoi(parser->GetValue(token));
  625. }
  626. else if (stricmp(parser->GetFirstWord(token), "CollectionNum") == 0)
  627. {
  628. m_dwColNo = atoi(parser->GetValue(token));
  629. }
  630. else
  631. break;
  632. }
  633. return F_OK;
  634. }
  635. DWORD CCollection::HandleFolder(CParseXML *parser, CHAR *token)
  636. {
  637. if (!parser || !token)
  638. return F_NULL;
  639. CFolder *newFolder = new CFolder;
  640. if (newFolder == NULL)
  641. return F_MEMORY;
  642. m_dwCurLevel++;
  643. while (TRUE)
  644. {
  645. token = parser->GetToken();
  646. if (stricmp(parser->GetFirstWord(token), "TitleString") == 0)
  647. {
  648. newFolder->SetTitle(parser->GetValue(token));
  649. }
  650. else if (stricmp(parser->GetFirstWord(token), "FolderOrder") == 0)
  651. {
  652. newFolder->SetOrder(atoi(parser->GetValue(token)));
  653. }
  654. else if (stricmp(parser->GetFirstWord(token), "LangId") == 0)
  655. {
  656. newFolder->SetLanguage((LANGID)atoi(parser->GetValue(token)));
  657. }
  658. else
  659. break;
  660. }
  661. CHAR *pTitle;
  662. pTitle = newFolder->GetTitle();
  663. if (pTitle && pTitle[0] == '=')
  664. {
  665. if (CheckTitleRef(pTitle, newFolder->GetLanguage()) != F_OK)
  666. {
  667. delete newFolder;
  668. return F_OK;
  669. }
  670. AddRefedTitle(newFolder);
  671. }
  672. m_pParents[m_dwCurLevel - 1]->AddChildFolder(newFolder);
  673. m_pParents[m_dwCurLevel] = newFolder;
  674. return F_OK;
  675. }
  676. DWORD CCollection::AddRefedTitle(CFolder *pFolder)
  677. {
  678. m_dwTitleRefCount++;
  679. m_RefTitles.Add(pFolder);
  680. return F_OK;
  681. }
  682. DWORD CCollection::HandleLocation(CParseXML *parser, CHAR *token)
  683. {
  684. if (!parser || !token)
  685. return F_NULL;
  686. CLocation *newLocation = NewLocation();
  687. if (newLocation == NULL)
  688. return F_MEMORY;
  689. newLocation->m_ColNum = 0;
  690. while (TRUE)
  691. {
  692. token = parser->GetToken();
  693. if (stricmp(parser->GetFirstWord(token), "LocName") == 0)
  694. {
  695. newLocation->SetId(parser->GetValue(token));
  696. }
  697. else if (stricmp(parser->GetFirstWord(token), "TitleString") == 0)
  698. {
  699. newLocation->SetTitle(parser->GetValue(token));
  700. }
  701. else if (stricmp(parser->GetFirstWord(token), "LocPath") == 0)
  702. {
  703. newLocation->SetPath(parser->GetValue(token));
  704. }
  705. else if (stricmp(parser->GetFirstWord(token), "Volume") == 0)
  706. {
  707. newLocation->SetVolume(parser->GetValue(token));
  708. }
  709. else if (stricmp(parser->GetFirstWord(token), "LocColNum") == 0)
  710. {
  711. newLocation->m_ColNum = atoi(parser->GetValue(token));
  712. }
  713. else
  714. break;
  715. }
  716. return F_OK;
  717. }
  718. DWORD CCollection::HandleTitle(CParseXML *parser, CHAR *token)
  719. {
  720. if (!parser || !token)
  721. return F_NULL;
  722. LOCATIONHISTORY *pNew;
  723. CTitle *newTitle = NewTitle();
  724. DWORD dw;
  725. CHAR *pSampleLocation = NULL;
  726. BOOL bMerge = FALSE;
  727. if (newTitle == NULL)
  728. return F_MEMORY;
  729. while (TRUE)
  730. {
  731. token = parser->GetToken();
  732. if (stricmp(parser->GetFirstWord(token), "DocCompId") == 0)
  733. {
  734. newTitle->SetId(parser->GetValue(token));
  735. }
  736. else if (stricmp(parser->GetFirstWord(token), "TitleString") == 0)
  737. {
  738. // no longer do anything with titlestring but need to support for backward compatiblity
  739. continue;
  740. }
  741. else if (stricmp(parser->GetFirstWord(token), "TitleSampleLocation") == 0)
  742. {
  743. if (newTitle->m_pTail == NULL)
  744. {
  745. // old style global.col, save this for the locations to follow
  746. AllocCopyValue(parser, token, &pSampleLocation);
  747. }
  748. else
  749. if ((dw = AllocCopyValue(parser, token, &(newTitle->m_pTail->SampleLocation))) != F_OK)
  750. return dw;
  751. }
  752. else if (stricmp(parser->GetFirstWord(token), "DocCompLanguage") == 0)
  753. {
  754. newTitle->SetLanguage((LANGID)atoi(parser->GetValue(token)));
  755. }
  756. else if (stricmp(parser->GetFirstWord(token), "SupportsMerge") == 0)
  757. {
  758. if (newTitle->m_pTail == NULL)
  759. {
  760. // old style global.col, save this for the locations to follow
  761. bMerge = (BOOL)atoi(parser->GetValue(token));
  762. }
  763. else
  764. newTitle->m_pTail->bSupportsMerge = (BOOL)atoi(parser->GetValue(token));
  765. }
  766. else if (stricmp(parser->GetFirstWord(token), "LocationHistory") == 0)
  767. {
  768. pNew = newTitle->NewLocationHistory();
  769. if (pNew == NULL)
  770. return F_MEMORY;
  771. if (pSampleLocation)
  772. if ((dw = AllocSetValue(pSampleLocation, &(newTitle->m_pTail->SampleLocation))) != F_OK)
  773. return dw;
  774. newTitle->m_pTail->bSupportsMerge = bMerge;
  775. dw = m_Strings.AddTail(parser->GetFirstWord(token));
  776. if (dw != F_OK)
  777. {
  778. return dw;
  779. }
  780. }
  781. else if (stricmp(parser->GetFirstWord(token), "/LocationHistory") == 0)
  782. {
  783. CHAR *sz;
  784. dw = m_Strings.GetTail(&sz);
  785. if (dw != F_OK)
  786. {
  787. return dw;
  788. }
  789. if (strcmp(sz, &token[1]) != 0)
  790. {
  791. delete sz;
  792. return F_TAGMISSMATCH;
  793. }
  794. delete sz;
  795. }
  796. else if (stricmp(parser->GetFirstWord(token), "TitleLocation") == 0)
  797. {
  798. if ((dw = AllocCopyValue(parser, token, &(newTitle->m_pTail->FileName))) != F_OK)
  799. return dw;
  800. }
  801. else if (stricmp(parser->GetFirstWord(token), "QueryLocation") == 0)
  802. {
  803. if ((dw = AllocCopyValue(parser, token, &(newTitle->m_pTail->QueryFileName))) != F_OK)
  804. return dw;
  805. }
  806. else if (stricmp(parser->GetFirstWord(token), "TitleQueryLocation") == 0)
  807. {
  808. if ((dw = AllocCopyValue(parser, token, &(newTitle->m_pTail->QueryLocation))) != F_OK)
  809. return dw;
  810. }
  811. else if (stricmp(parser->GetFirstWord(token), "IndexLocation") == 0)
  812. {
  813. if ((dw = AllocCopyValue(parser, token, &(newTitle->m_pTail->IndexFileName))) != F_OK)
  814. return dw;
  815. }
  816. else if (stricmp(parser->GetFirstWord(token), "LocationRef") == 0)
  817. {
  818. if ((dw = AllocCopyValue(parser, token, &(newTitle->m_pTail->LocationId))) != F_OK)
  819. return dw;
  820. }
  821. else if (stricmp(parser->GetFirstWord(token), "Version") == 0)
  822. {
  823. newTitle->m_pTail->Version = atoi(parser->GetValue(token));
  824. }
  825. else if (stricmp(parser->GetFirstWord(token), "LastPromptedVersion") == 0)
  826. {
  827. newTitle->m_pTail->LastPromptedVersion = atoi(parser->GetValue(token));
  828. }
  829. else if (stricmp(parser->GetFirstWord(token), "ColNum") == 0)
  830. {
  831. newTitle->m_pTail->CollectionNumber = atoi(parser->GetValue(token));
  832. }
  833. else
  834. break;
  835. }
  836. if (pSampleLocation)
  837. delete pSampleLocation;
  838. return F_OK;
  839. }
  840. // Saves any changes made to the internal data structures to the file.
  841. DWORD CCollection::Save()
  842. {
  843. CHAR szBuffer[MAX_LINE_LEN];
  844. DWORD dwWritten;
  845. #ifdef HHSETUP // only hhsetup needs to rewrite the users .col file
  846. // don't want the control to add any new tags to old
  847. // collections, which would break uninstall and update
  848. // if no root folders delete the collection file
  849. if (m_bRemoved == TRUE)
  850. {
  851. DeleteFile(m_szFileName);
  852. m_bRemoved = FALSE;
  853. }
  854. else
  855. {
  856. if ((m_fh = CreateFile(m_szFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL )) == INVALID_HANDLE_VALUE) {
  857. return F_NOFILE;
  858. }
  859. strcpy(szBuffer, "<XML>\r\n");
  860. if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  861. {
  862. CloseHandle(m_fh);
  863. return F_WRITE;
  864. }
  865. // write out collection information
  866. strcpy(szBuffer, "<HTMLHelpCollection>\r\n");
  867. if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  868. {
  869. CloseHandle(m_fh);
  870. return F_WRITE;
  871. }
  872. wsprintf(szBuffer, "<masterchm value=\"%s\"/>\r\n", (m_szMasterCHM ? m_szMasterCHM : ""));
  873. if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  874. {
  875. CloseHandle(m_fh);
  876. return F_WRITE;
  877. }
  878. wsprintf(szBuffer, "<masterlangid value=%d/>\r\n", m_MasterLangId);
  879. if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  880. {
  881. CloseHandle(m_fh);
  882. return F_WRITE;
  883. }
  884. wsprintf(szBuffer, "<samplelocation value=\"%s\"/>\r\n", (m_szSampleLocation ? m_szSampleLocation : ""));
  885. if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  886. {
  887. CloseHandle(m_fh);
  888. return F_WRITE;
  889. }
  890. wsprintf(szBuffer, "<collectionnum value=%d/>\r\n", m_dwColNo);
  891. if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  892. {
  893. CloseHandle(m_fh);
  894. return F_WRITE;
  895. }
  896. wsprintf(szBuffer, "<refcount value=%d/>\r\n", m_dwRef);
  897. if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  898. {
  899. CloseHandle(m_fh);
  900. return F_WRITE;
  901. }
  902. wsprintf(szBuffer, "<version value=%d/>\r\n", m_dwVersion);
  903. if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  904. {
  905. CloseHandle(m_fh);
  906. return F_WRITE;
  907. }
  908. wsprintf(szBuffer, "<findmergedchms value=%d/>\r\n", m_bFindMergedChms);
  909. if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  910. {
  911. CloseHandle(m_fh);
  912. return F_WRITE;
  913. }
  914. // write out folders
  915. strcpy(szBuffer,"<Folders>\r\n");
  916. if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  917. {
  918. CloseHandle(m_fh);
  919. return F_WRITE;
  920. }
  921. m_dwCurLevel = 0;
  922. if (WriteFolders(&m_pRootFolder) == FALSE)
  923. {
  924. CloseHandle(m_fh);
  925. return F_WRITE;
  926. }
  927. // close tags
  928. strcpy(szBuffer, "</Folders>\r\n");
  929. if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  930. {
  931. CloseHandle(m_fh);
  932. return F_WRITE;
  933. }
  934. strcpy(szBuffer, "</HTMLHelpCollection>\r\n");
  935. if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  936. {
  937. CloseHandle(m_fh);
  938. return F_WRITE;
  939. }
  940. strcpy(szBuffer, "</XML>\r\n");
  941. if (WriteFile(m_fh, szBuffer, (ULONG)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  942. {
  943. CloseHandle(m_fh);
  944. return F_WRITE;
  945. }
  946. CloseHandle(m_fh);
  947. }
  948. #endif
  949. // save the global titles and locations
  950. // open collection file
  951. if ((m_fh = CreateFile(gszColReg, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL )) == INVALID_HANDLE_VALUE) {
  952. return F_NOFILE;
  953. }
  954. // write out XML tag
  955. strcpy(szBuffer, "<XML>\r\n");
  956. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  957. {
  958. CloseHandle(m_fh);
  959. return F_WRITE;
  960. }
  961. strcpy(szBuffer, "<HTMLHelpDocInfo>\r\n");
  962. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  963. {
  964. CloseHandle(m_fh);
  965. return F_WRITE;
  966. }
  967. wsprintf(szBuffer, "<NextCollectionId value=%d/>\r\n", m_dwNextColNo);
  968. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  969. {
  970. CloseHandle(m_fh);
  971. return F_WRITE;
  972. }
  973. // write out the collection list
  974. strcpy(szBuffer, "<Collections>\r\n");
  975. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  976. {
  977. CloseHandle(m_fh);
  978. return F_WRITE;
  979. }
  980. CColList *pCol = m_pColListHead;
  981. while (pCol)
  982. {
  983. strcpy(szBuffer, "<Collection>\r\n");
  984. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  985. {
  986. CloseHandle(m_fh);
  987. return F_WRITE;
  988. }
  989. wsprintf(szBuffer, "\t<ColNum value=%d/>\r\n", pCol->GetColNo());
  990. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  991. {
  992. CloseHandle(m_fh);
  993. return F_WRITE;
  994. }
  995. wsprintf(szBuffer, "\t<ColName value=\"%s\"/>\r\n", (pCol->GetFileName() ? pCol->GetFileName() : ""));
  996. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  997. {
  998. CloseHandle(m_fh);
  999. return F_WRITE;
  1000. }
  1001. strcpy(szBuffer, "</Collection>\r\n");
  1002. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1003. {
  1004. CloseHandle(m_fh);
  1005. return F_WRITE;
  1006. }
  1007. pCol = pCol->GetNext();
  1008. }
  1009. strcpy(szBuffer, "</Collections>\r\n");
  1010. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1011. {
  1012. CloseHandle(m_fh);
  1013. return F_WRITE;
  1014. }
  1015. // write out the locations
  1016. strcpy(szBuffer, "<Locations>\r\n");
  1017. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1018. {
  1019. CloseHandle(m_fh);
  1020. return F_WRITE;
  1021. }
  1022. CLocation *p = FirstLocation();
  1023. while (p)
  1024. {
  1025. strcpy(szBuffer, "<Location>\r\n");
  1026. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1027. {
  1028. CloseHandle(m_fh);
  1029. return F_WRITE;
  1030. }
  1031. wsprintf(szBuffer, "\t<LocColNum value=%d/>\r\n", p->m_ColNum);
  1032. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1033. {
  1034. CloseHandle(m_fh);
  1035. return F_WRITE;
  1036. }
  1037. wsprintf(szBuffer, "\t<LocName value=\"%s\"/>\r\n", (p->GetId() ? p->GetId() : ""));
  1038. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1039. {
  1040. CloseHandle(m_fh);
  1041. return F_WRITE;
  1042. }
  1043. wsprintf(szBuffer, "\t<TitleString value=\"%s\"/>\r\n", (p->GetTitle() ? p->GetTitle() : ""));
  1044. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1045. {
  1046. CloseHandle(m_fh);
  1047. return F_WRITE;
  1048. }
  1049. wsprintf(szBuffer, "\t<LocPath value=\"%s\"/>\r\n", (p->GetPath() ? p->GetPath() : ""));
  1050. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1051. {
  1052. CloseHandle(m_fh);
  1053. return F_WRITE;
  1054. }
  1055. wsprintf(szBuffer, "\t<Volume value=\"%s\"/>\r\n", (p->GetVolume() ? p->GetVolume() : ""));
  1056. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1057. {
  1058. CloseHandle(m_fh);
  1059. return F_WRITE;
  1060. }
  1061. strcpy(szBuffer, "</Location>\r\n");
  1062. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1063. {
  1064. CloseHandle(m_fh);
  1065. return F_WRITE;
  1066. }
  1067. p = p->GetNextLocation();
  1068. }
  1069. strcpy(szBuffer, "</Locations>\r\n");
  1070. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1071. {
  1072. CloseHandle(m_fh);
  1073. return F_WRITE;
  1074. }
  1075. // write out the titles
  1076. strcpy(szBuffer, "<DocCompilations>\r\n");
  1077. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1078. {
  1079. CloseHandle(m_fh);
  1080. return F_WRITE;
  1081. }
  1082. CTitle *pTitle = GetFirstTitle();
  1083. LOCATIONHISTORY *pHist;
  1084. while (pTitle)
  1085. {
  1086. strcpy(szBuffer, "<DocCompilation>\r\n");
  1087. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1088. {
  1089. CloseHandle(m_fh);
  1090. return F_WRITE;
  1091. }
  1092. wsprintf(szBuffer, "\t<DocCompId value=\"%s\"/>\r\n", (pTitle->GetId() ? pTitle->GetId() : ""));
  1093. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1094. {
  1095. CloseHandle(m_fh);
  1096. return F_WRITE;
  1097. }
  1098. wsprintf(szBuffer, "\t<DocCompLanguage value=%d/>\r\n", pTitle->GetLanguage());
  1099. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1100. {
  1101. CloseHandle(m_fh);
  1102. return F_WRITE;
  1103. }
  1104. pHist = pTitle->m_pHead;
  1105. while (pHist)
  1106. {
  1107. strcpy(szBuffer, "\t<LocationHistory>\r\n");
  1108. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1109. {
  1110. CloseHandle(m_fh);
  1111. return F_WRITE;
  1112. }
  1113. wsprintf(szBuffer, "\t\t<ColNum value=%d/>\r\n", pHist->CollectionNumber);
  1114. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1115. {
  1116. CloseHandle(m_fh);
  1117. return F_WRITE;
  1118. }
  1119. wsprintf(szBuffer, "\t\t<TitleLocation value=\"%s\"/>\r\n", (pHist->FileName ? pHist->FileName : ""));
  1120. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1121. {
  1122. CloseHandle(m_fh);
  1123. return F_WRITE;
  1124. }
  1125. wsprintf(szBuffer, "\t\t<IndexLocation value=\"%s\"/>\r\n", (pHist->IndexFileName ? pHist->IndexFileName : ""));
  1126. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1127. {
  1128. CloseHandle(m_fh);
  1129. return F_WRITE;
  1130. }
  1131. wsprintf(szBuffer, "\t\t<QueryLocation value=\"%s\"/>\r\n", (pHist->QueryFileName ? pHist->QueryFileName : ""));
  1132. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1133. {
  1134. CloseHandle(m_fh);
  1135. return F_WRITE;
  1136. }
  1137. wsprintf(szBuffer, "\t\t<LocationRef value=\"%s\"/>\r\n", (pHist->LocationId ? pHist->LocationId : ""));
  1138. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1139. {
  1140. CloseHandle(m_fh);
  1141. return F_WRITE;
  1142. }
  1143. wsprintf(szBuffer, "\t\t<Version value=%ld/>\r\n", pHist->Version);
  1144. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1145. {
  1146. CloseHandle(m_fh);
  1147. return F_WRITE;
  1148. }
  1149. wsprintf(szBuffer, "\t\t<LastPromptedVersion value=%ld/>\r\n", pHist->LastPromptedVersion);
  1150. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1151. {
  1152. CloseHandle(m_fh);
  1153. return F_WRITE;
  1154. }
  1155. wsprintf(szBuffer, "\t\t<TitleSampleLocation value=\"%s\"/>\r\n", (pHist->SampleLocation ? pHist->SampleLocation : ""));
  1156. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1157. {
  1158. CloseHandle(m_fh);
  1159. return F_WRITE;
  1160. }
  1161. wsprintf(szBuffer, "\t\t<TitleQueryLocation value=\"%s\"/>\r\n", (pHist->QueryLocation ? pHist->QueryLocation : ""));
  1162. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1163. {
  1164. CloseHandle(m_fh);
  1165. return F_WRITE;
  1166. }
  1167. wsprintf(szBuffer, "\t\t<SupportsMerge value=%d/>\r\n", pHist->bSupportsMerge);
  1168. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1169. {
  1170. CloseHandle(m_fh);
  1171. return F_WRITE;
  1172. }
  1173. strcpy(szBuffer, "\t</LocationHistory>\r\n");
  1174. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1175. {
  1176. CloseHandle(m_fh);
  1177. return F_WRITE;
  1178. }
  1179. pHist = pHist->pNext;
  1180. }
  1181. strcpy(szBuffer, "</DocCompilation>\r\n");
  1182. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1183. {
  1184. CloseHandle(m_fh);
  1185. return F_WRITE;
  1186. }
  1187. pTitle = pTitle->GetNextTitle();
  1188. }
  1189. strcpy(szBuffer, "</DocCompilations>\r\n");
  1190. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1191. {
  1192. CloseHandle(m_fh);
  1193. return F_WRITE;
  1194. }
  1195. strcpy(szBuffer, "</HTMLHelpDocInfo>\r\n");
  1196. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1197. {
  1198. CloseHandle(m_fh);
  1199. return F_WRITE;
  1200. }
  1201. strcpy(szBuffer,"</XML>\r\n");
  1202. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1203. {
  1204. CloseHandle(m_fh);
  1205. return F_WRITE;
  1206. }
  1207. if (CloseHandle(m_fh) == FALSE)
  1208. return F_CLOSE;
  1209. // make sure we can open this file for read
  1210. if ((m_fh = CreateFile(gszColReg, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL, NULL )) == INVALID_HANDLE_VALUE) {
  1211. return F_EXISTCHECK;
  1212. }
  1213. if (CloseHandle(m_fh) == FALSE)
  1214. return F_CLOSE;
  1215. return F_OK;
  1216. }
  1217. BOOL CCollection::WriteFolders(CFolder **p)
  1218. {
  1219. BOOL b = TRUE;
  1220. if (!p || !(*p))
  1221. return FALSE;
  1222. CFolder *pChild;
  1223. pChild = (*p)->GetFirstChildFolder();
  1224. if (pChild)
  1225. b = WriteFolder(&pChild);
  1226. delete *p;
  1227. *p = NULL;
  1228. return b;
  1229. }
  1230. BOOL CCollection::WriteFolder(CFolder **p)
  1231. {
  1232. if (!p || !(*p))
  1233. return FALSE;
  1234. CHAR szBuffer[MAX_LINE_LEN];
  1235. DWORD dwWritten;
  1236. CFolder *pChild, *pNext;
  1237. DWORD i;
  1238. // write this folder
  1239. // tab over the indent level
  1240. strcpy(szBuffer, "\t");
  1241. for (i = 0; i < m_dwCurLevel; i++)
  1242. {
  1243. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1244. {
  1245. return FALSE;
  1246. }
  1247. }
  1248. strcpy(szBuffer, "<Folder>\r\n");
  1249. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1250. {
  1251. return FALSE;
  1252. }
  1253. strcpy(szBuffer, "\t");
  1254. for (i = 0; i < m_dwCurLevel+1; i++)
  1255. {
  1256. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1257. {
  1258. return FALSE;
  1259. }
  1260. }
  1261. wsprintf(szBuffer, "<TitleString value=\"%s\"/>\r\n", (*p)->GetTitle());
  1262. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1263. {
  1264. return FALSE;
  1265. }
  1266. strcpy(szBuffer, "\t");
  1267. for (i = 0; i < m_dwCurLevel+1; i++)
  1268. {
  1269. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1270. {
  1271. return FALSE;
  1272. }
  1273. }
  1274. wsprintf(szBuffer, "<FolderOrder value=%d/>\r\n", (*p)->GetOrder());
  1275. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1276. {
  1277. return FALSE;
  1278. }
  1279. CHAR *pTitle = (*p)->GetTitle();
  1280. if (pTitle[0] == '=')
  1281. {
  1282. strcpy(szBuffer, "\t");
  1283. for (i = 0; i < m_dwCurLevel+1; i++)
  1284. {
  1285. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1286. {
  1287. return FALSE;
  1288. }
  1289. }
  1290. wsprintf(szBuffer, "<LangId value=%d/>\r\n", (*p)->GetLanguage());
  1291. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1292. {
  1293. return FALSE;
  1294. }
  1295. }
  1296. m_dwCurLevel++;
  1297. if (pChild = (*p)->GetFirstChildFolder())
  1298. {
  1299. if (WriteFolder(&pChild) == FALSE)
  1300. return FALSE;
  1301. }
  1302. if (m_dwCurLevel)
  1303. m_dwCurLevel--;
  1304. strcpy(szBuffer, "\t");
  1305. for (i = 0; i < m_dwCurLevel; i++)
  1306. {
  1307. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1308. {
  1309. return FALSE;
  1310. }
  1311. }
  1312. strcpy(szBuffer, "</Folder>\r\n");
  1313. if (WriteFile(m_fh, szBuffer, (int)strlen(szBuffer), &dwWritten, NULL) == FALSE)
  1314. {
  1315. return FALSE;
  1316. }
  1317. pNext = (*p)->GetNextFolder();
  1318. delete (*p);
  1319. *p = NULL;
  1320. do {
  1321. if (pNext)
  1322. {
  1323. if (WriteFolder(&pNext) == FALSE)
  1324. return FALSE;
  1325. }
  1326. } while (pNext && (pNext = pNext->GetNextFolder()));
  1327. return TRUE;
  1328. }
  1329. DWORD CCollection::Close()
  1330. {
  1331. m_locationnum = 0;
  1332. gszColReg[0] = NULL;
  1333. m_dwNextColNo = 1;
  1334. m_dwColNo = 0;
  1335. m_dwTitleRefCount = 0;
  1336. m_dwRef = 0;
  1337. m_dwVersion = 0;
  1338. for (int i = 0; i < MAX_LEVELS; i++)
  1339. m_pParents[i] = NULL;
  1340. m_dwCurLevel = 0;
  1341. m_dwLastLevel = 0;
  1342. m_bConfirmTitles = FALSE;
  1343. m_MasterLangId = ENGLANGID;
  1344. m_bFindMergedChms = FALSE;
  1345. m_Strings.RemoveAll();
  1346. if (m_szFileName)
  1347. {
  1348. delete m_szFileName;
  1349. m_szFileName = NULL;
  1350. }
  1351. if (m_pwcFileName)
  1352. {
  1353. delete m_pwcFileName;
  1354. m_pwcFileName = NULL;
  1355. }
  1356. if (m_szMasterCHM)
  1357. {
  1358. delete m_szMasterCHM;
  1359. m_szMasterCHM = NULL;
  1360. }
  1361. if (m_pwcMasterCHM)
  1362. {
  1363. delete m_pwcMasterCHM;
  1364. m_pwcMasterCHM = NULL;
  1365. }
  1366. if (m_szSampleLocation)
  1367. {
  1368. delete m_szSampleLocation;
  1369. m_szSampleLocation = NULL;
  1370. }
  1371. // clean up col list
  1372. CColList *pCol, *pColNext;
  1373. for (pCol = m_pColListHead; pCol; pCol = pColNext)
  1374. {
  1375. pColNext = pCol->GetNext();
  1376. delete pCol;
  1377. }
  1378. m_pColListHead = NULL;
  1379. m_pColListTail = NULL;
  1380. // clean up locations
  1381. CLocation *p, *pNext;
  1382. for (p = m_pFirstLocation; p; p=pNext)
  1383. {
  1384. pNext = p->GetNextLocation();
  1385. delete p;
  1386. }
  1387. m_pFirstLocation=NULL;
  1388. m_pLocationTail = NULL;
  1389. // clean up titles
  1390. CTitle *pTitle, *pNextTitle;
  1391. for (pTitle = m_pFirstTitle; pTitle; pTitle=pNextTitle)
  1392. {
  1393. pNextTitle = pTitle->GetNextTitle();
  1394. delete pTitle;
  1395. }
  1396. m_pFirstTitle = NULL;
  1397. m_pTitleTail = NULL;
  1398. // clean up folder
  1399. if (m_pRootFolder)
  1400. {
  1401. DeleteChildren(&m_pRootFolder);
  1402. }
  1403. m_pRootFolder = NULL;
  1404. return F_OK;
  1405. }
  1406. // Returns the first title
  1407. CTitle * CCollection::GetFirstTitle()
  1408. {
  1409. return m_pFirstTitle;
  1410. }
  1411. // Locates a title based on id
  1412. CTitle * CCollection::FindTitle(const CHAR * Id, LANGID LangId)
  1413. {
  1414. if (!Id)
  1415. return NULL;
  1416. CTitle *p;
  1417. p = m_pFirstTitle;
  1418. while (p)
  1419. {
  1420. if (stricmp(p->GetId(), Id) == 0 &&
  1421. (LangId == 0 || p->GetLanguage() == LangId)) // Ignore LangId if its zero.
  1422. {
  1423. return p;
  1424. }
  1425. p = p->GetNextTitle();
  1426. }
  1427. return NULL;
  1428. }
  1429. #ifdef HHCTRL
  1430. // Try multiple LangIds before failing
  1431. CTitle * CCollection::FindTitleNonExact(const CHAR * Id, LANGID DesiredLangId)
  1432. {
  1433. CTitle* pTitle = NULL ;
  1434. CLanguageEnum* pEnum = _Module.m_Language.GetEnumerator(DesiredLangId) ;
  1435. ASSERT(pEnum) ;
  1436. LANGID langid = pEnum->start() ;
  1437. while (langid != c_LANGID_ENUM_EOF)
  1438. {
  1439. pTitle = FindTitle(Id, langid);
  1440. if (pTitle)
  1441. {
  1442. break ; //Found It!
  1443. }
  1444. langid = pEnum->next() ;
  1445. }
  1446. // Cleanup.
  1447. if (pEnum)
  1448. {
  1449. delete pEnum ;
  1450. }
  1451. return pTitle;
  1452. }
  1453. #endif // #ifdef HHCTRL
  1454. // Returns the first location
  1455. CLocation* CCollection::FirstLocation()
  1456. {
  1457. return m_pFirstLocation;
  1458. }
  1459. // Finds a location based on a name
  1460. CLocation * CCollection::FindLocation(const CHAR * Id, UINT* puiVolumeOrder )
  1461. {
  1462. if (!Id)
  1463. return NULL;
  1464. CLocation *p;
  1465. p = m_pFirstLocation;
  1466. if( puiVolumeOrder )
  1467. *puiVolumeOrder = 0;
  1468. while (p)
  1469. {
  1470. if( puiVolumeOrder )
  1471. *puiVolumeOrder = (*puiVolumeOrder)+1;
  1472. if (stricmp(p->GetId(), Id) == 0 && (p->m_ColNum == m_dwColNo|| p->m_ColNum == 0))
  1473. return p;
  1474. p = p->GetNextLocation();
  1475. }
  1476. return NULL;
  1477. }
  1478. DWORD CCollection::CheckTitleRef(const CHAR *pId, const LANGID Lang)
  1479. {
  1480. if (m_bConfirmTitles == FALSE)
  1481. return F_OK;
  1482. if (pId[0] != '=')
  1483. return F_OK;
  1484. CTitle *pTitle;
  1485. if ((pTitle = FindTitle(&pId[1], Lang)) == NULL)
  1486. return F_NOTITLE;
  1487. LOCATIONHISTORY *p;
  1488. p = pTitle->m_pHead;
  1489. while (p)
  1490. {
  1491. if (p->CollectionNumber == GetColNo())
  1492. return F_OK;
  1493. p = p->pNext;
  1494. }
  1495. return F_NOTITLE;
  1496. }
  1497. //Adds a new folder to the top level of the table of contents, with the given name and order and returns a pointer to that folder object. A return of NULL indicates a failure and pDWORD will be populated with one of above DWORD codes.
  1498. CFolder * CCollection::AddFolder(const CHAR * szName, DWORD Order, DWORD *pDWORD, LANGID LangId)
  1499. {
  1500. if (!szName)
  1501. {
  1502. if (pDWORD)
  1503. *pDWORD = F_NULL;
  1504. return NULL;
  1505. }
  1506. if (CheckTitleRef(szName, LangId) != F_OK)
  1507. {
  1508. if (pDWORD)
  1509. *pDWORD = F_NOTITLE;
  1510. return NULL;
  1511. }
  1512. CFolder *pNew;
  1513. pNew = new CFolder;
  1514. DWORD dwrc = F_OK;
  1515. if (pNew)
  1516. {
  1517. pNew->SetTitle(szName);
  1518. pNew->SetOrder(Order);
  1519. pNew->SetLanguage(LangId);
  1520. dwrc = m_pRootFolder->AddChildFolder(pNew);
  1521. if (dwrc != F_OK)
  1522. {
  1523. if (pDWORD)
  1524. *pDWORD = dwrc;
  1525. delete pNew;
  1526. return NULL;
  1527. }
  1528. Dirty();
  1529. return pNew;
  1530. }
  1531. if (pDWORD)
  1532. *pDWORD = F_MEMORY;
  1533. return NULL;
  1534. }
  1535. CTitle * CCollection::NewTitle()
  1536. {
  1537. CTitle *newTitle = new CTitle;
  1538. if (newTitle == NULL)
  1539. return NULL;
  1540. if (m_pFirstTitle == NULL)
  1541. {
  1542. m_pFirstTitle = newTitle;
  1543. }
  1544. else
  1545. {
  1546. m_pTitleTail->SetNextTitle(newTitle);
  1547. }
  1548. m_pTitleTail = newTitle;
  1549. return newTitle;
  1550. }
  1551. // Adds a title based on the provided information. A return of NULL indicates a failure and pDWORD will be populated with one of above DWORD codes.
  1552. // Note: you must add or find a CLocation object or pass null to indication no location is in use (local file).
  1553. CTitle * CCollection::AddTitle(const CHAR * Id, const CHAR * FileName,
  1554. const CHAR * IndexFile, const CHAR * Query, const CHAR *SampleLocation, LANGID Lang, UINT uiFlags,
  1555. CLocation *pLocation, DWORD *pDWORD, BOOL bSupportsMerge, const CHAR *QueryLocation)
  1556. {
  1557. if (!Id || !FileName || !IndexFile)
  1558. return NULL;
  1559. DWORD dwrc;
  1560. CTitle *pTitle;
  1561. // check if the title exist
  1562. if (pTitle = FindTitle(Id, Lang))
  1563. {
  1564. // add location
  1565. dwrc = pTitle->AddLocationHistory(m_dwColNo, FileName, IndexFile, Query, pLocation, SampleLocation, QueryLocation, bSupportsMerge);
  1566. if (pDWORD)
  1567. *pDWORD = dwrc;
  1568. }
  1569. else
  1570. {
  1571. // just add the title then
  1572. pTitle = NewTitle();
  1573. if (pTitle == NULL)
  1574. {
  1575. if (pDWORD)
  1576. *pDWORD = F_MEMORY;
  1577. return NULL;
  1578. }
  1579. pTitle->SetId(Id);
  1580. pTitle->SetLanguage(Lang);
  1581. dwrc = pTitle->AddLocationHistory(m_dwColNo, FileName, IndexFile, Query, pLocation, SampleLocation, QueryLocation, bSupportsMerge);
  1582. if (pDWORD)
  1583. *pDWORD = dwrc;
  1584. }
  1585. Dirty();
  1586. return pTitle;
  1587. }
  1588. CLocation * CCollection::NewLocation()
  1589. {
  1590. CLocation *p = new CLocation;
  1591. if (!p)
  1592. {
  1593. return NULL;
  1594. }
  1595. if (m_pFirstLocation == NULL)
  1596. {
  1597. m_pFirstLocation = p;
  1598. }
  1599. else
  1600. {
  1601. m_pLocationTail->SetNextLocation(p);
  1602. }
  1603. m_pLocationTail = p;
  1604. return p;
  1605. }
  1606. // Adds location based on the given information. A return of NULL indicates a failure and pDWORD will be populated with one of above DWORD codes.
  1607. CLocation * CCollection::AddLocation(const CHAR * Title, const CHAR * Path, const CHAR * Id, const CHAR * Volume, DWORD *pDWORD)
  1608. {
  1609. if (!Title || !Path || !Id || !Volume)
  1610. return NULL;
  1611. CLocation *p;
  1612. p = FindLocation(Id);
  1613. // if not found then add new location entry
  1614. if (!p)
  1615. p = NewLocation();
  1616. if (!p)
  1617. {
  1618. if (pDWORD)
  1619. *pDWORD = F_MEMORY;
  1620. return NULL;
  1621. }
  1622. p->SetTitle(Title);
  1623. p->SetPath(Path);
  1624. p->SetId(Id);
  1625. p->SetVolume(Volume);
  1626. p->m_ColNum = m_dwColNo;
  1627. if (pDWORD)
  1628. *pDWORD = F_OK;
  1629. Dirty();
  1630. return p;
  1631. }
  1632. // removing objects
  1633. DWORD CCollection::DeleteFolder(CFolder *pDelete)
  1634. {
  1635. if (!pDelete)
  1636. return F_NULL;
  1637. CFolder *pParent;
  1638. CFolder *pPrev = NULL;
  1639. CFolder *p;
  1640. if ((pParent = pDelete->GetParent()) == NULL)
  1641. return F_NOPARENT;
  1642. p = pParent->GetFirstChildFolder();
  1643. while (p)
  1644. {
  1645. if (p == pDelete)
  1646. {
  1647. // is this the head
  1648. if (!pPrev)
  1649. {
  1650. pParent->SetFirstChildFolder(p->GetNextFolder());
  1651. }
  1652. else
  1653. {
  1654. // fixup the list
  1655. pPrev->SetNextFolder(p->GetNextFolder());
  1656. }
  1657. DeleteChildren(&pDelete);
  1658. Dirty();
  1659. return F_OK;
  1660. }
  1661. pPrev = p;
  1662. p = p->GetNextFolder();
  1663. }
  1664. return F_NOTFOUND;
  1665. }
  1666. DWORD CCollection::DeleteTitle(CTitle *pDelete)
  1667. {
  1668. if (!pDelete)
  1669. return F_NULL;
  1670. // remove all location history entries for this collection
  1671. LOCATIONHISTORY *pHist, *pHistPrev;
  1672. pHistPrev = NULL;
  1673. pHist = pDelete->m_pHead;
  1674. while (pHist)
  1675. {
  1676. if (pHist->CollectionNumber == m_dwColNo)
  1677. {
  1678. // head
  1679. if (pHist == pDelete->m_pHead)
  1680. {
  1681. // and tail
  1682. if (pHist == pDelete->m_pTail)
  1683. {
  1684. pDelete->m_pHead = NULL;
  1685. pDelete->m_pTail = NULL;
  1686. DeleteLocalFiles(pHist, pDelete);
  1687. delete pHist;
  1688. break;
  1689. }
  1690. pDelete->m_pHead = pHist->pNext;
  1691. DeleteLocalFiles(pHist, pDelete);
  1692. delete pHist;
  1693. pHist = pDelete->m_pHead;
  1694. pHistPrev = NULL;
  1695. continue;
  1696. }
  1697. // tail
  1698. if (pHist == pDelete->m_pTail)
  1699. {
  1700. pDelete->m_pTail = pHistPrev;
  1701. if (pHistPrev)
  1702. pHistPrev->pNext = NULL;
  1703. DeleteLocalFiles(pHist, pDelete);
  1704. delete pHist;
  1705. break;
  1706. }
  1707. pHistPrev->pNext = pHist->pNext;
  1708. DeleteLocalFiles(pHist, pDelete);
  1709. delete pHist;
  1710. pHist = pHistPrev->pNext;
  1711. }
  1712. else
  1713. {
  1714. pHistPrev = pHist;
  1715. pHist = pHist->pNext;
  1716. }
  1717. }
  1718. Dirty();
  1719. // if no history remains remove the title
  1720. if (pDelete->m_pHead != NULL)
  1721. return F_OK;
  1722. CTitle *p, *pPrev;
  1723. p = m_pFirstTitle;
  1724. pPrev = NULL;
  1725. if (p== NULL)
  1726. return F_NOTFOUND;
  1727. while (p)
  1728. {
  1729. if (p == pDelete)
  1730. {
  1731. // is this the head
  1732. if (!pPrev)
  1733. {
  1734. m_pFirstTitle = p->GetNextTitle();
  1735. }
  1736. // is this the tail
  1737. else if (p == m_pTitleTail)
  1738. {
  1739. m_pTitleTail = pPrev;
  1740. pPrev->SetNextTitle(p->GetNextTitle());
  1741. }
  1742. else
  1743. {
  1744. // fixup the list
  1745. pPrev->SetNextTitle(p->GetNextTitle());
  1746. }
  1747. delete p;
  1748. return F_OK;
  1749. }
  1750. pPrev = p;
  1751. p = p->GetNextTitle();
  1752. }
  1753. return F_NOTFOUND;
  1754. }
  1755. void CCollection::DeleteLocalFiles(LOCATIONHISTORY *pThisHist, CTitle *pTitle)
  1756. {
  1757. if (m_bRemoveLocalFiles == FALSE)
  1758. return;
  1759. LOCATIONHISTORY *pHist;
  1760. pHist = pTitle->m_pHead;
  1761. // if the chm or chi is in use don't delete
  1762. while (pHist)
  1763. {
  1764. if (strcmp(pHist->FileName, pThisHist->FileName) == 0)
  1765. return;
  1766. if (strcmp(pHist->IndexFileName, pThisHist->IndexFileName) == 0)
  1767. return;
  1768. pHist = pHist->pNext;
  1769. }
  1770. // if these are local files delete them
  1771. char drive[_MAX_DRIVE+1];
  1772. char dir[_MAX_DIR];
  1773. char fname[_MAX_FNAME];
  1774. char ext[_MAX_EXT];
  1775. _splitpath( pThisHist->FileName, drive, dir, fname, ext );
  1776. if(drive[1] == ':')
  1777. {
  1778. drive[2] = '\\';
  1779. drive[3] = 0;
  1780. }
  1781. if (GetDriveType(drive) == DRIVE_FIXED)
  1782. {
  1783. // delete the title
  1784. if (DeleteFile(pThisHist->FileName) == FALSE)
  1785. m_bAllFilesDeleted = FALSE;
  1786. // could need to check for and delete samples stuff here
  1787. }
  1788. // if files are different
  1789. if (strcmp(pThisHist->IndexFileName, pThisHist->FileName))
  1790. {
  1791. _splitpath( pThisHist->IndexFileName, drive, dir, fname, ext );
  1792. if(drive[1] == ':')
  1793. {
  1794. drive[2] = '\\';
  1795. drive[3] = 0;
  1796. }
  1797. if (GetDriveType(drive) == DRIVE_FIXED)
  1798. {
  1799. // delete the index
  1800. if (DeleteFile(pThisHist->IndexFileName) == FALSE)
  1801. m_bAllFilesDeleted = FALSE;
  1802. // could need to check for and delete samples stuff here
  1803. }
  1804. }
  1805. }
  1806. // only used from HHSETUP
  1807. LANGID CCollection::GetLangId(const CHAR *szFileName)
  1808. {
  1809. #ifdef HHSETUP
  1810. return ::GetLangId(szFileName);
  1811. #else
  1812. return 0;
  1813. #endif
  1814. }
  1815. DWORD CCollection::DeleteLocation(CLocation *pDelete)
  1816. {
  1817. if (!pDelete)
  1818. return F_NULL;
  1819. CLocation *p, *pPrev;
  1820. p = m_pFirstLocation;
  1821. pPrev = NULL;
  1822. if (p== NULL)
  1823. return F_NOTFOUND;
  1824. while (p)
  1825. {
  1826. if (p == pDelete)
  1827. {
  1828. // is this the head
  1829. if (!pPrev)
  1830. {
  1831. m_pFirstLocation = p->GetNextLocation();
  1832. }
  1833. // is this the tail
  1834. else if (p == m_pLocationTail)
  1835. {
  1836. m_pLocationTail = pPrev;
  1837. pPrev->SetNextLocation(NULL);
  1838. }
  1839. else
  1840. {
  1841. // fixup the list
  1842. pPrev->SetNextLocation(p->GetNextLocation());
  1843. }
  1844. delete p;
  1845. Dirty();
  1846. return F_OK;
  1847. }
  1848. pPrev = p;
  1849. p = p->GetNextLocation();
  1850. }
  1851. return F_NOTFOUND;
  1852. }
  1853. DWORD CCollection::RemoveCollection(BOOL bRemoveLocalFiles)
  1854. {
  1855. // if release returns a positive ref count then don't delete
  1856. if (Release())
  1857. return F_OK;
  1858. m_bRemoveLocalFiles = bRemoveLocalFiles;
  1859. m_bAllFilesDeleted = TRUE;
  1860. m_bRemoved = TRUE;
  1861. CTitle *pT = GetFirstTitle();
  1862. CTitle *pNext;
  1863. while (pT)
  1864. {
  1865. pNext = pT->GetNextTitle();
  1866. DeleteTitle(pT);
  1867. pT = pNext;
  1868. }
  1869. // delete locations for this collection
  1870. CLocation *pL = FirstLocation();
  1871. CLocation *pNextLoc;
  1872. while (pL)
  1873. {
  1874. pNextLoc = pL->GetNextLocation();
  1875. if (pL->m_ColNum == m_dwColNo)
  1876. DeleteLocation(pL);
  1877. pL = pNextLoc;
  1878. }
  1879. RemoveCollectionEntry(m_szFileName);
  1880. Dirty();
  1881. if (m_bRemoveLocalFiles == TRUE && m_bAllFilesDeleted == FALSE)
  1882. return F_DELETE;
  1883. return F_OK;
  1884. }
  1885. void CCollection::DeleteFolders(CFolder **p)
  1886. {
  1887. CFolder *pChild, *pNext;
  1888. if (pChild = (*p)->GetFirstChildFolder())
  1889. DeleteFolders(&pChild);
  1890. pNext = (*p)->GetNextFolder();
  1891. // check if this is a title
  1892. const CHAR *pTitle = (*p)->GetTitle();
  1893. if (pTitle && pTitle[0] == '=') // if so delete it.
  1894. {
  1895. CTitle *pT;
  1896. pT = FindTitle(&pTitle[1], (*p)->GetLanguage());
  1897. if (pT)
  1898. DeleteTitle(pT);
  1899. }
  1900. delete (*p);
  1901. *p = NULL;
  1902. do {
  1903. if (pNext)
  1904. DeleteFolders(&pNext);
  1905. } while (pNext && (pNext = pNext->GetNextFolder()));
  1906. }
  1907. // Merges the currently installed titles for the collection into the specified filename (path determined internally)
  1908. BOOL CCollection::MergeKeywords(CHAR * pwzFilename )
  1909. {
  1910. return FALSE;
  1911. }
  1912. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1913. // CFolder implementation
  1914. CFolder::CFolder()
  1915. {
  1916. Title = NULL;
  1917. pwcTitle = NULL;
  1918. Order = 0;
  1919. LangId = ENGLANGID;
  1920. pNext = NULL;
  1921. pKid = NULL;
  1922. pParent = NULL;
  1923. iLevel = 0;
  1924. f_HasHash = 0;
  1925. f_IsOrphan = 1; // Assume the worst.
  1926. }
  1927. CFolder::~CFolder()
  1928. {
  1929. if (Title)
  1930. delete Title;
  1931. if(pwcTitle)
  1932. delete pwcTitle;
  1933. }
  1934. void CFolder::SetTitle(const CHAR *sz)
  1935. {
  1936. AllocSetValue(sz, &Title);
  1937. }
  1938. void CFolder::SetExTitlePtr(CExTitle* pTitle)
  1939. {
  1940. CFolder* pTmp;
  1941. pExTitle = pTitle;
  1942. f_IsOrphan = 0;
  1943. pTmp = pParent;
  1944. while ( pTmp )
  1945. {
  1946. pTmp->f_IsOrphan = 0;
  1947. pTmp = pTmp->pParent;
  1948. }
  1949. }
  1950. void CFolder::SetOrder(DWORD newOrder)
  1951. {
  1952. Order = newOrder;
  1953. }
  1954. DWORD CFolder::GetOrder()
  1955. {
  1956. return Order;
  1957. }
  1958. // Returns the next sibling folder given a folder entry
  1959. CFolder * CFolder::GetNextFolder()
  1960. {
  1961. return pNext;
  1962. }
  1963. // Returns the first child of a given folder if it exists
  1964. CFolder * CFolder::GetFirstChildFolder()
  1965. {
  1966. return pKid;
  1967. }
  1968. CFolder * CFolder::AddChildFolder(const CHAR *szName, DWORD Order, DWORD *pError, LANGID LangId)
  1969. {
  1970. CFolder *pFolder = new CFolder;
  1971. if (pFolder == NULL)
  1972. return NULL;
  1973. pFolder->SetTitle(szName);
  1974. pFolder->SetOrder(Order);
  1975. pFolder->SetLanguage(LangId);
  1976. DWORD dwrc = AddChildFolder(pFolder);
  1977. if (pError)
  1978. *pError = dwrc;
  1979. return pFolder;
  1980. }
  1981. DWORD CFolder::AddChildFolder(CFolder *newFolder)
  1982. {
  1983. CFolder* pTmp;
  1984. newFolder->SetParent(this);
  1985. if (pKid == NULL)
  1986. {
  1987. pKid = newFolder;
  1988. }
  1989. else
  1990. {
  1991. if (newFolder->GetOrder() < pKid->GetOrder())
  1992. {
  1993. // make this the first child
  1994. newFolder->pNext = pKid;
  1995. pKid = newFolder;
  1996. }
  1997. else
  1998. {
  1999. // search for an insertion point
  2000. CFolder *pNext = pKid->pNext;
  2001. CFolder *pPrev = pKid;
  2002. while (pNext)
  2003. {
  2004. if (newFolder->GetOrder() < pNext->GetOrder())
  2005. {
  2006. newFolder->pNext = pNext;
  2007. break;
  2008. }
  2009. pPrev = pNext;
  2010. pNext = pNext->pNext;
  2011. }
  2012. pPrev->pNext = newFolder;
  2013. }
  2014. }
  2015. //
  2016. // Setup members to facilitate subsetting...
  2017. //
  2018. if ( newFolder->Title && newFolder->Title[0] == '=' )
  2019. {
  2020. newFolder->f_HasHash = 1;
  2021. //
  2022. // Leaf nodes will be rendered as open books in the subset dialog.
  2023. //
  2024. newFolder->f_A_Open = 1;
  2025. newFolder->f_F_Open = 1;
  2026. }
  2027. pTmp = newFolder->pParent;
  2028. while ( pTmp )
  2029. {
  2030. newFolder->iLevel++;
  2031. pTmp = pTmp->pParent;
  2032. }
  2033. newFolder->iLevel--;
  2034. return F_OK;
  2035. }
  2036. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2037. // CTitle implementation
  2038. void CTitle::SetId(const CHAR *sz)
  2039. {
  2040. AllocSetValue(sz, &Id);
  2041. }
  2042. void CTitle::SetLanguage(LANGID l)
  2043. {
  2044. Language = l;
  2045. }
  2046. CHAR *CTitle::GetId()
  2047. {
  2048. return Id;
  2049. }
  2050. LANGID CTitle::GetLanguage()
  2051. {
  2052. return Language;
  2053. }
  2054. LOCATIONHISTORY *CTitle::NewLocationHistory()
  2055. {
  2056. LOCATIONHISTORY *p;
  2057. p = new LOCATIONHISTORY;
  2058. if (p == NULL)
  2059. return NULL;
  2060. p->SampleLocation = NULL;
  2061. p->QueryLocation = NULL;
  2062. p->FileName = NULL;
  2063. p->IndexFileName = NULL;
  2064. p->QueryFileName = NULL;
  2065. p->LocationId = NULL;
  2066. p->Version = 0;
  2067. p->LastPromptedVersion = 0;
  2068. p->bSupportsMerge = FALSE;
  2069. p->pNext = NULL;
  2070. if (m_pHead == NULL)
  2071. {
  2072. m_pHead = p;
  2073. }
  2074. else
  2075. {
  2076. m_pTail->pNext = p;
  2077. }
  2078. m_pTail = p;
  2079. return p;
  2080. }
  2081. DWORD CTitle::AddLocationHistory(DWORD ColNo, const CHAR *FileName, const CHAR *IndexFile, const CHAR *Query, const CLocation *pLocation, const CHAR *SampleLocation, const CHAR *QueryLocation, BOOL bSupportsMerge)
  2082. {
  2083. LOCATIONHISTORY *p;
  2084. // get version information
  2085. DWORD dwNewVersion;
  2086. #ifdef HHSETUP
  2087. if (IndexFile)
  2088. dwNewVersion = GetTitleVersion(IndexFile);
  2089. else if (FileName)
  2090. dwNewVersion = GetTitleVersion(FileName);
  2091. else
  2092. dwNewVersion = 0;
  2093. #else
  2094. dwNewVersion = 0;
  2095. #endif
  2096. // see of any current entries match is new one if so update the existing item.
  2097. if (m_pHead)
  2098. {
  2099. p = m_pHead;
  2100. while (p)
  2101. {
  2102. if (p->CollectionNumber == ColNo &&
  2103. ((FileName == NULL && p->FileName[0] == NULL) || (FileName &&strcmp(p->FileName, FileName) == 0)) &&
  2104. ((IndexFile == NULL && p->IndexFileName[0] == NULL) || (IndexFile &&strcmp(p->IndexFileName, IndexFile) == 0)) &&
  2105. ((Query == NULL && p->QueryFileName[0] == NULL) || (Query &&strcmp(p->QueryFileName, Query) == 0)) &&
  2106. ((SampleLocation == NULL && p->SampleLocation[0] == NULL) || (SampleLocation &&strcmp(p->SampleLocation, SampleLocation) == 0)) &&
  2107. ((QueryLocation == NULL && p->QueryLocation[0] == NULL) || (QueryLocation &&strcmp(p->QueryLocation, QueryLocation) == 0)) &&
  2108. p->bSupportsMerge == bSupportsMerge)
  2109. {
  2110. if (pLocation && strcmp(pLocation->GetId(), p->LocationId) != 0)
  2111. {
  2112. p = p->pNext;
  2113. continue;
  2114. }
  2115. // everything matches just update the version number
  2116. p->Version = dwNewVersion;
  2117. return F_OK;
  2118. }
  2119. p = p->pNext;
  2120. }
  2121. }
  2122. // see if we already have this version if so update to location
  2123. if (m_pHead)
  2124. {
  2125. p = m_pHead;
  2126. while (p)
  2127. {
  2128. if (p->Version == dwNewVersion && p->CollectionNumber == ColNo)
  2129. {
  2130. // same version update location
  2131. p->bSupportsMerge = bSupportsMerge;
  2132. if (FileName)
  2133. AllocSetValue(FileName, &p->FileName);
  2134. else
  2135. p->FileName = NULL;
  2136. if (IndexFile)
  2137. AllocSetValue(IndexFile, &p->IndexFileName);
  2138. else
  2139. p->IndexFileName = NULL;
  2140. if (SampleLocation)
  2141. AllocSetValue(SampleLocation, &p->SampleLocation);
  2142. else
  2143. p->SampleLocation = NULL;
  2144. if (QueryLocation)
  2145. AllocSetValue(QueryLocation, &p->QueryLocation);
  2146. else
  2147. p->QueryLocation = NULL;
  2148. if (Query)
  2149. AllocSetValue(Query, &p->QueryFileName);
  2150. else
  2151. p->QueryFileName = NULL;
  2152. if (pLocation)
  2153. AllocSetValue(pLocation->GetId() , &p->LocationId);
  2154. else
  2155. p->LocationId = NULL;
  2156. return F_OK;
  2157. }
  2158. p = p->pNext;
  2159. }
  2160. }
  2161. p = NewLocationHistory();
  2162. if (p == NULL)
  2163. return F_MEMORY;
  2164. p->Version = dwNewVersion;
  2165. p->CollectionNumber = ColNo;
  2166. p->bSupportsMerge = bSupportsMerge;
  2167. if (FileName)
  2168. AllocSetValue(FileName, &p->FileName);
  2169. if (IndexFile)
  2170. AllocSetValue(IndexFile, &p->IndexFileName);
  2171. if (SampleLocation)
  2172. AllocSetValue(SampleLocation, &p->SampleLocation);
  2173. if (QueryLocation)
  2174. AllocSetValue(QueryLocation, &p->QueryLocation);
  2175. else
  2176. AllocSetValue("", &p->QueryLocation);
  2177. if (Query)
  2178. AllocSetValue(Query, &p->QueryFileName);
  2179. else
  2180. AllocSetValue("", &p->QueryFileName);
  2181. if (pLocation)
  2182. AllocSetValue(pLocation->GetId() , &p->LocationId);
  2183. return F_OK;
  2184. }
  2185. LOCATIONHISTORY * CTitle::GetLocation(DWORD Index)
  2186. {
  2187. LOCATIONHISTORY *p;
  2188. p = m_pHead;
  2189. for (DWORD i = 0; p && i < Index; i++)
  2190. p++;
  2191. return p;
  2192. }
  2193. CTitle* CTitle::GetNextTitle()
  2194. {
  2195. return NextTitle;
  2196. }
  2197. CTitle::~CTitle()
  2198. {
  2199. if (Id) delete Id;
  2200. if (pwcId)
  2201. delete pwcId;
  2202. // clean up location history
  2203. LOCATIONHISTORY *p, *pNext;
  2204. for (p = m_pHead; p; p=pNext)
  2205. {
  2206. pNext = p->pNext;
  2207. if (p->FileName) delete p->FileName;
  2208. if (p->IndexFileName) delete p->IndexFileName;
  2209. if (p->QueryFileName) delete p->QueryFileName;
  2210. if (p->LocationId) delete p->LocationId;
  2211. if (p->SampleLocation) delete p->SampleLocation;
  2212. if (p->QueryLocation) delete p->QueryLocation;
  2213. delete p;
  2214. }
  2215. }
  2216. CTitle::CTitle()
  2217. {
  2218. Id = NULL;
  2219. pwcId = NULL;
  2220. Language = 0;
  2221. NextTitle = NULL;
  2222. m_pHead = NULL;
  2223. m_pTail = NULL;
  2224. }
  2225. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2226. // CLocation implementation
  2227. // BUGBUG: 29-May-1997 [ralphw] This is a lot of code overhead to call
  2228. // functions that do nothing but return a value or exectue a single line
  2229. // of code. These should all be inlined, at least for the OCX version
  2230. // to cut down code size.
  2231. void CLocation::SetId(const CHAR *sz)
  2232. {
  2233. AllocSetValue(sz, &Id);
  2234. }
  2235. void CLocation::SetTitle(const CHAR *sz)
  2236. {
  2237. AllocSetValue(sz, &Title);
  2238. }
  2239. void CLocation::SetPath(const CHAR *sz)
  2240. {
  2241. AllocSetValue(sz, &Path);
  2242. }
  2243. void CLocation::SetVolume(const CHAR *sz)
  2244. {
  2245. AllocSetValue(sz, &Volume);
  2246. }
  2247. CHAR * CLocation::GetId() const
  2248. {
  2249. return Id;
  2250. }
  2251. CHAR * CLocation::GetTitle()
  2252. {
  2253. return Title;
  2254. }
  2255. CHAR * CLocation::GetPath()
  2256. {
  2257. return Path;
  2258. }
  2259. CHAR * CLocation::GetVolume()
  2260. {
  2261. return Volume;
  2262. }
  2263. // Returns the next location
  2264. CLocation * CLocation::GetNextLocation()
  2265. {
  2266. return NextLocation;
  2267. }
  2268. // UNICODE APIs /////////////////////////////////////////////////////////////////////////////////////////////////
  2269. //
  2270. void CFolder::SetTitle(const WCHAR *pTitle)
  2271. {
  2272. CAnsi cszTemp((WCHAR *)pTitle);
  2273. SetTitle((char *)cszTemp);
  2274. }
  2275. const WCHAR * CFolder::GetTitleW()
  2276. {
  2277. if(pwcTitle)
  2278. delete [] pwcTitle;
  2279. pwcTitle = CreateUnicodeFromAnsi(Title);
  2280. return pwcTitle;
  2281. }
  2282. CFolder * CFolder::AddChildFolder(const WCHAR *szName, DWORD Order, DWORD *pError, LANGID LangId)
  2283. {
  2284. CAnsi cszTemp1((WCHAR *)szName);
  2285. return AddChildFolder((CHAR *)cszTemp1,Order,pError,LangId);
  2286. }
  2287. const WCHAR * CTitle::GetIdW()
  2288. {
  2289. if(pwcId)
  2290. delete [] pwcId;
  2291. pwcId = CreateUnicodeFromAnsi(Id);
  2292. return pwcId;
  2293. }
  2294. void CTitle::SetId(const WCHAR *pszId)
  2295. {
  2296. CAnsi cszTemp1((WCHAR *)pszId);
  2297. SetId((CHAR *)cszTemp1);
  2298. }
  2299. DWORD CTitle::AddLocationHistory(DWORD ColNo, const WCHAR *FileName, const WCHAR *IndexFile, const WCHAR *Query, const CLocation *pLocation, const WCHAR *Sample, const WCHAR *QueryLocation, BOOL bSupportsMerge)
  2300. {
  2301. CAnsi cszTemp1((WCHAR *)FileName);
  2302. CAnsi cszTemp2((WCHAR *)IndexFile);
  2303. CAnsi cszTemp3((WCHAR *)Query);
  2304. CAnsi cszTemp4((WCHAR *)Sample);
  2305. CAnsi cszTemp5((WCHAR *)QueryLocation);
  2306. return AddLocationHistory(ColNo, (CHAR *)cszTemp1, (CHAR *)cszTemp2, (CHAR *)cszTemp3, pLocation, (CHAR *)cszTemp4, (CHAR *)cszTemp5, bSupportsMerge);
  2307. }
  2308. void CLocation::SetId(const WCHAR *pwcTemp)
  2309. {
  2310. CAnsi cszTemp1((WCHAR *)pwcTemp);
  2311. SetId((CHAR *)cszTemp1);
  2312. }
  2313. void CLocation::SetTitle(const WCHAR *pwcTemp)
  2314. {
  2315. CAnsi cszTemp1((WCHAR *)pwcTemp);
  2316. SetTitle((CHAR *)cszTemp1);
  2317. }
  2318. void CLocation::SetPath(const WCHAR *pwcTemp)
  2319. {
  2320. CAnsi cszTemp1((WCHAR *)pwcTemp);
  2321. SetPath((CHAR *)cszTemp1);
  2322. }
  2323. void CLocation::SetVolume(const WCHAR *pwcTemp)
  2324. {
  2325. CAnsi cszTemp1((WCHAR *)pwcTemp);
  2326. SetVolume((CHAR *)cszTemp1);
  2327. }
  2328. const WCHAR * CLocation::GetIdW()
  2329. {
  2330. if(pwcId)
  2331. delete [] pwcId;
  2332. pwcId = CreateUnicodeFromAnsi(Id);
  2333. return pwcId;
  2334. }
  2335. const WCHAR * CLocation::GetTitleW()
  2336. {
  2337. if(pwcTitle)
  2338. delete [] pwcTitle;
  2339. pwcTitle = CreateUnicodeFromAnsi(Title);
  2340. return pwcTitle;
  2341. }
  2342. const WCHAR * CLocation::GetPathW()
  2343. {
  2344. if(pwcPath)
  2345. delete [] pwcPath;
  2346. pwcPath = CreateUnicodeFromAnsi(Path);
  2347. return pwcPath;
  2348. }
  2349. const WCHAR * CLocation::GetVolumeW()
  2350. {
  2351. if(pwcVolume)
  2352. delete [] pwcVolume;
  2353. pwcVolume = CreateUnicodeFromAnsi(Volume);
  2354. return pwcVolume;
  2355. }
  2356. DWORD CCollection::CheckTitleRef(const WCHAR *pId, const LANGID Lang)
  2357. {
  2358. CAnsi cszTemp1((WCHAR *)pId);
  2359. return CheckTitleRef(cszTemp1, Lang);
  2360. }
  2361. void CCollection::SetSampleLocation(const WCHAR *pwcItem1)
  2362. {
  2363. CAnsi cszTemp1((WCHAR *)pwcItem1);
  2364. SetSampleLocation(cszTemp1);
  2365. }
  2366. const WCHAR * CCollection::GetSampleLocationW()
  2367. {
  2368. if(m_pwcSampleLocation)
  2369. delete [] m_pwcSampleLocation;
  2370. m_pwcSampleLocation = CreateUnicodeFromAnsi(m_szSampleLocation);
  2371. return m_pwcSampleLocation;
  2372. }
  2373. void CCollection::SetMasterCHM(const WCHAR *szName, LANGID Lang)
  2374. {
  2375. CAnsi cszTemp1((WCHAR *)szName);
  2376. SetMasterCHM(cszTemp1, Lang);
  2377. }
  2378. BOOL CCollection::GetMasterCHM(WCHAR ** szName, LANGID *pLang)
  2379. {
  2380. *pLang = m_MasterLangId;
  2381. *szName = NULL;
  2382. if (m_szMasterCHM == NULL)
  2383. return FALSE;
  2384. if(m_pwcMasterCHM)
  2385. delete [] m_pwcMasterCHM;
  2386. m_pwcMasterCHM = CreateUnicodeFromAnsi(m_szMasterCHM);
  2387. *szName = m_pwcMasterCHM;
  2388. return ((strlen(m_szMasterCHM) ? TRUE : FALSE));
  2389. }
  2390. DWORD CCollection::Open(const WCHAR * FileName)
  2391. {
  2392. CAnsi cszTemp1((WCHAR *)FileName);
  2393. return Open(cszTemp1);
  2394. }
  2395. CTitle * CCollection::FindTitle(const WCHAR * Id, LANGID LangId)
  2396. {
  2397. CAnsi cszTemp1((WCHAR *)Id);
  2398. return FindTitle(cszTemp1, LangId);
  2399. }
  2400. CLocation * CCollection::FindLocation(const WCHAR * Name, UINT* puiVolumeOrder)
  2401. {
  2402. CAnsi cszTemp1((WCHAR *)Name);
  2403. return FindLocation(cszTemp1,puiVolumeOrder);
  2404. }
  2405. CFolder * CCollection::AddFolder(const WCHAR * szName, DWORD Order, DWORD *pDWORD, LANGID LangId)
  2406. {
  2407. CAnsi cszTemp1((WCHAR *)szName);
  2408. return AddFolder(cszTemp1, Order, pDWORD, LangId);
  2409. }
  2410. CTitle * CCollection::AddTitle(const WCHAR * Id, const WCHAR * FileName,
  2411. const WCHAR * IndexFile, const WCHAR * Query,
  2412. const WCHAR *SampleLocation, LANGID Lang,
  2413. UINT uiFlags, CLocation *pLocation,
  2414. DWORD *pDWORD, BOOL bSupportsMerge,
  2415. const WCHAR *QueryLocation)
  2416. {
  2417. CAnsi cszTemp1((WCHAR *)Id);
  2418. CAnsi cszTemp2((WCHAR *)FileName);
  2419. CAnsi cszTemp3((WCHAR *)IndexFile);
  2420. CAnsi cszTemp4((WCHAR *)Query);
  2421. CAnsi cszTemp5((WCHAR *)SampleLocation);
  2422. CAnsi cszTemp6((WCHAR *)QueryLocation);
  2423. return AddTitle(cszTemp1, cszTemp2, cszTemp3, cszTemp4,cszTemp5, Lang, uiFlags, pLocation, pDWORD, bSupportsMerge, cszTemp6);
  2424. }
  2425. CLocation * CCollection::AddLocation(const WCHAR * Title, const WCHAR * Path, const WCHAR * Id, const WCHAR * Volume, DWORD *pDWORD)
  2426. {
  2427. CAnsi cszTemp1((WCHAR *)Title);
  2428. CAnsi cszTemp2((WCHAR *)Path);
  2429. CAnsi cszTemp3((WCHAR *)Id);
  2430. CAnsi cszTemp4((WCHAR *)Volume);
  2431. return AddLocation(cszTemp1, cszTemp2,cszTemp3,cszTemp4,pDWORD);
  2432. }
  2433. BOOL CCollection::MergeKeywords(WCHAR * pwzFilename )
  2434. {
  2435. CAnsi cszTemp1((WCHAR *)pwzFilename);
  2436. return MergeKeywords(cszTemp1);
  2437. }
  2438. const WCHAR *CCollection::GetCollectionFileNameW(void)
  2439. {
  2440. if(m_pwcFileName)
  2441. delete [] m_pwcFileName;
  2442. m_pwcFileName = CreateUnicodeFromAnsi(m_szFileName);
  2443. return m_pwcFileName;
  2444. }
  2445. LANGID CCollection::GetLangId(const WCHAR *FileName)
  2446. {
  2447. CAnsi cszTemp1((WCHAR *)FileName);
  2448. return GetLangId(cszTemp1);
  2449. }
  2450. WCHAR *CreateUnicodeFromAnsi(LPSTR psz)
  2451. {
  2452. LPWSTR pwsz;
  2453. int i;
  2454. if(!psz)
  2455. return NULL;
  2456. i = MultiByteToWideChar(CP_ACP, 0, psz, -1, NULL, 0);
  2457. if (i <= 0)
  2458. return NULL;
  2459. pwsz = (LPWSTR) new WCHAR[i];
  2460. if (!pwsz)
  2461. return NULL;
  2462. MultiByteToWideChar(CP_ACP, 0, psz, -1, pwsz, i * sizeof(WCHAR));
  2463. return pwsz;
  2464. }
  2465. CAnsi::CAnsi(WCHAR *pwcString)
  2466. {
  2467. m_pszChar = NULL;
  2468. int i;
  2469. i = WideCharToMultiByte(CP_ACP, 0, pwcString, -1, NULL, 0, NULL, NULL);
  2470. if (i <= 0)
  2471. return;
  2472. m_pszChar = (CHAR *) new CHAR[i];
  2473. WideCharToMultiByte(CP_ACP, 0, pwcString, -1, m_pszChar, i, NULL, NULL);
  2474. m_pszChar[i - 1] = 0;
  2475. }
  2476. CAnsi::~CAnsi()
  2477. {
  2478. if(m_pszChar)
  2479. delete [] m_pszChar;
  2480. }
  2481. #ifdef HHCTRL
  2482. //
  2483. // CSlotLookupTable implementation...
  2484. //
  2485. int FASTCALL CSlotLookupTable::ltqs_callback(const void *elem1, const void *elem2)
  2486. {
  2487. struct _slt* p1 = (struct _slt*)elem1;
  2488. struct _slt* p2 = (struct _slt*)elem2;
  2489. if ( p1->hash > p2->hash )
  2490. return 1;
  2491. else if ( p2->hash > p1->hash )
  2492. return -1;
  2493. else
  2494. return 1;
  2495. }
  2496. CSlotLookupTable::CSlotLookupTable()
  2497. {
  2498. m_pSLT = NULL;
  2499. m_uiTotalCnt = m_uiHashCnt = m_uiTotalAllocated = 0;
  2500. }
  2501. CSlotLookupTable::~CSlotLookupTable()
  2502. {
  2503. if ( m_pSLT )
  2504. lcFree(m_pSLT);
  2505. }
  2506. void CSlotLookupTable::AddValue(CFolder* pFolder)
  2507. {
  2508. if ( (m_uiTotalCnt && (!(m_uiTotalCnt % 8))) || (m_uiTotalAllocated == 0) )
  2509. {
  2510. m_uiTotalAllocated += 8;
  2511. m_pSLT = (struct _slt*)lcReAlloc(m_pSLT, sizeof(struct _slt) * m_uiTotalAllocated);
  2512. }
  2513. m_pSLT[m_uiTotalCnt].pCFolder = pFolder;
  2514. if ( pFolder->f_HasHash )
  2515. {
  2516. m_pSLT[m_uiTotalCnt].hash = pFolder->pExTitle->m_dwHash;
  2517. m_uiHashCnt++;
  2518. }
  2519. else
  2520. m_pSLT[m_uiTotalCnt].hash = (unsigned)(-1);
  2521. m_uiTotalCnt++;
  2522. }
  2523. void CSlotLookupTable::SortAndAssignSlots(void)
  2524. {
  2525. unsigned i;
  2526. // First, sort by hash.
  2527. //
  2528. qsort(m_pSLT, m_uiTotalCnt, sizeof(struct _slt), ltqs_callback);
  2529. //
  2530. // Next, run through the table and assign the slots back to the CFolders.
  2531. //
  2532. for (i = 0; i < m_uiTotalCnt; i++)
  2533. m_pSLT[i].pCFolder->dwSlot = i;
  2534. }
  2535. CFolder* CSlotLookupTable::HashToCFolder(HASH hash)
  2536. {
  2537. if (! m_pSLT )
  2538. return NULL;
  2539. int mid,low = 0;
  2540. int high = m_uiHashCnt - 1;
  2541. while ( low <= high )
  2542. {
  2543. mid = ((low + high) / 2);
  2544. if ( m_pSLT[mid].hash == hash )
  2545. return m_pSLT[mid].pCFolder; // Found it!
  2546. else if ( m_pSLT[mid].hash > hash )
  2547. high = mid - 1;
  2548. else
  2549. low = mid + 1;
  2550. }
  2551. return NULL; // Oh bad!
  2552. }
  2553. #endif