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.

298 lines
9.2 KiB

  1. // Copyright (c) 1998-1999 Microsoft Corporation
  2. #include "stdafx.h"
  3. #include "MSICAB.h"
  4. extern "C" {
  5. #include "uni2utf.h"
  6. };
  7. #ifndef IDS_CAB_DIR_NAME
  8. #include "resource.h"
  9. #endif
  10. LPCTSTR cszDirSeparator = _T("\\");
  11. //---------------------------------------------------------------------------
  12. // DirectorySearch is used to locate all of the files in a directory or
  13. // one of its subdirectories which match a file spec.
  14. //---------------------------------------------------------------------------
  15. void DirectorySearch(const CString & strSpec, const CString & strDir, CStringList &results)
  16. {
  17. // Look for all of the files which match the file spec in the directory
  18. // specified by strDir.
  19. WIN32_FIND_DATA finddata;
  20. CString strSearch, strDirectory;
  21. strDirectory = strDir;
  22. if (strDirectory.Right(1) != CString(cszDirSeparator)) strDirectory += CString(cszDirSeparator);
  23. strSearch = strDirectory + strSpec;
  24. HANDLE hFind = FindFirstFile(strSearch, &finddata);
  25. if (hFind != INVALID_HANDLE_VALUE)
  26. {
  27. do
  28. {
  29. results.AddHead(strDirectory + CString(finddata.cFileName));
  30. } while (FindNextFile(hFind, &finddata));
  31. FindClose(hFind);
  32. }
  33. // Now call this function recursively, with each of the subdirectories.
  34. strSearch = strDirectory + CString(_T("*"));
  35. hFind = FindFirstFile(strSearch, &finddata);
  36. if (hFind != INVALID_HANDLE_VALUE)
  37. {
  38. do
  39. {
  40. if (finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  41. if (::_tcscmp(finddata.cFileName, _T(".")) != 0 && ::_tcscmp(finddata.cFileName, _T("..")) != 0)
  42. DirectorySearch(strSpec, strDirectory + CString(finddata.cFileName), results);
  43. } while (FindNextFile(hFind, &finddata));
  44. FindClose(hFind);
  45. }
  46. }
  47. //---------------------------------------------------------------------------
  48. // This function gets the directory in which to put exploded CAB files.
  49. // This will be the same directory each time, so this function will create
  50. // the directory (if necessary) and delete any files in the directory.
  51. //---------------------------------------------------------------------------
  52. BOOL GetCABExplodeDir(CString &destination, BOOL fDeleteFiles, const CString & strDontDelete)
  53. {
  54. CString strMSInfoDir, strExplodeTo, strSubDirName;
  55. // Determine the temporary path and add on a subdir name.
  56. TCHAR szTempDir[_MAX_PATH];
  57. if (GetTempPath(_MAX_PATH, szTempDir) > _MAX_PATH)
  58. {
  59. // MSIError(IDS_GENERAL_ERROR, "couldn't get temporary path");
  60. destination = _T("");
  61. return FALSE;
  62. }
  63. strSubDirName.LoadString(IDS_CAB_DIR_NAME);
  64. strExplodeTo = szTempDir;
  65. if (strExplodeTo.Right(1) == CString(cszDirSeparator))
  66. strExplodeTo = strExplodeTo + strSubDirName;
  67. else
  68. strExplodeTo = strExplodeTo + CString(cszDirSeparator) + strSubDirName;
  69. // Kill the directory if it already exists.
  70. if (fDeleteFiles)
  71. KillDirectory(strExplodeTo, strDontDelete);
  72. // Create the subdirectory.
  73. if (!CreateDirectoryEx(szTempDir, strExplodeTo, NULL))
  74. {
  75. if (GetLastError() != ERROR_ALREADY_EXISTS)
  76. {
  77. // MSIError(IDS_GENERAL_ERROR, "couldn't create the target directory");
  78. destination = "";
  79. return FALSE;
  80. }
  81. }
  82. destination = strExplodeTo;
  83. return TRUE;
  84. }
  85. //---------------------------------------------------------------------------
  86. // This functions kills a directory by recursively deleting files and
  87. // subdirectories.
  88. //---------------------------------------------------------------------------
  89. void KillDirectory(const CString & strDir, const CString & strDontDelete)
  90. {
  91. CString strDirectory = strDir;
  92. if (strDirectory.Right(1) == CString(cszDirSeparator))
  93. strDirectory = strDirectory.Left(strDirectory.GetLength() - 1);
  94. // Delete any files in directory.
  95. CString strFilesToDelete = strDirectory + CString(_T("\\*.*"));
  96. CString strDeleteFile;
  97. WIN32_FIND_DATA filedata;
  98. BOOL bFound = TRUE;
  99. HANDLE hFindFile = FindFirstFile(strFilesToDelete, &filedata);
  100. while (hFindFile != INVALID_HANDLE_VALUE && bFound)
  101. {
  102. if ((filedata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0L)
  103. {
  104. strDeleteFile = strDirectory + CString(cszDirSeparator) + filedata.cFileName;
  105. if (strDontDelete.CompareNoCase(strDeleteFile) != 0)
  106. {
  107. ::SetFileAttributes(strDeleteFile, FILE_ATTRIBUTE_NORMAL);
  108. ::DeleteFile(strDeleteFile);
  109. }
  110. }
  111. bFound = FindNextFile(hFindFile, &filedata);
  112. }
  113. FindClose(hFindFile);
  114. // Now call this function on any subdirectories in this directory.
  115. CString strSearch = strDirectory + CString(_T("\\*"));
  116. hFindFile = FindFirstFile(strSearch, &filedata);
  117. if (hFindFile != INVALID_HANDLE_VALUE)
  118. {
  119. do
  120. {
  121. if (filedata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  122. if (::_tcscmp(filedata.cFileName, _T(".")) != 0 && ::_tcscmp(filedata.cFileName, _T("..")) != 0)
  123. KillDirectory(strDirectory + CString(cszDirSeparator) + CString(filedata.cFileName));
  124. } while (FindNextFile(hFindFile, &filedata));
  125. FindClose(hFindFile);
  126. }
  127. // Finally, remove this directory.
  128. ::RemoveDirectory(strDirectory);
  129. }
  130. //---------------------------------------------------------------------------
  131. // This function will expand the specified CAB file, putting all of the
  132. // files in the specified destination directory.
  133. //---------------------------------------------------------------------------
  134. BOOL OpenCABFile(const CString & filename, const CString & destination)
  135. {
  136. char szFilebuffer[MAX_UTF_LENGTH];
  137. char szDestination[MAX_UTF_LENGTH];
  138. // If the filename has Unicode characters which can't be represented
  139. // directly by ANSI characters, we need to make a copy of it to the
  140. // temp directory, and give it an ANSI name. The code we've borrowed
  141. // for expanding CAB files can't open Unicode named files.
  142. BOOL fNonANSICharacter = FALSE;
  143. const TCHAR * pChar = (LPCTSTR) filename;
  144. while (pChar && *pChar)
  145. if (*pChar++ >= (TCHAR)0x0080)
  146. {
  147. fNonANSICharacter = TRUE;
  148. break;
  149. }
  150. CString strFilename(filename);
  151. BOOL fMadeCopy = FALSE;
  152. if (fNonANSICharacter)
  153. {
  154. TCHAR szNewFile[MAX_PATH + 10];
  155. DWORD dwLength = 0;
  156. dwLength = ::GetTempPath(MAX_PATH, szNewFile);
  157. if (dwLength != 0 && dwLength < MAX_PATH)
  158. {
  159. _tcscat(szNewFile, _T("msitemp.cab"));
  160. fMadeCopy = ::CopyFile((LPCTSTR) strFilename, szNewFile, FALSE);
  161. strFilename = szNewFile;
  162. }
  163. }
  164. char * szFilename = Unicode2UTF((LPCTSTR)strFilename);
  165. ::strcpy(szFilebuffer, szFilename);
  166. szFilename = Unicode2UTF((LPCTSTR)destination);
  167. ::strcpy(szDestination, szFilename);
  168. BOOL fResult = explode_cab(szFilebuffer, szDestination);
  169. // If we made a copy of the CAB file, we should delete it now.
  170. if (fMadeCopy)
  171. ::DeleteFile((LPCTSTR)strFilename);
  172. return fResult;
  173. }
  174. //---------------------------------------------------------------------------
  175. // This function looks in the specified directory for an NFO file. If it
  176. // finds one, it assigns it to filename and returns TRUE. This function
  177. // will only find the first NFO file in a directory.
  178. //
  179. // If an NFO file cannot be found, then we'll look for another file type
  180. // to open. Grab the string entry in the registry = "cabdefaultopen". An
  181. // example value would be "*.nfo|hwinfo.dat|*.dat|*.txt" which would be
  182. // interpreted as follows:
  183. //
  184. // 1. First look for any NFO file to open.
  185. // 2. Then try to open a file called "hwinfo.dat".
  186. // 3. Then try to open any file with a DAT extension.
  187. // 4. Then try for any TXT file.
  188. // 5. Finally, if none of these can be found, present an open dialog
  189. // to the user.
  190. //---------------------------------------------------------------------------
  191. LPCTSTR VAL_CABDEFAULTOPEN = _T("cabdefaultopen");
  192. BOOL FindFileToOpen(const CString & destination, CString & filename)
  193. {
  194. CString strCABDefaultOpen, strRegBase, strDirectory;
  195. HKEY hkey;
  196. filename.Empty();
  197. strDirectory = destination;
  198. if (strDirectory.Right(1) != CString(cszDirSeparator))
  199. strDirectory += CString(cszDirSeparator);
  200. // Set up a fallback string of the NFO file type, in case we can't
  201. // find the registry entry.
  202. strCABDefaultOpen.LoadString(IDS_MSI_FILE_EXTENSION);
  203. strCABDefaultOpen = CString("*.") + strCABDefaultOpen;
  204. // Load the string of files and file types to open from the registry.
  205. strRegBase.LoadString(IDS_MSI_REG_BASE);
  206. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, strRegBase, 0, KEY_READ, &hkey) == ERROR_SUCCESS)
  207. {
  208. char szData[MAX_PATH];
  209. DWORD dwType, dwSize = MAX_PATH;
  210. if (RegQueryValueEx(hkey, VAL_CABDEFAULTOPEN, NULL, &dwType, (LPBYTE) szData, &dwSize) == ERROR_SUCCESS)
  211. if (dwType == REG_SZ)
  212. strCABDefaultOpen = szData;
  213. RegCloseKey(hkey);
  214. }
  215. // Look through each of the potential files and file types. If we find
  216. // a match, return TRUE after setting filename appropriately. Note that
  217. // we need to recurse down through directories.
  218. CString strFileSpec;
  219. CStringList filesfound;
  220. POSITION pos;
  221. while (!strCABDefaultOpen.IsEmpty())
  222. {
  223. if (strCABDefaultOpen.Find('|') == -1)
  224. strFileSpec = strCABDefaultOpen;
  225. else
  226. strFileSpec = strCABDefaultOpen.Left(strCABDefaultOpen.Find('|'));
  227. filesfound.RemoveAll();
  228. DirectorySearch(strFileSpec, strDirectory, filesfound);
  229. pos = filesfound.GetHeadPosition();
  230. if (pos != NULL)
  231. {
  232. filename = filesfound.GetNext(pos);
  233. return TRUE;
  234. }
  235. strCABDefaultOpen = strCABDefaultOpen.Right(strCABDefaultOpen.GetLength() - strFileSpec.GetLength());
  236. if (strCABDefaultOpen.Find('|') == 0)
  237. strCABDefaultOpen = strCABDefaultOpen.Right(strCABDefaultOpen.GetLength() - 1);
  238. }
  239. return FALSE;
  240. }