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.

579 lines
15 KiB

  1. //
  2. // MODULE: FS.cpp
  3. //
  4. // PURPOSE: Implementation of classes needed in order to use CHM files.
  5. //
  6. // COMPANY: This file was created by Microsoft and should not be changed by Saltmine
  7. // except for comments
  8. //
  9. // ORIGINAL DATE: 1997.
  10. //
  11. // NOTES:
  12. //
  13. // Version Date By Comments
  14. //--------------------------------------------------------------------
  15. // V3.1 01-18-99 JM This header added. Added include of apgtsstr.h since
  16. // we are compiling in a non-MFC environment.
  17. //
  18. // Copyright (C) 1997 Microsoft Corporation. All rights reserved.
  19. #include "stdafx.h"
  20. // to avoid linker error related to undefined GUIDs
  21. #include "initguid.h"
  22. #include "fs.h"
  23. #include "apgtsstr.h"
  24. #pragma data_seg(".text", "CODE")
  25. static const WCHAR txtwUncompressed[] = L"uncompressed";
  26. #pragma data_seg()
  27. // returns poinder inside pszPath string that points to file name
  28. // for example in "d:\Tshooter\http\lan.chm\lan.htm" it points
  29. // to "lan.htm"
  30. LPCSTR FindFilePortion(LPCSTR pszPath)
  31. {
  32. int index =0;
  33. CString path(pszPath);
  34. if (-1 == (index = path.ReverseFind(_T('\\'))))
  35. {
  36. if (-1 == (index = path.ReverseFind(_T('/'))))
  37. index = 0;
  38. else
  39. index += sizeof(_T('/'));
  40. }
  41. else
  42. index += sizeof(_T('\\'));
  43. return pszPath + index;
  44. }
  45. CFileSystem::CFileSystem()
  46. {
  47. m_pITStorage = NULL;
  48. m_pStorage = NULL;
  49. m_szPathName[0] = 0;
  50. }
  51. CFileSystem::~CFileSystem()
  52. {
  53. ReleaseObjPtr(m_pStorage);
  54. ReleaseObjPtr(m_pITStorage);
  55. }
  56. HRESULT CFileSystem::Init(void)
  57. {
  58. if (! m_pITStorage) {
  59. IClassFactory* pICFITStorage;
  60. HRESULT hr = CoGetClassObject(CLSID_ITStorage, CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory, (void **) &pICFITStorage);
  61. if (!SUCCEEDED(hr))
  62. return hr;
  63. hr = pICFITStorage->CreateInstance(NULL, IID_ITStorage,(void **) &m_pITStorage);
  64. ReleaseObjPtr( pICFITStorage );
  65. if (!SUCCEEDED(hr))
  66. return hr;
  67. }
  68. return S_OK;
  69. }
  70. typedef struct tagITSControlData
  71. {
  72. UINT cdwFollowing; // Must be 6 or 13
  73. DWORD cdwITFS_Control; // Must be 5
  74. DWORD dwMagicITS; // Must be MAGIC_ITSFS_CONTROL (see below)
  75. DWORD dwVersionITS; // Must be 1
  76. DWORD cbDirectoryBlock; // Size in bytes of directory blocks (Default is 8192)
  77. DWORD cMinCacheEntries; // Least upper bound on the number of directory blocks
  78. // which we'll cache in memory. (Default is 20)
  79. DWORD fFlags; // Control bit flags (see below).
  80. // Default value is fDefaultIsCompression.
  81. UINT cdwControlData; // Must be 6
  82. DWORD dwLZXMagic; // Must be LZX_MAGIC (see below)
  83. DWORD dwVersion; // Must be 2
  84. DWORD dwMulResetBlock; // Number of blocks between compression resets. (Default: 4)
  85. DWORD dwMulWindowSize; // Maximum number of blocks kept in data history (Default: 4)
  86. DWORD dwMulSecondPartition; // Granularity in blocks of sliding history(Default: 2)
  87. DWORD dwOptions; // Option flags (Default: fOptimizeCodeStreams)
  88. } ITCD;
  89. HRESULT CFileSystem::Create( PCSTR pszPathName )
  90. {
  91. HRESULT hr;
  92. ITCD itcd;
  93. if (! m_pITStorage || m_pStorage )
  94. return E_FAIL;
  95. itcd.cdwFollowing = 13;
  96. itcd.cdwITFS_Control = 5;
  97. itcd.dwMagicITS = MAGIC_ITSFS_CONTROL;
  98. itcd.dwVersionITS = 1;
  99. itcd.cbDirectoryBlock = 4096; // default = 8192
  100. itcd.cMinCacheEntries = 10; // default = 20
  101. itcd.fFlags = 1; // 0 == Uncompressed, 1 == Compressed.
  102. itcd.cdwControlData = 6;
  103. itcd.dwLZXMagic = LZX_MAGIC;
  104. itcd.dwVersion = 2;
  105. itcd.dwMulResetBlock = 2; // Default = 4
  106. itcd.dwMulWindowSize = 2; // Default = 4
  107. itcd.dwMulSecondPartition = 1; // Default = 2
  108. itcd.dwOptions = 0; // Default = fOptimizeCodeStreams
  109. m_pITStorage->SetControlData(PITS_Control_Data(&itcd));
  110. WCHAR wsz[MAX_PATH];
  111. MultiByteToWideChar(CP_ACP, 0, pszPathName, -1, (PWSTR) wsz, MAX_PATH);
  112. hr = m_pITStorage->StgCreateDocfile( (LPCWSTR) wsz, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT, 0, &m_pStorage);
  113. if (!SUCCEEDED(hr)) {
  114. return hr;
  115. }
  116. strcpy( (LPSTR) m_szPathName, pszPathName );
  117. return S_OK;
  118. }
  119. // NOTE: The below function is required for the ITIR full-text indexer to
  120. // initialize. I'm working to find out why this is and what impact
  121. // the below has on the file system.
  122. //
  123. HRESULT CFileSystem::CreateUncompressed( PCSTR pszPathName )
  124. {
  125. HRESULT hr;
  126. ITCD itcd;
  127. if (! m_pITStorage || m_pStorage )
  128. return E_FAIL;
  129. itcd.cdwFollowing = 6;
  130. itcd.cdwITFS_Control = 5;
  131. itcd.dwMagicITS = MAGIC_ITSFS_CONTROL;
  132. itcd.dwVersionITS = 1;
  133. itcd.cbDirectoryBlock = 8192; // default = 8192
  134. itcd.cMinCacheEntries = 20; // default = 20
  135. itcd.fFlags = 0; // 0 == Uncompressed, 1 == Compressed.
  136. m_pITStorage->SetControlData(PITS_Control_Data(&itcd));
  137. WCHAR wsz[MAX_PATH];
  138. MultiByteToWideChar(CP_ACP, 0, pszPathName, -1, (PWSTR) wsz, MAX_PATH);
  139. hr = m_pITStorage->StgCreateDocfile( (LPCWSTR) wsz, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT, 0, &m_pStorage);
  140. if (!SUCCEEDED(hr)) {
  141. return hr;
  142. }
  143. strcpy( (LPSTR) m_szPathName, pszPathName );
  144. return S_OK;
  145. }
  146. HRESULT CFileSystem::Open(PCSTR pszPathName, DWORD dwAccess)
  147. {
  148. HRESULT hr = S_OK;
  149. if (! m_pITStorage || m_pStorage )
  150. return E_FAIL;
  151. // force access modes
  152. if( (dwAccess & STGM_WRITE) || (dwAccess & STGM_READWRITE) ) {
  153. dwAccess &= ~STGM_WRITE;
  154. dwAccess |= STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
  155. }
  156. else
  157. dwAccess |= STGM_SHARE_DENY_WRITE;
  158. WCHAR wsz[MAX_PATH];
  159. MultiByteToWideChar(CP_ACP, 0, pszPathName, -1, (PWSTR) wsz, MAX_PATH);
  160. hr = m_pITStorage->StgOpenStorage( (LPCWSTR) wsz, NULL, dwAccess, NULL, 0, &m_pStorage);
  161. if (!SUCCEEDED(hr)) {
  162. return hr;
  163. }
  164. strcpy( (LPSTR) m_szPathName, pszPathName );
  165. return hr;
  166. }
  167. HRESULT CFileSystem::Compact(LPCSTR pszPathName)
  168. {
  169. WCHAR wszPathName[MAX_PATH];
  170. //[BC-03022001] - changed 5th param to MultiByteToWideChar to number of chars from number of bytes.
  171. MultiByteToWideChar(CP_ACP, 0, pszPathName, -1, wszPathName, sizeof(wszPathName)/sizeof(WCHAR));
  172. m_pITStorage->Compact(wszPathName, COMPACT_DATA_AND_PATH);
  173. return S_OK;
  174. }
  175. HRESULT CFileSystem::Close()
  176. {
  177. ReleaseObjPtr(m_pStorage);
  178. return S_OK;
  179. }
  180. //////////////////////////////////////////////////////////////////////////////////////////////
  181. //
  182. // Here are a set of "sub" file I/O calls.
  183. //
  184. //
  185. CSubFileSystem::CSubFileSystem(CFileSystem* pFS)
  186. {
  187. m_pFS = pFS;
  188. m_pStorage = NULL;
  189. m_pStream = NULL;
  190. m_szPathName[0] = 0;
  191. }
  192. CSubFileSystem::~CSubFileSystem()
  193. {
  194. if ( m_pStorage && (m_pStorage != m_pFS->m_pStorage) )
  195. ReleaseObjPtr(m_pStorage);
  196. ReleaseObjPtr(m_pStream);
  197. }
  198. HRESULT CSubFileSystem::CreateSub(PCSTR pszPathName)
  199. {
  200. PCSTR pszFilePortion;
  201. HRESULT hr;
  202. if ( m_pStorage || m_pStream )
  203. return E_FAIL;
  204. if ((pszFilePortion = FindFilePortion(pszPathName)) && pszFilePortion > pszPathName)
  205. {
  206. CHAR szPath[MAX_PATH];
  207. strcpy( szPath, pszPathName );
  208. szPath[(pszFilePortion - 1) - pszPathName] = '\0';
  209. WCHAR wszStorage[MAX_PATH];
  210. MultiByteToWideChar(CP_ACP, 0, szPath, -1, (PWSTR) wszStorage, MAX_PATH);
  211. hr = m_pFS->m_pStorage->OpenStorage(wszStorage, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &m_pStorage);
  212. if (!SUCCEEDED(hr) || !m_pStorage) // storage didn't exist, so create it
  213. hr = m_pFS->m_pStorage->CreateStorage(wszStorage, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &m_pStorage);
  214. if (!SUCCEEDED(hr))
  215. {
  216. return hr;
  217. }
  218. }
  219. else // no folder, so store the file in the root
  220. {
  221. m_pStorage = m_pFS->m_pStorage;
  222. pszFilePortion = pszPathName;
  223. }
  224. WCHAR wszStream[MAX_PATH];
  225. MultiByteToWideChar(CP_ACP, 0, pszFilePortion, -1, (PWSTR) wszStream, MAX_PATH);
  226. hr = m_pStorage->CreateStream(wszStream, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &m_pStream);
  227. if (!SUCCEEDED(hr))
  228. {
  229. if (m_pStorage != m_pFS->m_pStorage)
  230. ReleaseObjPtr(m_pStorage);
  231. return hr;
  232. }
  233. // Needed for delete.
  234. strcpy( m_szPathName, pszFilePortion );
  235. return S_OK;
  236. }
  237. HRESULT CSubFileSystem::CreateUncompressedSub(PCSTR pszPathName)
  238. {
  239. PCSTR pszFilePortion;
  240. HRESULT hr;
  241. IStorageITEx* pIStorageEx;
  242. if ( m_pStorage || m_pStream )
  243. return E_FAIL;
  244. if ((pszFilePortion = FindFilePortion(pszPathName)) && pszFilePortion > pszPathName)
  245. {
  246. CHAR szPath[MAX_PATH];
  247. strcpy( szPath, pszPathName );
  248. szPath[(pszFilePortion - 1) - pszPathName] = '\0';
  249. WCHAR wszStorage[MAX_PATH];
  250. MultiByteToWideChar(CP_ACP, 0, szPath, -1, (PWSTR) wszStorage, MAX_PATH);
  251. hr = m_pFS->m_pStorage->OpenStorage(wszStorage, NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, 0, &m_pStorage);
  252. if (!SUCCEEDED(hr) || !m_pStorage) // storage didn't exist, so create it
  253. hr = m_pFS->m_pStorage->CreateStorage(wszStorage, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &m_pStorage);
  254. if (!SUCCEEDED(hr))
  255. {
  256. return hr;
  257. }
  258. }
  259. else // no folder, so store the file in the root
  260. {
  261. m_pStorage = m_pFS->m_pStorage;
  262. pszFilePortion = pszPathName;
  263. }
  264. if ( !(SUCCEEDED(hr = m_pStorage->QueryInterface(IID_IStorageITEx, (void**)&pIStorageEx))) )
  265. pIStorageEx = (IStorageITEx*)m_pStorage; // BUGBUG the QI call above should work!
  266. WCHAR wszStream[MAX_PATH];
  267. MultiByteToWideChar(CP_ACP, 0, pszFilePortion, -1, (PWSTR) wszStream, MAX_PATH);
  268. hr = pIStorageEx->CreateStreamITEx(wszStream, txtwUncompressed, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, (IStreamITEx**)&m_pStream);
  269. ReleaseObjPtr(pIStorageEx);
  270. if (!SUCCEEDED(hr))
  271. {
  272. if (m_pStorage != m_pFS->m_pStorage)
  273. ReleaseObjPtr(m_pStorage);
  274. return hr;
  275. }
  276. // Needed for delete.
  277. strcpy( m_szPathName, pszFilePortion );
  278. return S_OK;
  279. }
  280. HRESULT CSubFileSystem::CreateSystemFile(PCSTR pszPathName)
  281. {
  282. m_pStorage = m_pFS->m_pStorage;
  283. WCHAR wszStream[MAX_PATH];
  284. MultiByteToWideChar(CP_ACP, 0, pszPathName, -1, (PWSTR) wszStream, MAX_PATH);
  285. HRESULT hr = m_pStorage->CreateStream(wszStream, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &m_pStream);
  286. if (!SUCCEEDED(hr))
  287. {
  288. return hr;
  289. }
  290. // Needed for delete.
  291. strcpy( m_szPathName, pszPathName );
  292. return S_OK;
  293. }
  294. HRESULT CSubFileSystem::CreateUncompressedSystemFile(PCSTR pszPathName)
  295. {
  296. IStorageITEx* pIStorageEx;
  297. HRESULT hr;
  298. m_pStorage = m_pFS->m_pStorage;
  299. if ( !(SUCCEEDED(hr = m_pStorage->QueryInterface(IID_IStorageITEx, (void**)&pIStorageEx))) )
  300. pIStorageEx = (IStorageITEx*)m_pStorage; // BUGBUG the QI call above should work!
  301. WCHAR wszStream[MAX_PATH];
  302. MultiByteToWideChar(CP_ACP, 0, pszPathName, -1, (PWSTR) wszStream, MAX_PATH);
  303. hr = pIStorageEx->CreateStreamITEx(wszStream, txtwUncompressed, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, (IStreamITEx**)&m_pStream);
  304. ReleaseObjPtr(pIStorageEx);
  305. if (!SUCCEEDED(hr))
  306. {
  307. return hr;
  308. }
  309. // Needed for delete.
  310. strcpy( m_szPathName, pszPathName );
  311. return S_OK;
  312. }
  313. HRESULT CSubFileSystem::OpenSub(PCSTR pszPathName, DWORD dwAccess)
  314. {
  315. PCSTR pszFilePortion;
  316. HRESULT hr;
  317. if ( m_pStorage || m_pStream )
  318. return E_FAIL;
  319. // force access modes
  320. if( (dwAccess & STGM_WRITE) || (dwAccess & STGM_READWRITE) ) {
  321. dwAccess &= ~STGM_WRITE;
  322. dwAccess |= STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
  323. }
  324. else
  325. dwAccess |= STGM_SHARE_DENY_WRITE;
  326. if ((pszFilePortion = FindFilePortion(pszPathName)) &&
  327. pszFilePortion > pszPathName + 2) // +2 to support / && ./
  328. {
  329. CHAR szPath[MAX_PATH];
  330. strcpy( szPath, pszPathName );
  331. szPath[(pszFilePortion - 1) - pszPathName] = '\0';
  332. WCHAR wszStorage[MAX_PATH];
  333. MultiByteToWideChar(CP_ACP, 0, szPath, -1, (PWSTR) wszStorage, MAX_PATH);
  334. hr = m_pFS->m_pStorage->OpenStorage(wszStorage, NULL, dwAccess, NULL, 0, &m_pStorage);
  335. if (!SUCCEEDED(hr))
  336. {
  337. return hr;
  338. }
  339. }
  340. else // no folder, so store the file in the root
  341. {
  342. m_pStorage = m_pFS->m_pStorage ? m_pFS->m_pStorage : m_pFS->m_pStorage;
  343. pszFilePortion = pszPathName;
  344. }
  345. WCHAR wszStream[MAX_PATH];
  346. MultiByteToWideChar(CP_ACP, 0, pszFilePortion, -1, (PWSTR) wszStream, MAX_PATH);
  347. hr = m_pStorage->OpenStream(wszStream, NULL, dwAccess, 0, &m_pStream);
  348. if (!SUCCEEDED(hr))
  349. {
  350. if (m_pStorage != m_pFS->m_pStorage)
  351. ReleaseObjPtr(m_pStorage);
  352. return hr;
  353. }
  354. // Needed for delete.
  355. strcpy( m_szPathName, pszFilePortion );
  356. return S_OK;
  357. }
  358. ULONG CSubFileSystem::WriteSub(const void* pData, int cb)
  359. {
  360. if ( !m_pStorage || !m_pStream )
  361. return (ULONG) -1;
  362. ULONG cbWritten;
  363. HRESULT hr = m_pStream->Write(pData, cb, &cbWritten);
  364. if (!SUCCEEDED(hr) || (cbWritten != (ULONG)cb) )
  365. {
  366. return (ULONG) -1;
  367. }
  368. // REVIEW: 30-May-1997 [ralphw] Why are we returning this? We fail if
  369. // we don't write cb bytes.
  370. return cbWritten;
  371. }
  372. /*
  373. * iOrigin:
  374. * 0 = Seek from beginning.
  375. * 1 = Seek from current.
  376. * 2 = Seek from end.
  377. */
  378. ULONG CSubFileSystem::SeekSub(int cb, int iOrigin)
  379. {
  380. HRESULT hr = S_OK;
  381. LARGE_INTEGER liCount = {0,0};
  382. ULARGE_INTEGER liNewPos = {0,0};
  383. if ( !m_pStorage || !m_pStream )
  384. return (ULONG) -1;
  385. liCount.LowPart = cb;
  386. hr = m_pStream->Seek(liCount, iOrigin, &liNewPos);
  387. if (!SUCCEEDED(hr) )
  388. {
  389. return (ULONG) -1;
  390. }
  391. return liNewPos.LowPart;
  392. }
  393. bool CSubFileSystem::GetSubPos(ULARGE_INTEGER* pliOldPos, STREAM_SEEK eDir /*=STREAM_SEEK_CUR*/)
  394. {
  395. HRESULT hr = S_OK;
  396. LARGE_INTEGER liNull = {0,0};
  397. if ( !m_pStorage || !m_pStream )
  398. return false;
  399. hr = m_pStream->Seek(liNull, eDir, pliOldPos);
  400. if (!SUCCEEDED(hr) )
  401. return false;
  402. return true;
  403. }
  404. bool CSubFileSystem::SetSubPos(LARGE_INTEGER liNewPos, STREAM_SEEK eDir /*=STREAM_SEEK_SET*/)
  405. {
  406. HRESULT hr = S_OK;
  407. if ( !m_pStorage || !m_pStream )
  408. return false;
  409. hr = m_pStream->Seek(liNewPos, eDir, NULL);
  410. if (!SUCCEEDED(hr) )
  411. return false;
  412. return true;
  413. }
  414. //
  415. // Pre-allocate the size of the stream.
  416. //
  417. HRESULT CSubFileSystem::SetSize(unsigned uSize)
  418. {
  419. ULARGE_INTEGER liSize = {0,0};
  420. HRESULT hr;
  421. if ( !m_pStorage || !m_pStream )
  422. return E_FAIL;
  423. liSize.LowPart = uSize;
  424. hr = m_pStream->SetSize(liSize);
  425. if (!SUCCEEDED(hr) )
  426. {
  427. return (ULONG) -1;
  428. }
  429. return hr;
  430. }
  431. //
  432. // Delete substorage.
  433. //
  434. HRESULT CSubFileSystem::DeleteSub()
  435. {
  436. if (m_pStorage)
  437. {
  438. if (m_pStream)
  439. {
  440. // Release the stream.
  441. ReleaseObjPtr(m_pStream) ;
  442. }
  443. // Now delete the storage.
  444. WCHAR element[MAX_PATH];
  445. MultiByteToWideChar(CP_ACP, 0, m_szPathName, -1, (PWSTR) element, MAX_PATH);
  446. HRESULT hr = m_pStorage->DestroyElement(element) ;
  447. if (SUCCEEDED(hr))
  448. {
  449. // Get back to the constructor state.
  450. if ( m_pStorage && (m_pStorage != m_pFS->m_pStorage) )
  451. {
  452. ReleaseObjPtr(m_pStorage);
  453. }
  454. return S_OK ;
  455. }
  456. }
  457. return S_OK ;
  458. }
  459. ULONG CSubFileSystem::GetUncompressedSize(void)
  460. {
  461. ULARGE_INTEGER liOldPos ={0,0};
  462. LARGE_INTEGER liOldOff ={0,0};
  463. ULONG ret = -1;
  464. if (GetSubPos(&liOldPos))
  465. {
  466. if (-1 != (ret = SeekSub(0, STREAM_SEEK_END)))
  467. {
  468. liOldOff.LowPart = liOldPos.LowPart;
  469. liOldOff.HighPart = liOldPos.HighPart;
  470. if (SetSubPos(liOldOff))
  471. {
  472. return ret;
  473. }
  474. }
  475. }
  476. return (ULONG) -1;
  477. }