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.

424 lines
12 KiB

  1. // File5Src.cpp Implementation of Version 5.00 data file methods.
  2. //
  3. // Copyright (c) 1998-1999 Microsoft Corporation
  4. #include "DataSrc.h"
  5. #ifndef IDS_V500FILENODE
  6. #include "resource.h"
  7. #endif
  8. #ifndef _UNICODE
  9. #define _ttoupper toupper
  10. #define _ttolower tolower
  11. #define _tislower islower
  12. #define _tisupper isupper
  13. #else
  14. #define _ttoupper towupper
  15. #define _ttolower towlower
  16. #define _tislower iswlower
  17. #define _tisupper iswupper
  18. #endif
  19. /*
  20. * CBufferV500DataSource - Construct the DataSource from a file, which mostly
  21. * means constructing all the folder.
  22. *
  23. * History: a-jsari 10/17/97 Initial version
  24. */
  25. CBufferV500DataSource::CBufferV500DataSource(CMSInfoFile *pFileSink)
  26. :CBufferDataSource(pFileSink)
  27. {
  28. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  29. CBufferFolder *pFolder;
  30. CBufferFolder *pLast;
  31. unsigned uReadCase;
  32. try {
  33. ReadHeader(pFileSink);
  34. m_szFileName = pFileSink->GetFileName();
  35. unsigned cFolders = 0;
  36. ReadFolder(pFileSink, (CFolder * &)pLast, NULL);
  37. // CFolders read by our ReadFolder are guaranteed to be CBufferFolder's.
  38. m_RootFolder = pLast;
  39. do {
  40. pFileSink->ReadUnsignedInt(uReadCase);
  41. // Only switch off the flags, not the extended bits.
  42. switch (uReadCase & CBufferV500DataSource::MASK) {
  43. case CBufferV500DataSource::CHILD:
  44. ReadFolder(pFileSink, (CFolder * &)(pFolder), pLast);
  45. ASSERT(pLast->m_ChildFolder == NULL);
  46. pLast->m_ChildFolder = pFolder;
  47. break;
  48. case CBufferV500DataSource::NEXT:
  49. ReadFolder(pFileSink, (CFolder * &)(pFolder), pLast->GetParentNode());
  50. // Attach the folder to the tree.
  51. pLast->m_NextFolder = pFolder;
  52. break;
  53. case CBufferV500DataSource::PARENT:
  54. unsigned iDepth;
  55. // Ascend to the right level in the tree.
  56. iDepth = (uReadCase & ~CBufferV500DataSource::MASK);
  57. while (iDepth--) {
  58. pLast = (CBufferFolder *)pLast->GetParentNode();
  59. }
  60. ReadFolder(pFileSink, (CFolder * &)pFolder, pLast->GetParentNode());
  61. // Now attach the folder as a sibling at the right level.
  62. while (pLast->m_NextFolder != NULL) {
  63. pLast = (CBufferFolder *)pLast->m_NextFolder;
  64. }
  65. pLast->m_NextFolder = pFolder;
  66. break;
  67. case CBufferV500DataSource::END:
  68. return;
  69. break;
  70. default:
  71. ThrowFileFormatException();
  72. break;
  73. }
  74. pLast = pFolder;
  75. // Never intended to exit until END key is read or an exception occurs.
  76. } while (TRUE);
  77. }
  78. catch (CException *e) {
  79. CString strMessage, strTitle;
  80. strMessage.LoadString( IDS_CORRUPTEDFILE);
  81. strTitle.LoadString( IDS_DESCRIPTION);
  82. ::MessageBox( ::AfxGetMainWnd()->GetSafeHwnd(), strMessage, strTitle, MB_OK);
  83. delete pFolder;
  84. throw e;
  85. }
  86. catch (...) {
  87. ASSERT(FALSE);
  88. }
  89. }
  90. /*
  91. * ~CBufferDataSource - Destructor. Does nothing; the file created here
  92. * is deleted in the CDataSource destructor.
  93. *
  94. * History: a-jsari 10/17/97 Initial version
  95. */
  96. CBufferV500DataSource::~CBufferV500DataSource()
  97. {
  98. }
  99. /*
  100. * GetNodeName - Return in strName the formatted name for the root node.
  101. *
  102. * History: a-jsari 1/16/98 Initial version
  103. */
  104. BOOL CBufferV500DataSource::GetNodeName(CString &strName)
  105. {
  106. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  107. CString strFileName = FileName();
  108. LPCTSTR szFilePart = ::_tcsrchr((LPCTSTR)strFileName, '\\');
  109. ASSERT(szFilePart != NULL);
  110. if (szFilePart == NULL)
  111. szFilePart = strFileName;
  112. else
  113. ++szFilePart;
  114. strName.Format(IDS_V500FILENODE, szFilePart);
  115. return TRUE;
  116. }
  117. /*
  118. * ReadElements - Read all of the element data into our buffers.
  119. *
  120. * History: a-jsari 11/3/97 Initial version
  121. */
  122. void CBufferV500DataSource::ReadElements(CMSInfoFile *pFileSink, CBufferFolder *pFolder)
  123. {
  124. pFileSink->ReadUnsignedInt(pFolder->m_cColumns);
  125. if (pFolder->m_cColumns == 0) {
  126. pFolder->m_cRows = 0;
  127. return;
  128. }
  129. unsigned iColumn = pFolder->m_cColumns;
  130. BYTE bComplexity;
  131. DataComplexity dcComplexity;
  132. pFolder->m_uWidths.SetSize(iColumn);
  133. pFolder->m_szColumns.SetSize(iColumn);
  134. pFolder->m_SortData.SetColumns(iColumn);
  135. while (iColumn--) {
  136. unsigned wSortType;
  137. pFileSink->ReadUnsignedInt(pFolder->m_uWidths[iColumn]);
  138. pFileSink->ReadString(pFolder->m_szColumns[iColumn]);
  139. pFileSink->ReadUnsignedInt(wSortType);
  140. pFileSink->ReadByte(bComplexity);
  141. dcComplexity = (DataComplexity)bComplexity;
  142. if (dcComplexity != BASIC && dcComplexity != ADVANCED)
  143. dcComplexity = BASIC;
  144. pFolder->m_dcColumns.SetAtGrow(iColumn, dcComplexity);
  145. if (pFolder->m_SortData.SetSortType(iColumn, wSortType) == FALSE)
  146. if (pFolder->m_SortData.SetSortType(iColumn, NOSORT) == FALSE)
  147. ::ThrowFileFormatException();
  148. }
  149. pFileSink->ReadUnsignedInt(pFolder->m_cRows);
  150. pFolder->m_szElements.SetSize(pFolder->m_cRows);
  151. pFolder->m_SortData.SetRows(pFolder->m_cRows);
  152. iColumn = pFolder->m_cColumns;
  153. unsigned iRow = pFolder->m_cRows;
  154. // Size the rows.
  155. while (iRow--) {
  156. pFolder->m_szElements[iRow].SetSize(pFolder->m_cColumns);
  157. pFileSink->ReadByte(bComplexity);
  158. dcComplexity = (DataComplexity)bComplexity;
  159. pFolder->m_dcRows.SetAtGrow(iRow, dcComplexity);
  160. }
  161. while (iColumn--) {
  162. iRow = pFolder->m_cRows;
  163. while (iRow--) {
  164. pFileSink->ReadString(pFolder->m_szElements[iRow][iColumn]);
  165. }
  166. pFolder->m_SortData.ReadSortValues(pFileSink, iColumn);
  167. }
  168. }
  169. /*
  170. * ReadFolder - Reads the data of a folder
  171. *
  172. * History: a-jsari 10/17/97 Initial version
  173. */
  174. void CBufferV500DataSource::ReadFolder(CMSInfoFile *pFileSink, CFolder * &pFolder, CFolder *pParentFolder)
  175. {
  176. CBufferFolder *pBufferFolder = new CBufferFolder(this, pParentFolder);
  177. if (pBufferFolder == NULL) ::AfxThrowMemoryException();
  178. pFileSink->ReadString(pBufferFolder->m_szName);
  179. ReadElements(pFileSink, pBufferFolder);
  180. pFolder = pBufferFolder;
  181. }
  182. /*
  183. * ReadHeader - Read header information for this buffer
  184. *
  185. * History: a-jsari 10/17/97 Initial version
  186. */
  187. void CBufferV500DataSource::ReadHeader(CMSInfoFile *pFileSink)
  188. {
  189. LONG l;
  190. ASSERT(pFileSink != NULL);
  191. pFileSink->ReadLong(l); // Save time.
  192. m_tsSaveTime = (ULONG) l;
  193. #ifdef _WIN64
  194. pFileSink->ReadLong(l); // Save time.
  195. m_tsSaveTime |= ((time_t) l) << 32;
  196. #endif
  197. CString szDummy;
  198. pFileSink->ReadString(szDummy); // Network machine name
  199. pFileSink->ReadString(szDummy); // Network user name
  200. }
  201. /*
  202. * VerifyFileVersion - Read the top two unsigned ints, and verify that they
  203. * have the expected values.
  204. *
  205. * History: a-jsari 11/23/97 Initial version
  206. */
  207. BOOL CBufferV500DataSource::VerifyFileVersion(CMSInfoFile *pFile)
  208. {
  209. UINT uVersion;
  210. pFile->ReadUnsignedInt(uVersion);
  211. ASSERT(uVersion == CMSInfoFile::VERSION_500_MAGIC_NUMBER);
  212. if (uVersion != CMSInfoFile::VERSION_500_MAGIC_NUMBER)
  213. return FALSE;
  214. pFile->ReadUnsignedInt(uVersion);
  215. ASSERT(uVersion == 0x0500);
  216. return (uVersion == 0x0500);
  217. }
  218. /*
  219. * Save - Save initialization information to the IStream passed in.
  220. *
  221. * History: a-jsari 11/13/97 Initial version
  222. */
  223. HRESULT CBufferV500DataSource::Save(IStream *pStm)
  224. {
  225. unsigned wValue;
  226. ULONG dwSize;
  227. HRESULT hResult;
  228. USES_CONVERSION;
  229. do {
  230. wValue = GetType();
  231. hResult = pStm->Write(&wValue, sizeof(wValue), &dwSize);
  232. ASSERT(SUCCEEDED(hResult) && (dwSize == sizeof(wValue)));
  233. if (FAILED(hResult)) break;
  234. wValue = m_szFileName.GetLength();
  235. hResult = pStm->Write(&wValue, sizeof(wValue), &dwSize);
  236. ASSERT(SUCCEEDED(hResult) && (dwSize == sizeof(wValue)));
  237. if (FAILED(hResult)) break;
  238. wValue *= sizeof(WCHAR);
  239. // Save the file name as a wide character string to avoid different
  240. // types of save filenames.
  241. hResult = pStm->Write(T2CW((LPCTSTR)m_szFileName), wValue, &dwSize);
  242. ASSERT(SUCCEEDED(hResult) && (dwSize == wValue));
  243. } while (FALSE);
  244. return hResult;
  245. }
  246. /*
  247. * CaseInsensitiveMatch - Compare two TCHARs without regard to case.
  248. *
  249. * History: a-jsari 12/31/97 Initial version
  250. */
  251. static inline BOOL CaseInsensitiveMatch(TCHAR aChar, TCHAR bChar)
  252. {
  253. if (::_tisupper(aChar))
  254. aChar = ::_ttolower(aChar);
  255. #if 0
  256. // We've already guaranteed that the second string is all lowercase.
  257. if (::_tisupper(bChar))
  258. bChar = ::_ttolower(bChar);
  259. #endif
  260. return aChar == bChar;
  261. }
  262. /*
  263. * FindCaseInsensitive - Like CString::Find, but not case sensitive.
  264. *
  265. * History: a-jsari 12/31/97 Initial version
  266. */
  267. static inline int FindCaseInsensitive(LPCTSTR szSearch, LPCTSTR szMatch)
  268. {
  269. int iString;
  270. // Set the number of iterations through the string: the number of
  271. // substrings we'll need to test.
  272. int iCount = ::_tcslen(szSearch)-::_tcslen(szMatch)+1;
  273. // Set the size so that we can return the proper index when we
  274. // successfully find the substring.
  275. int nSize = iCount-1;
  276. // We can't find a substring larger than our search string.
  277. if (iCount <= 0) return -1;
  278. while (iCount--) {
  279. iString = 0;
  280. while (CaseInsensitiveMatch(szSearch[iString], szMatch[iString])) {
  281. if (szMatch[++iString] == 0) {
  282. // End of match string; return index.
  283. return nSize-iCount;
  284. }
  285. }
  286. // Increment our search string.
  287. ++szSearch;
  288. }
  289. // End of search string; failure.
  290. return -1;
  291. }
  292. /*
  293. * FolderContains - Test to see if the fCurrent folder contains the substring
  294. *
  295. * History: a-jsari 12/16/97 Initial version.
  296. */
  297. BOOL CBufferV500DataSource::FolderContains(const CListViewFolder *fCurrent,
  298. const CString &strSearch, int &wRow, long lFolderOptions)
  299. {
  300. CString strName;
  301. int wRowMax = fCurrent->GetRows();
  302. unsigned uColMax = fCurrent->GetColumns();
  303. CString strLowerSearch = strSearch;
  304. strLowerSearch.MakeLower();
  305. fCurrent->GetName(strName);
  306. if (wRow == -1) {
  307. if (FindCaseInsensitive(strName, strLowerSearch) != -1)
  308. return TRUE;
  309. wRow = 0;
  310. }
  311. // Don't check the data elements if we are only checking categories.
  312. if ((lFolderOptions & FIND_OPTION_CATEGORY_ONLY) == FIND_OPTION_CATEGORY_ONLY)
  313. return FALSE;
  314. for ( ; wRow < wRowMax ; ++wRow) {
  315. unsigned iCol = uColMax;
  316. while (iCol--) {
  317. fCurrent->GetSubElement(wRow, iCol, strName);
  318. if (FindCaseInsensitive(strName, strLowerSearch) != -1) {
  319. return TRUE;
  320. }
  321. if (FindStopped() == TRUE)
  322. return FALSE;
  323. }
  324. }
  325. return FALSE;
  326. }
  327. /*
  328. * Find - Traverse the tree looking for a match.
  329. *
  330. * History: a-jsari 12/11/97 Initial version
  331. */
  332. BOOL CBufferV500DataSource::Find(const CString &strSearch, long lFindOptions)
  333. {
  334. // Record our depth in the tree so we don't go above our initial search
  335. // category when ascending.
  336. static int iDepth;
  337. CFolder *pfNext;
  338. CString strName;
  339. ASSERT(strSearch.GetLength() != 0);
  340. StartSearch();
  341. if (m_pfLast == NULL || (lFindOptions & FIND_OPTION_REPEAT_SEARCH) == 0) {
  342. // If we are searching all categories, reset to the root, otherwise
  343. // our root is set for us.
  344. if ((lFindOptions & FIND_OPTION_ONE_CATEGORY) == 0)
  345. m_pfLast = GetRootNode();
  346. iDepth = 0;
  347. } else
  348. ++m_iLine;
  349. while (m_pfLast) {
  350. if (FolderContains(dynamic_cast<CListViewFolder *>(m_pfLast),
  351. strSearch, m_iLine, lFindOptions)) {
  352. m_pfLast->InternalName(m_strPath);
  353. StopSearch();
  354. return TRUE;
  355. }
  356. else if (FindStopped() == TRUE)
  357. return FALSE;
  358. // For the next folder searched, start with the folder name
  359. m_iLine = -1;
  360. do {
  361. // Depth-first
  362. pfNext = m_pfLast->GetChildNode();
  363. if (pfNext != NULL) {
  364. ++iDepth;
  365. break;
  366. }
  367. pfNext = m_pfLast->GetNextNode();
  368. if (pfNext != NULL) break;
  369. pfNext = m_pfLast->GetParentNode();
  370. if (pfNext) {
  371. // Check that we don't ascend back above our current category.
  372. if (--iDepth == 0 && (lFindOptions & FIND_OPTION_ONE_CATEGORY)
  373. == FIND_OPTION_ONE_CATEGORY) {
  374. pfNext = NULL;
  375. break;
  376. }
  377. pfNext = pfNext->GetNextNode();
  378. }
  379. } while (FALSE);
  380. m_pfLast = pfNext;
  381. }
  382. // No matches; restart the next search at the beginning.
  383. m_pfLast = NULL;
  384. return FALSE;
  385. }
  386. #if 0
  387. /*
  388. * StopSearch - Ends the current search.
  389. *
  390. * History: a-jsari 1/19/98 Initial version
  391. */
  392. BOOL CBufferV500DataSource::StopSearch()
  393. {
  394. if (m_fSearching == TRUE) {
  395. m_fSearching = FALSE;
  396. return TRUE;
  397. }
  398. return FALSE;
  399. }
  400. #endif