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.

1064 lines
26 KiB

  1. // DataSrc.cpp - Implementation of DataSource and Folder shared base methods.
  2. //
  3. // Copyright (c) 1998-1999 Microsoft Corporation
  4. #include <afx.h>
  5. #include "StdAfx.h"
  6. #include "DataSrc.h"
  7. #include "Resource.h"
  8. #include "resrc1.h"
  9. #include "FileIO.h"
  10. #include "msicab.h"
  11. LPCTSTR cszRootName = _T("");
  12. /*
  13. * CDataSource - Default data source constructor.
  14. *
  15. * History: a-jsari 10/15/97 Initial version
  16. */
  17. CDataSource::CDataSource(LPCTSTR szMachineName)
  18. :m_RootFolder(NULL),
  19. m_pPrintContent(NULL),
  20. m_pDC(NULL),
  21. m_pPrintInfo(NULL),
  22. m_pprinterFont(NULL),
  23. m_strPath(_T("")),
  24. m_iLine(0),
  25. m_fCanceled(FALSE),
  26. m_strHeaderLeft(szMachineName),
  27. m_pfLast(NULL)
  28. {
  29. }
  30. /*
  31. * ~CDataSource - Default data source destructor.
  32. *
  33. * History: a-jsari 10/15/97 Initial version.
  34. */
  35. CDataSource::~CDataSource()
  36. {
  37. delete m_RootFolder;
  38. delete m_pPrintContent;
  39. delete m_pDC;
  40. delete m_pprinterFont;
  41. #pragma warning(disable:4150)
  42. // C++ warns us that no destructor is called for m_pPrintInfo.
  43. // This is intended behavior
  44. delete m_pPrintInfo;
  45. #pragma warning(default:4150)
  46. }
  47. /*
  48. * GetNodeName - Return the default node name (if not overridden in subclasses.
  49. *
  50. * History: a-jsari 1/16/98 Initial version.
  51. */
  52. BOOL CDataSource::GetNodeName(CString &strNode)
  53. {
  54. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  55. VERIFY(strNode.LoadString(IDS_EXTENSIONNODENAME));
  56. return TRUE;
  57. }
  58. /*
  59. * SetDataComplexity - Set the global complexity of this source.
  60. *
  61. * History: a-jsari 12/22/97 Initial version.
  62. */
  63. BOOL CDataSource::SetDataComplexity(enum DataComplexity Complexity)
  64. {
  65. m_Complexity = Complexity;
  66. return TRUE;
  67. }
  68. /*
  69. * ResultFromFileException - Return the HRESULT which corresponds to the
  70. *
  71. * History: a-jsari 3/26/98 Initial version.
  72. */
  73. static inline HRESULT ResultFromFileException(CFileException *e)
  74. {
  75. HRESULT hrReturn;
  76. switch (e->m_cause) {
  77. case CFileException::badPath:
  78. hrReturn = STG_E_PATHNOTFOUND;
  79. break;
  80. case CFileException::accessDenied:
  81. hrReturn = STG_E_ACCESSDENIED;
  82. break;
  83. case CFileException::tooManyOpenFiles:
  84. hrReturn = STG_E_TOOMANYOPENFILES;
  85. break;
  86. case CFileException::sharingViolation:
  87. hrReturn = STG_E_SHAREVIOLATION;
  88. break;
  89. case CFileException::hardIO:
  90. hrReturn = STG_E_WRITEFAULT;
  91. break;
  92. case CFileException::directoryFull:
  93. case CFileException::diskFull:
  94. hrReturn = STG_E_MEDIUMFULL;
  95. break;
  96. default:
  97. // Return the default error code.
  98. hrReturn = E_UNEXPECTED;
  99. break;
  100. }
  101. return hrReturn;
  102. }
  103. /*
  104. * SaveFile - Save, starting from the root passed in, as a binary file.
  105. *
  106. * History: a-jsari 10/21/97 Initial version
  107. */
  108. HRESULT CDataSource::SaveFile(LPCTSTR cszFilename, CFolder *pSaveRoot)
  109. {
  110. HRESULT hrReturn;
  111. if (cszFilename == NULL) return E_INVALIDARG;
  112. try {
  113. CMSInfoFile msfSave(cszFilename);
  114. hrReturn = WriteOutput(&msfSave, pSaveRoot);
  115. }
  116. catch (CFileException *e) {
  117. // Remove the incomplete file.
  118. if (::_taccess(cszFilename, A_EXIST) == 0) {
  119. (void)_tunlink(cszFilename);
  120. }
  121. hrReturn = ::ResultFromFileException(e);
  122. }
  123. return hrReturn;
  124. }
  125. /*
  126. * ReportWrite - Create a text file and write output to it. (Automatically
  127. * writes data in the text file [report] format.)
  128. *
  129. * History: a-jsari 10/21/97 Initial version
  130. */
  131. HRESULT CDataSource::ReportWrite(LPCTSTR cszFilename, CFolder *pSaveRoot)
  132. {
  133. HRESULT hrReturn;
  134. if (cszFilename == NULL)
  135. return E_INVALIDARG;
  136. try
  137. {
  138. CMSInfoTextFile msfSave( cszFilename);
  139. hrReturn = WriteOutput(&msfSave, pSaveRoot);
  140. }
  141. catch (CFileException *e)
  142. {
  143. // Remove the incomplete file.
  144. if (::_taccess(cszFilename, A_EXIST) == 0)
  145. (void)_tunlink(cszFilename);
  146. hrReturn = ::ResultFromFileException(e);
  147. }
  148. return hrReturn;
  149. }
  150. /*
  151. * WriteOutput - Traverse a sub-tree of our internal storage, saving
  152. * each node, ending when we return to the original CFolder. If
  153. * our parameter is NULL, start from the root (write the entire
  154. * tree).
  155. *
  156. * Note: This function calls FileSave, which writes text data automatically
  157. * when the CMSInfoFile passed in is a text file and binary data when
  158. * it is a binary file.
  159. *
  160. * History: a-jsari 11/5/97 Initial version
  161. */
  162. HRESULT CDataSource::WriteOutput(CMSInfoFile * pFile, CFolder * pRootNode)
  163. {
  164. CFolder *pFolder;
  165. CFolder *pNext;
  166. enum DataComplexity Complexity;
  167. HRESULT hrReturn = S_OK;
  168. ASSERT(pFile != NULL);
  169. try {
  170. // When we save, always save the advanced information. Note, even if the
  171. // complexity is currently ADVANCED, we should make the call to SetDataComplexity.
  172. // If WriteOutput is being called because of a COM call to MSInfo (e.g. when
  173. // WinRep creates an NFO using MSInfo without launching MSInfo), the data
  174. // gatherer object might not have had a complexity set yet.
  175. Complexity = m_Complexity;
  176. m_Complexity = ADVANCED;
  177. SetDataComplexity(m_Complexity);
  178. if (pRootNode)
  179. VERIFY(pRootNode->Refresh(TRUE));
  180. else
  181. VERIFY(Refresh()); // Ensure that we have the most current data.
  182. pFile->WriteHeader(this);
  183. if (pRootNode == NULL)
  184. pFolder = GetRootNode();
  185. else
  186. pFolder = pRootNode;
  187. ASSERT(pFolder != NULL);
  188. // Traverse the tree structure, writing the nodes in order.
  189. do {
  190. // Write the data for each folder as it is encountered.
  191. pFolder->FileSave(pFile);
  192. // Depth-first: If we have a child, traverse it next.
  193. pNext = pFolder->GetChildNode();
  194. if (pNext != NULL) {
  195. pFile->WriteChildMark();
  196. pFolder = pNext;
  197. continue;
  198. }
  199. // If we are at our root folder, don't traverse to the next node..
  200. if (pFolder == pRootNode) break;
  201. // If we have reached the bottom of our list, traverse
  202. // our siblings.
  203. pNext = pFolder->GetNextNode();
  204. if (pNext != NULL) {
  205. pFile->WriteNextMark();
  206. pFolder = pNext;
  207. continue;
  208. }
  209. // If we have no more siblings, find our nearest parent's
  210. // sibling, traversing upwards until we find the node we
  211. // started with.
  212. pNext = pFolder->GetParentNode();
  213. ASSERT(pNext != NULL);
  214. unsigned uParentCount = 0;
  215. while (pNext != pRootNode) {
  216. ++uParentCount;
  217. pFolder = pNext->GetNextNode();
  218. // Our Parent has a sibling, continue with it.
  219. if (pFolder != NULL) {
  220. pFile->WriteParentMark(uParentCount);
  221. break;
  222. }
  223. // No siblings; check the next parent..
  224. pNext = pNext->GetParentNode();
  225. }
  226. // If we've returned to our root node, we're done.
  227. if (pNext == pRootNode) break;
  228. } while (pFolder);
  229. pFile->WriteEndMark();
  230. }
  231. catch (CFileException *e) {
  232. if (Complexity == BASIC)
  233. SetDataComplexity(Complexity);
  234. throw e;
  235. }
  236. catch (...) {
  237. ASSERT(FALSE);
  238. hrReturn = E_UNEXPECTED;
  239. }
  240. // Restore the original complexity.
  241. if (Complexity != m_Complexity)
  242. {
  243. m_Complexity = Complexity;
  244. SetDataComplexity(m_Complexity);
  245. }
  246. return hrReturn;
  247. }
  248. /*
  249. * CreateFromIStream - Return the appropriate CDataSource pointer the exists
  250. * on the IStream.
  251. *
  252. * History: a-jsari 11/13/97 Initial version
  253. */
  254. CDataSource *CDataSource::CreateFromIStream(IStream *pStm)
  255. {
  256. unsigned wType;
  257. unsigned wLength;
  258. ULONG dwSize;
  259. HRESULT hResult;
  260. CDataSource *pSource = NULL;
  261. WCHAR szBuffer[MAX_PATH];
  262. LPWSTR pszBuffer;
  263. ASSERT(pStm != NULL);
  264. ASSERT(!IsBadReadPtr(pStm, sizeof(IStream)));
  265. if (pStm == NULL || IsBadReadPtr(pStm, sizeof(IStream)))
  266. return NULL;
  267. do {
  268. hResult = pStm->Read(&wType, sizeof(wType), &dwSize);
  269. ASSERT(SUCCEEDED(hResult));
  270. ASSERT(dwSize == sizeof(wType));
  271. if (FAILED(hResult) || dwSize != sizeof(wType))
  272. break;
  273. hResult = pStm->Read(&wLength, sizeof(wLength), &dwSize);
  274. ASSERT(SUCCEEDED(hResult));
  275. ASSERT(dwSize == sizeof(wLength));
  276. ASSERT(wLength <= MAX_PATH);
  277. if (FAILED(hResult) || (dwSize != sizeof(wLength)) || wLength > MAX_PATH)
  278. break;
  279. szBuffer[wLength] = (WCHAR)0;
  280. wLength *= sizeof(WCHAR);
  281. if (wLength != 0) {
  282. hResult = pStm->Read(szBuffer, wLength, &dwSize);
  283. ASSERT(SUCCEEDED(hResult));
  284. ASSERT(dwSize == wLength);
  285. if (FAILED(hResult) || dwSize != wLength)
  286. break;
  287. pszBuffer = szBuffer;
  288. } else {
  289. pszBuffer = NULL;
  290. }
  291. switch (wType) {
  292. case V500FILE:
  293. try {
  294. ASSERT(pszBuffer != NULL);
  295. CMSInfoFile msiFile(pszBuffer, CFile::modeRead
  296. | CFile::shareDenyWrite | CFile::typeBinary);
  297. VERIFY(CBufferV500DataSource::VerifyFileVersion(&msiFile));
  298. pSource = new CBufferV500DataSource(&msiFile);
  299. }
  300. catch (...) {
  301. if (pSource != NULL)
  302. delete pSource;
  303. return NULL;
  304. }
  305. break;
  306. case GATHERER:
  307. try {
  308. pSource = new CWBEMDataSource(pszBuffer);
  309. }
  310. catch (...) {
  311. if (pSource != NULL)
  312. delete pSource;
  313. return NULL;
  314. }
  315. break;
  316. default:
  317. ASSERT(FALSE);
  318. break;
  319. }
  320. } while (FALSE);
  321. return pSource;
  322. }
  323. /*
  324. * CFolder - Default folder constructor. Initializes the pointers
  325. * to NULL.
  326. *
  327. * History: a-jsari 10/15/97 Initial version
  328. */
  329. CFolder::CFolder(CDataSource *pDataSource, CFolder *pParentNode)
  330. :m_ChildFolder(NULL), m_NextFolder(NULL), m_ParentFolder(pParentNode),
  331. m_pDataSource(pDataSource), fChildTested(FALSE), fNextTested(FALSE),
  332. m_nLine(-1)
  333. {
  334. }
  335. /*
  336. * ~CFolder - Default folder destructor. Deletes the saved pointers.
  337. *
  338. * History: a-jsari 10/15/97 Initial version
  339. */
  340. CFolder::~CFolder()
  341. {
  342. if (m_ChildFolder)
  343. {
  344. delete m_ChildFolder;
  345. m_ChildFolder = NULL;
  346. }
  347. if (m_NextFolder)
  348. {
  349. delete m_NextFolder;
  350. m_NextFolder = NULL;
  351. }
  352. // Don't delete m_ParentFolder, since it won't necessarily go
  353. // away when its child Folder goes away (and if it does, it's
  354. // already in the process of going away).
  355. }
  356. /*
  357. * InternalName - Return our internal name, just the amalgam of all parent
  358. * internal names and our name.
  359. *
  360. * History: a-jsari 12/12/97 Initial version
  361. */
  362. void CFolder::InternalName(CString &strName) const
  363. {
  364. if (m_ParentFolder == NULL) {
  365. strName = cszRootName;
  366. return;
  367. }
  368. m_ParentFolder->InternalName(strName);
  369. strName += _T("\\");
  370. CString strLocalName;
  371. GetName(strLocalName);
  372. strName += strLocalName;
  373. }
  374. /*
  375. * SaveTitle - Save the folder's title as a string to binary save file pFile
  376. *
  377. * History: a-jsari 10/29/97 Initial version
  378. */
  379. void CListViewFolder::SaveTitle(CMSInfoFile *pFile)
  380. {
  381. CString szName;
  382. GetName(szName);
  383. pFile->WriteString(szName);
  384. }
  385. /*
  386. * SaveElements - Write the list of elements to a binary save file
  387. *
  388. * History: a-jsari 10/29/97 Initial version
  389. */
  390. void CListViewFolder::SaveElements(CMSInfoFile *pFile)
  391. {
  392. CString szWriteString;
  393. MSIColumnSortType stColumn;
  394. unsigned iCol = GetColumns();
  395. DataComplexity dcAdvanced;
  396. CArray <unsigned, unsigned &> aColumnValues;
  397. pFile->WriteUnsignedInt(iCol);
  398. if (iCol == 0) return;
  399. while (iCol--) {
  400. unsigned uWidth;
  401. GetColumnTextAndWidth(iCol, szWriteString, uWidth);
  402. GetSortType(iCol, stColumn);
  403. dcAdvanced = GetColumnComplexity(iCol);
  404. if (stColumn == BYVALUE) {
  405. aColumnValues.Add(iCol);
  406. }
  407. pFile->WriteUnsignedInt(uWidth);
  408. pFile->WriteString(szWriteString);
  409. pFile->WriteUnsignedInt((unsigned) stColumn);
  410. pFile->WriteByte((BYTE)dcAdvanced);
  411. }
  412. unsigned cRow = GetRows();
  413. int wNextColumn = -1;
  414. unsigned iArray = 0;
  415. unsigned iRow;
  416. // Set wNextColumn to the next column which is sorted BYVALUE.
  417. // BYVALUE columns require that each row
  418. if (aColumnValues.GetSize() != 0)
  419. wNextColumn = aColumnValues[iArray++];
  420. pFile->WriteUnsignedInt(cRow);
  421. iCol = GetColumns();
  422. iRow = cRow;
  423. while (iRow--) {
  424. dcAdvanced = GetRowComplexity(iRow);
  425. pFile->WriteByte((BYTE)dcAdvanced);
  426. }
  427. // Iterate over columns, writing sort indices for BYVALUE columns.
  428. while (iCol--) {
  429. iRow = cRow;
  430. while (iRow--) {
  431. GetSubElement(iRow, iCol, szWriteString);
  432. pFile->WriteString(szWriteString);
  433. }
  434. if (wNextColumn == (int)iCol) {
  435. iRow = cRow;
  436. while (iRow--) {
  437. pFile->WriteUnsignedLong(GetSortIndex(iRow, iCol));
  438. }
  439. if (aColumnValues.GetSize() > (int)iArray)
  440. wNextColumn = aColumnValues[iArray++];
  441. }
  442. }
  443. }
  444. /*
  445. * FileSave - Save all elements associated with a CListViewFolder.
  446. * Automatically writes the correct version of the file, based
  447. * on the type of CMSInfoFile passed in.
  448. *
  449. * History: a-jsari 10/21/97 Initial version
  450. */
  451. BOOL CListViewFolder::FileSave(CMSInfoFile *pFile)
  452. {
  453. #if 0
  454. try {
  455. #endif
  456. // If our file is a text file, we must be writing a report file.
  457. // Call our report write functions.
  458. if (pFile->GetType() != CMSInfoFile::BINARY) {
  459. ReportWriteTitle(pFile);
  460. ReportWriteElements(pFile);
  461. } else {
  462. // Binary file, write binary data.
  463. SaveTitle(pFile);
  464. SaveElements(pFile);
  465. }
  466. #if 0
  467. }
  468. catch (...) {
  469. return FALSE;
  470. }
  471. #endif
  472. return TRUE;
  473. }
  474. /*
  475. * ReportWriteTitle - Write the title of the folder
  476. *
  477. * History: a-jsari 11/5/97 Initial version
  478. */
  479. void CListViewFolder::ReportWriteTitle(CMSInfoFile *pFile)
  480. {
  481. CString szWriteValue = _T("[");
  482. CString szName;
  483. GetName(szName);
  484. szWriteValue += szName + _T("]\r\n\r\n");
  485. pFile->WriteString(szWriteValue);
  486. }
  487. /*
  488. * ReportWriteElements - Write the Column headers and row and column data.
  489. *
  490. * History: a-jsari 10/29/97 Initial version
  491. */
  492. void CListViewFolder::ReportWriteElements(CMSInfoFile *pFile)
  493. {
  494. CString strWriteString;
  495. CString strTab = _T("\t");
  496. CString strNewLine = _T("\r\n");
  497. unsigned cColumns = GetColumns();
  498. CString strTest;
  499. CString strReplacement;
  500. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  501. VERIFY(strTest.LoadString(IDS_REPORT_CATEGORY));
  502. VERIFY(strReplacement.LoadString(IDS_REPORT_REPLACEMENT));
  503. for (unsigned iCol = 0 ; iCol < cColumns ; ++iCol) {
  504. unsigned uWidth;
  505. GetColumnTextAndWidth(iCol, strWriteString, uWidth);
  506. // Replace the category string with a more informative equivalent..
  507. if (!strTest.Compare(strWriteString))
  508. strWriteString = strReplacement;
  509. pFile->WriteString(strWriteString);
  510. if (iCol < cColumns - 1) {
  511. pFile->WriteString(strTab);
  512. }
  513. }
  514. pFile->WriteString(strNewLine);
  515. unsigned cRows = GetRows();
  516. for (unsigned iRow = 0 ; iRow < cRows ; ++iRow) {
  517. for (iCol = 0 ; iCol < cColumns ; ++iCol) {
  518. GetSubElement(iRow, iCol, strWriteString);
  519. pFile->WriteString(strWriteString);
  520. if (iCol < cColumns - 1) {
  521. pFile->WriteString(strTab);
  522. }
  523. }
  524. pFile->WriteString(strNewLine);
  525. }
  526. pFile->WriteString(strNewLine);
  527. }
  528. /*
  529. * CBufferDataSource - pFileSink is assumed to be a new'd CMSInfoFile
  530. * pointer. (See CMSInfoFile::CreateCBufferDataSource function,
  531. * the only constructor of CBufferDataSource.)
  532. *
  533. * History: a-jsari 10/17/97 Initial version
  534. */
  535. CBufferDataSource::CBufferDataSource(CMSInfoFile *pFileSink)
  536. :m_strUserName(_T("")), m_strMachine(_T("")), m_strCabDirectory(_T("")), CDataSource(_T("LocalMachine"))
  537. {
  538. if (pFileSink)
  539. m_strFileName = pFileSink->GetFileName();
  540. }
  541. /*
  542. * ~CBufferDataSource - Do nothing.
  543. *
  544. * History: a-jsari 10/17/97 Initial version
  545. */
  546. CBufferDataSource::~CBufferDataSource()
  547. {
  548. }
  549. /*
  550. * CreateDataSourceFromFile - Based on the magic number and version number,
  551. * return a new'd pointer to the appropriate CBufferDataSource.
  552. *
  553. * Note: The caller is responsible for deleting the pointer returned by
  554. * this function.
  555. *
  556. * History: a-jsari 10/20/97 Initial version
  557. */
  558. BOOL fCABOpened = FALSE;
  559. CBufferDataSource *CBufferDataSource::CreateDataSourceFromFile(LPCTSTR szFileName)
  560. {
  561. CBufferDataSource * pSource = NULL;
  562. // Enclose this in a scope so that the file will close when we've checked it.
  563. unsigned uMagicNumber;
  564. {
  565. try
  566. {
  567. CMSInfoFile FileWrapper(szFileName, CFile::modeRead | CFile::shareDenyWrite | CFile::typeBinary);
  568. // Check the first int in the file to see if it's the magic number
  569. // for a version 5 NFO file.
  570. FileWrapper.ReadUnsignedInt(uMagicNumber);
  571. if (uMagicNumber == CMSInfoFile::VERSION_500_MAGIC_NUMBER)
  572. {
  573. unsigned uVersion;
  574. FileWrapper.ReadUnsignedInt(uVersion);
  575. ASSERT(uVersion == 0x500);
  576. pSource = new CBufferV500DataSource(&FileWrapper);
  577. return pSource;
  578. }
  579. }
  580. catch (CFileException * e)
  581. {
  582. e->ReportError();
  583. e->Delete();
  584. return NULL;
  585. }
  586. catch (CFileFormatException * e)
  587. {
  588. CString strTitle, strError;
  589. strError.LoadString( IDS_CORRUPTEDFILE);
  590. strTitle.LoadString(IDS_DESCRIPTION);
  591. ::MessageBox( ::AfxGetMainWnd()->GetSafeHwnd(), strError, strTitle, MB_OK | MB_APPLMODAL);
  592. return NULL;
  593. }
  594. catch (...)
  595. {
  596. return NULL;
  597. }
  598. }
  599. // Next, check to see if this is a version 4.10 file. If it is, it
  600. // will be an OLE compound file with specific streams.
  601. IStorage * pStorage;
  602. DWORD grfMode = STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
  603. HRESULT hr = StgOpenStorage(szFileName, NULL, grfMode, NULL, 0, &pStorage);
  604. if (SUCCEEDED(hr))
  605. {
  606. OLECHAR FAR * szMSIStream = _T("MSInfo");
  607. IStream * pStream;
  608. if (SUCCEEDED(pStorage->OpenStream(szMSIStream, NULL, grfMode, 0, &pStream)))
  609. {
  610. // Things are looking good. This is a compound doc, and it has a
  611. // stream named MSInfo. Now we have to read the contents of the
  612. // MSInfo stream.
  613. pSource = new CBufferV410DataSource(pStorage, pStream);
  614. pStream->Release();
  615. pStorage->Release();
  616. return pSource;
  617. }
  618. pStorage->Release();
  619. }
  620. // It wasn't a 4.10 or a 5.0 NFO file. Check to see if it's a CAB file.
  621. //
  622. // Use of FileWrapper.FileHandle() is not recommended in case we have
  623. // a subclass of CFile which does not use file handles. This function
  624. // always uses standard file-based CFile pointers.
  625. //
  626. // There's a problem with using an MFC derived file class. The handle
  627. // in the class isn't recognized by the CAB code as belonging to a CAB
  628. // file. We need to open the file using the CRT file routines, and pass
  629. // that file handle.
  630. FILE *pfile = _wfopen(szFileName, _T("r"));
  631. if (pfile != NULL && ::isCabFile(pfile->_file, NULL))
  632. {
  633. fclose(pfile);
  634. // If our file is a cab file, explode it.
  635. CString strFile = szFileName;
  636. CString strCabDirectory;
  637. CString strDontDelete = _T("");
  638. USES_CONVERSION;
  639. ::GetCABExplodeDir(strCabDirectory, TRUE, strDontDelete);
  640. fCABOpened = ::OpenCABFile(strFile, strCabDirectory);
  641. // Get our NFO file's name.
  642. if (::FindFileToOpen(strCabDirectory, strFile) != FALSE)
  643. {
  644. pSource = CreateDataSourceFromFile(strFile);
  645. pSource->m_strCabDirectory = strCabDirectory;
  646. return pSource;
  647. }
  648. return NULL;
  649. }
  650. else
  651. {
  652. // Unidentified format.
  653. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  654. CString strError, strTitle;
  655. strTitle.LoadString(IDS_DESCRIPTION);
  656. strError.Format(IDS_UNRECOGNIZED_FILE, szFileName);
  657. ::MessageBox( ::AfxGetMainWnd()->GetSafeHwnd(), strError, strTitle, MB_OK);
  658. pSource = NULL;
  659. }
  660. return pSource;
  661. }
  662. /*
  663. * FileName -
  664. *
  665. * History: a-jsari 11/17/97 Initial version
  666. */
  667. LPCTSTR CBufferDataSource::FileName()
  668. {
  669. return m_strFileName;
  670. }
  671. /*
  672. * CBufferSortData - Construct our sort object
  673. *
  674. * History: a-jsari 12/1/97 Initial version
  675. */
  676. CBufferSortData::CBufferSortData()
  677. :m_cRows(0), m_cColumns(0)
  678. {
  679. }
  680. /*
  681. * ~CBufferSortData - Do-nothing destructor
  682. *
  683. * History: a-jsari 12/1/97 Initial version.
  684. */
  685. CBufferSortData::~CBufferSortData()
  686. {
  687. }
  688. /*
  689. * SetSortType - Set the sort type for an iColumn
  690. *
  691. * History: a-jsari 12/1/97 Initial version.
  692. */
  693. BOOL CBufferSortData::SetSortType(unsigned iColumn, unsigned stColumn)
  694. {
  695. if (stColumn > BYVALUE) return FALSE;
  696. m_SortTypes[iColumn] = (MSIColumnSortType) stColumn;
  697. if (stColumn == BYVALUE) {
  698. m_ValueColumns.Add(iColumn);
  699. }
  700. return TRUE;
  701. }
  702. /*
  703. * GetSortType - Return the sort type for iColumn
  704. *
  705. * History: a-jsari 12/1/97 Initial version
  706. */
  707. BOOL CBufferSortData::GetSortType(unsigned iColumn, MSIColumnSortType &stColumn) const
  708. {
  709. stColumn = m_SortTypes[iColumn];
  710. return TRUE;
  711. }
  712. /*
  713. * ValueIndexFromColumn - Return the sparse array index corresponding
  714. * to the column index passed in.
  715. *
  716. * History: a-jsari 12/1/97 Initial version
  717. */
  718. int CBufferSortData::ValueIndexFromColumn(unsigned iColumn) const
  719. {
  720. int iType = (int)m_ValueColumns.GetSize();
  721. while (iType--) {
  722. if (m_ValueColumns[iType] == iColumn) break;
  723. }
  724. ASSERT(iType >= 0);
  725. return iType;
  726. }
  727. /*
  728. * ReadSortValues - Read SortValue values from the pFile for iColumn
  729. *
  730. * History: a-jsari 12/1/97 Initial version
  731. */
  732. BOOL CBufferSortData::ReadSortValues(CMSInfoFile *pFile, unsigned iColumn)
  733. {
  734. // There is only data to be read if the column is sorted by value.
  735. if (m_SortTypes[iColumn] == BYVALUE) {
  736. int iType = ValueIndexFromColumn(iColumn);
  737. unsigned iRow = m_cRows;
  738. while (iRow--) {
  739. pFile->ReadUnsignedLong(m_dwSortIndices[iType][iRow]);
  740. }
  741. }
  742. return TRUE;
  743. }
  744. /*
  745. * GetSortValue - Return the sort value corresponding with iRow and iColumn
  746. *
  747. * History: a-jsari 12/1/97 Initial version
  748. */
  749. DWORD CBufferSortData::GetSortValue(unsigned iRow, unsigned iColumn) const
  750. {
  751. // No value is necessary if we are not sorting based on Sort Values.
  752. if (m_SortTypes[iColumn] != BYVALUE) return 0;
  753. // Every BYVALUE type should have data.
  754. int iType = ValueIndexFromColumn(iColumn);
  755. return m_dwSortIndices[iType][iRow];
  756. }
  757. /*
  758. * SetColumns - Set the number of columns of data we are sorting over.
  759. *
  760. * History: a-jsari 12/1/97 Initial version.
  761. */
  762. BOOL CBufferSortData::SetColumns(unsigned cColumns)
  763. {
  764. m_SortTypes.SetSize(cColumns);
  765. m_cColumns = cColumns;
  766. return TRUE;
  767. }
  768. /*
  769. * SetRows - Set the number of rows we are sorting over.
  770. *
  771. * History: a-jsari 12/1/97 Initial version.
  772. */
  773. BOOL CBufferSortData::SetRows(unsigned cRows)
  774. {
  775. m_cRows = cRows;
  776. unsigned iColumn = (unsigned)m_ValueColumns.GetSize();
  777. m_dwSortIndices.SetSize(iColumn);
  778. while (iColumn--) {
  779. m_dwSortIndices[iColumn].SetSize(cRows);
  780. }
  781. return TRUE;
  782. }
  783. /*
  784. * CBufferFolder - Trivial constructor
  785. *
  786. * History: a-jsari 10/17/97 Initial version
  787. */
  788. CBufferFolder::CBufferFolder(CDataSource *pDataSource, CFolder *pParent)
  789. :CListViewFolder(pDataSource, pParent), m_cRows(0), m_cColumns(0)
  790. {
  791. }
  792. /*
  793. * ~CBufferFolder - Do-nothing destructor.
  794. *
  795. * History: a-jsari 10/17/97 Initial version
  796. */
  797. CBufferFolder::~CBufferFolder()
  798. {
  799. }
  800. /*
  801. * GetColumnTextAndWidth - Return formatting information for the wCol'th column.
  802. *
  803. * History: a-jsari 10/17/97 Initial version
  804. */
  805. BOOL CBufferFolder::GetColumnTextAndWidth(unsigned wCol, CString &szName, unsigned &wWidth) const
  806. {
  807. // Adjust to the Basic-indexed column.
  808. if (GetComplexity() == BASIC)
  809. wCol = BasicColumn(wCol);
  810. szName = m_szColumns[(int)wCol];
  811. wWidth = m_uWidths[wCol];
  812. return TRUE;
  813. }
  814. /*
  815. * BasicColumn - Return the index into the advanced columns of the basic column
  816. * index iBasicColumn
  817. *
  818. * History: a-jsari 12/23/97 Initial version
  819. */
  820. unsigned CBufferFolder::BasicColumn(unsigned iBasicColumn) const
  821. {
  822. ASSERT(GetComplexity() == BASIC);
  823. for (unsigned iColumn = 0 ; iColumn < iBasicColumn ; ++iColumn) {
  824. // If any of our columns are advanced, skip them.
  825. if (m_dcColumns[iColumn] == ADVANCED)
  826. ++iBasicColumn;
  827. }
  828. ASSERT(iBasicColumn < m_cColumns);
  829. return iBasicColumn;
  830. }
  831. /*
  832. * BasicRow - Return the index into the advanced rows of the basic row index
  833. * iBasicRow
  834. *
  835. * History: a-jsari 12/23/97 Initial version
  836. */
  837. unsigned CBufferFolder::BasicRow(unsigned iBasicRow) const
  838. {
  839. ASSERT(GetComplexity() == BASIC);
  840. for (unsigned iRow = 0 ; iRow < iBasicRow ; ++iRow) {
  841. // If any of our rows are advanced, skip them.
  842. if (m_dcRows[iRow] == ADVANCED)
  843. ++iBasicRow;
  844. }
  845. ASSERT(iBasicRow < m_cRows);
  846. return iBasicRow;
  847. }
  848. /*
  849. * GetColumns - Read the columns value from the current file.
  850. *
  851. * History: a-jsari 10/17/97 Initial version
  852. */
  853. unsigned CBufferFolder::GetColumns() const
  854. {
  855. // If Complexity is advanced, the number of columns is equal to our stored value.
  856. if (GetComplexity() == ADVANCED)
  857. return m_cColumns;
  858. // We are in basic mode; remove all advanced columns.
  859. unsigned cColumns = m_cColumns;
  860. unsigned iColumn = m_cColumns;
  861. while (iColumn--) {
  862. if (m_dcColumns[iColumn] == ADVANCED) --cColumns;
  863. }
  864. return cColumns;
  865. }
  866. /*
  867. * GetRows - Read the rows value from the current file
  868. *
  869. * History: a-jsari 10/17/97 Initial version
  870. */
  871. unsigned CBufferFolder::GetRows() const
  872. {
  873. // If Complexity is advanced, the number of rows is equal to our stored value.
  874. if (GetComplexity() == ADVANCED)
  875. return m_cRows;
  876. // Otherwise, we are basic; remove all Advanced rows.
  877. unsigned cRows = m_cRows;
  878. unsigned iRow = m_cRows;
  879. while (iRow--) {
  880. if (m_dcRows[iRow] == ADVANCED) --cRows;
  881. }
  882. return cRows;
  883. }
  884. /*
  885. * GetName - Return the category's name.
  886. *
  887. * History: a-jsari 10/27/97 Initial version
  888. */
  889. BOOL CBufferFolder::GetName(CString &szName) const
  890. {
  891. szName = m_szName;
  892. return TRUE;
  893. }
  894. /*
  895. * GetSubElement - Return the Element stored at iRow and iCol.
  896. *
  897. * History: a-jsari 10/27/97 Initial version
  898. */
  899. BOOL CBufferFolder::GetSubElement(unsigned iRow, unsigned iCol, CString &szName) const
  900. {
  901. if (GetComplexity() == BASIC) {
  902. iRow = BasicRow(iRow);
  903. iCol = BasicColumn(iCol);
  904. }
  905. szName = m_szElements[iRow][iCol];
  906. return TRUE;
  907. }
  908. /*
  909. * GetSortType - Return the sort method for the column numbered iColumn
  910. * in this folder.
  911. *
  912. * History: a-jsari 12/1/97 Initial version
  913. */
  914. BOOL CBufferFolder::GetSortType(unsigned iColumn, MSIColumnSortType &stColumn) const
  915. {
  916. if (GetComplexity() == BASIC) {
  917. iColumn = BasicColumn(iColumn);
  918. }
  919. m_SortData.GetSortType(iColumn, stColumn);
  920. return TRUE;
  921. }
  922. /*
  923. * GetSortIndex - Return the iColumn numbered column's internal sort index
  924. * for the element at row iRow compared to other rows in this column.
  925. *
  926. * History: a-jsari 12/1/97 Initial version
  927. */
  928. DWORD CBufferFolder::GetSortIndex(unsigned iRow, unsigned iColumn) const
  929. {
  930. if (GetComplexity() == BASIC) {
  931. iColumn = BasicColumn(iColumn);
  932. iRow = BasicRow(iRow);
  933. }
  934. return m_SortData.GetSortValue( iRow, iColumn);
  935. }
  936. /*
  937. * GetColumnComplexity - Return the complexity of the iColumn'th column
  938. *
  939. * History: a-jsari 12/23/97 Initial version
  940. */
  941. DataComplexity CBufferFolder::GetColumnComplexity(unsigned iColumn)
  942. {
  943. // We are only concerned with Complexity when we are saving the data
  944. // and we must be in Advanced mode to save.
  945. ASSERT(GetComplexity() == ADVANCED);
  946. return m_dcColumns[iColumn];
  947. }
  948. /*
  949. * GetRowComplexity - Return complexity of this folder's iRow'th row.
  950. *
  951. * History: a-jsari 12/23/97 Initial version
  952. */
  953. DataComplexity CBufferFolder::GetRowComplexity(unsigned iRow)
  954. {
  955. // We are only concerned with Complexity when we are saving the data
  956. // and we must be in Advanced mode to do a save.
  957. ASSERT(GetComplexity() == ADVANCED);
  958. return m_dcRows[iRow];
  959. }