821 lines
22 KiB
C++
821 lines
22 KiB
C++
|
|
||
|
#include "stdafx.h"
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <io.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <dos.h>
|
||
|
#include "cabfunc.h"
|
||
|
#include "resource.h"
|
||
|
#include "filestuff.h"
|
||
|
#include "fdi.h"
|
||
|
|
||
|
BOOL test_fdi(char *cabinet_fullpath);
|
||
|
//static char dest_dir[MAX_PATH];
|
||
|
BOOL explode_cab(char *cabinet_fullpath, char *destination)
|
||
|
{
|
||
|
char cab_path[MAX_PATH];
|
||
|
|
||
|
strcpy(dest_dir, destination);
|
||
|
strcpy(cab_path, cabinet_fullpath);
|
||
|
|
||
|
return test_fdi(cabinet_fullpath);
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// The following definitions are pulled from stat.h and types.h. I was having
|
||
|
// trouble getting the build tree make to pull them in, so I just copied the
|
||
|
// relevant stuff. This may very well need to be changed if those include
|
||
|
// files change.
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
#define _S_IREAD 0000400 /* read permission, owner */
|
||
|
#define _S_IWRITE 0000200 /* write permission, owner */
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// All of these functions may be called by the unCAB library.
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
FNALLOC(mem_alloc) { return malloc(cb); }
|
||
|
FNFREE(mem_free) { free(pv); }
|
||
|
FNOPEN(file_open) { return _open(pszFile, oflag, pmode); }
|
||
|
FNREAD(file_read) { return _read((int)hf, pv, cb); }
|
||
|
FNWRITE(file_write) { return _write((int)hf, pv, cb); }
|
||
|
FNCLOSE(file_close) { return _close((int)hf); }
|
||
|
FNSEEK(file_seek) { return _lseek((int)hf, dist, seektype); }
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
BOOL DoesFileExist(char *szFile)
|
||
|
{
|
||
|
USES_CONVERSION;
|
||
|
HANDLE handle;
|
||
|
handle = CreateFile(A2T(szFile), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||
|
if (handle != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
CloseHandle(handle);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// This callback will be called by the unCAB library.
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
FNFDINOTIFY(notification_function)
|
||
|
{
|
||
|
switch (fdint)
|
||
|
{
|
||
|
case fdintCABINET_INFO: // general information about the cabinet
|
||
|
return 0;
|
||
|
|
||
|
case fdintPARTIAL_FILE: // first file in cabinet is continuation
|
||
|
return 0;
|
||
|
|
||
|
case fdintCOPY_FILE: // file to be copied
|
||
|
{
|
||
|
int handle = -1;
|
||
|
char destination[MAX_PATH];
|
||
|
char szBuffer[MAX_PATH], *szFile;
|
||
|
|
||
|
// We no longer want to create a directory tree as we expand the files.
|
||
|
// TSHOOT.EXE, which is used to open some of the files in the CAB, likes
|
||
|
// to find the files in a nice flat directory. Now we will need to handle
|
||
|
// name collisions (although there probably won't be many). If we are
|
||
|
// asked to create a second file with the same name as an existing file,
|
||
|
// we'll prefix the subdirectory name and an underscore to the new file.
|
||
|
|
||
|
if (pfdin->psz1 == NULL)
|
||
|
return 0;
|
||
|
|
||
|
strcpy(szBuffer, pfdin->psz1);
|
||
|
szFile = strrchr(szBuffer, '\\');
|
||
|
while (handle == -1 && szFile != NULL)
|
||
|
{
|
||
|
sprintf(destination, "%s\\%s", dest_dir, szFile + 1);
|
||
|
if (!DoesFileExist(destination))
|
||
|
handle = (int)file_open(destination, _O_BINARY | _O_CREAT | _O_WRONLY | _O_SEQUENTIAL, _S_IREAD | _S_IWRITE);
|
||
|
else
|
||
|
{
|
||
|
*szFile = '_';
|
||
|
szFile = strrchr(szBuffer, '\\');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (handle == -1)
|
||
|
{
|
||
|
sprintf(destination, "%s\\%s", dest_dir, szBuffer);
|
||
|
handle = (int)file_open(destination, _O_BINARY | _O_CREAT | _O_WRONLY | _O_SEQUENTIAL, _S_IREAD | _S_IWRITE);
|
||
|
}
|
||
|
|
||
|
return handle;
|
||
|
|
||
|
// Old code which created the directory structure:
|
||
|
|
||
|
#if FALSE
|
||
|
// If the file we are supposed to create contains path information,
|
||
|
// we may need to create the directories before create the file.
|
||
|
|
||
|
char szDir[MAX_PATH], szSubDir[MAX_PATH], *p;
|
||
|
|
||
|
p = strrchr(pfdin->psz1, '\\');
|
||
|
if (p)
|
||
|
{
|
||
|
strncpy(szSubDir, pfdin->psz1, MAX_PATH);
|
||
|
|
||
|
p = strchr(szSubDir, '\\');
|
||
|
while (p != NULL)
|
||
|
{
|
||
|
*p = '\0';
|
||
|
sprintf(szDir, "%s\\%s", dest_dir, szSubDir);
|
||
|
CreateDirectory(szDir, NULL);
|
||
|
*p = '\\';
|
||
|
p = strchr(p+1, '\\');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sprintf(destination, "%s\\%s", dest_dir, pfdin->psz1);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
case fdintCLOSE_FILE_INFO: // close the file, set relevant info
|
||
|
{
|
||
|
HANDLE handle;
|
||
|
DWORD attrs;
|
||
|
TCHAR destination[MAX_PATH];
|
||
|
|
||
|
_stprintf(destination, _T("%s\\%s"), dest_dir, pfdin->psz1);
|
||
|
file_close(pfdin->hf);
|
||
|
|
||
|
// Need to use Win32 type handle to set date/time
|
||
|
|
||
|
handle = CreateFile(destination, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||
|
|
||
|
if (handle != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
FILETIME datetime;
|
||
|
|
||
|
if (TRUE == DosDateTimeToFileTime(pfdin->date, pfdin->time, &datetime))
|
||
|
{
|
||
|
FILETIME local_filetime;
|
||
|
|
||
|
if (TRUE == LocalFileTimeToFileTime(&datetime, &local_filetime))
|
||
|
{
|
||
|
(void) SetFileTime(handle, &local_filetime, NULL, &local_filetime);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CloseHandle(handle);
|
||
|
}
|
||
|
|
||
|
// Mask out attribute bits other than readonly,
|
||
|
// hidden, system, and archive, since the other
|
||
|
// attribute bits are reserved for use by
|
||
|
// the cabinet format.
|
||
|
|
||
|
attrs = pfdin->attribs;
|
||
|
|
||
|
// Actually, let's mask out hidden as well.
|
||
|
// attrs &= (_A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH);
|
||
|
attrs &= (_A_RDONLY | _A_SYSTEM | _A_ARCH);
|
||
|
|
||
|
(void) SetFileAttributes(destination, attrs);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
case fdintNEXT_CABINET: // file continued to next cabinet
|
||
|
return 0;
|
||
|
|
||
|
default:
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
/**/
|
||
|
//---------------------------------------------------------------------------
|
||
|
// This function is used to actually expand the files in a CAB.
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
BOOL test_fdi(char *cabinet_fullpath)
|
||
|
{
|
||
|
HFDI hfdi;
|
||
|
ERF erf;
|
||
|
FDICABINETINFO fdici;
|
||
|
int hf;
|
||
|
char *p;
|
||
|
char cabinet_name[256];
|
||
|
char cabinet_path[256];
|
||
|
|
||
|
hfdi = FDICreate(mem_alloc, mem_free, file_open, file_read, file_write, file_close, file_seek, cpu80386, &erf);
|
||
|
|
||
|
if (hfdi == NULL)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
hf = (int)file_open(cabinet_fullpath, _O_BINARY | _O_RDONLY | _O_SEQUENTIAL, 0);
|
||
|
if (hf == -1)
|
||
|
{
|
||
|
(void) FDIDestroy(hfdi);
|
||
|
|
||
|
// printf("Unable to open '%s' for input\n", cabinet_fullpath);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (FALSE == FDIIsCabinet(hfdi, hf, &fdici))
|
||
|
{
|
||
|
_close(hf);
|
||
|
(void) FDIDestroy(hfdi);
|
||
|
return FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_close(hf);
|
||
|
}
|
||
|
|
||
|
p = strrchr(cabinet_fullpath, '\\');
|
||
|
|
||
|
if (p == NULL)
|
||
|
{
|
||
|
strcpy(cabinet_name, cabinet_fullpath);
|
||
|
strcpy(cabinet_path, "");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
strcpy(cabinet_name, p+1);
|
||
|
|
||
|
strncpy(cabinet_path, cabinet_fullpath, (int) (p-cabinet_fullpath)+1);
|
||
|
cabinet_path[ (int) (p-cabinet_fullpath)+1 ] = 0;
|
||
|
}
|
||
|
|
||
|
if (TRUE != FDICopy(hfdi, cabinet_name, cabinet_path, 0, notification_function, NULL, NULL))
|
||
|
{
|
||
|
(void) FDIDestroy(hfdi);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (FDIDestroy(hfdi) != TRUE)
|
||
|
return FALSE;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* UNI2UTF -- Unicode to/from UTF conversions
|
||
|
*
|
||
|
* Copyright (C) 1996, Microsoft Corporation. All rights reserved.
|
||
|
*
|
||
|
* History:
|
||
|
*
|
||
|
* 10-14-96 msliger Created.
|
||
|
* 12-16-99 moved to .cpp from uni2utf.c
|
||
|
* combined with code from cabfunc.c
|
||
|
*/
|
||
|
/*
|
||
|
* Unicode2UTF()
|
||
|
*
|
||
|
* This function converts any 0-terminated Unicode string to the corresponding
|
||
|
* nul-terminated UTF string, and returns a pointer to the resulting string.
|
||
|
* The pointer references a single, static internal buffer, so the result will
|
||
|
* be destroyed on the next call.
|
||
|
*
|
||
|
* If the generated UTF string would be too long, NULL is returned.
|
||
|
*/
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
char *Unicode2UTF(const wchar_t *unicode)
|
||
|
{
|
||
|
static char utfbuffer[MAX_UTF_LENGTH + 4];
|
||
|
int utfindex = 0;
|
||
|
|
||
|
while (*unicode != 0)
|
||
|
{
|
||
|
if (utfindex >= MAX_UTF_LENGTH)
|
||
|
{
|
||
|
return(NULL);
|
||
|
}
|
||
|
|
||
|
if (*unicode < 0x0080)
|
||
|
{
|
||
|
utfbuffer[utfindex++] = (char) *unicode;
|
||
|
}
|
||
|
else if (*unicode < 0x0800)
|
||
|
{
|
||
|
utfbuffer[utfindex++] = (char) (0xC0 + (*unicode >> 6));
|
||
|
utfbuffer[utfindex++] = (char) (0x80 + (*unicode & 0x3F));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
utfbuffer[utfindex++] = (char) (0xE0 + (*unicode >> 12));
|
||
|
utfbuffer[utfindex++] = (char) (0x80 + ((*unicode >> 6) & 0x3F));
|
||
|
utfbuffer[utfindex++] = (char) (0x80 + (*unicode & 0x3F));
|
||
|
}
|
||
|
|
||
|
unicode++;
|
||
|
}
|
||
|
|
||
|
utfbuffer[utfindex] = '\0';
|
||
|
|
||
|
return(utfbuffer);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* UTF2Unicode()
|
||
|
*
|
||
|
* This function converts a valid UTF string into the corresponding unicode string,
|
||
|
* and returns a pointer to the resulting unicode. The pointer references a single,
|
||
|
* internal static buffer, which will be destroyed on the next call.
|
||
|
*
|
||
|
* If the generated unicode string would be too long, or if the UTF string contains
|
||
|
* any illegal UTF values, NULL is returned.
|
||
|
*/
|
||
|
|
||
|
wchar_t *UTF2Unicode(const char *utfString)
|
||
|
{
|
||
|
static wchar_t unicodebuffer[MAX_UNICODE_LENGTH + 1];
|
||
|
int unicodeindex = 0;
|
||
|
int c;
|
||
|
|
||
|
while (*utfString != 0)
|
||
|
{
|
||
|
if (unicodeindex >= MAX_UNICODE_LENGTH)
|
||
|
{
|
||
|
return(NULL);
|
||
|
}
|
||
|
|
||
|
c = (*utfString++ & 0x00FF);
|
||
|
|
||
|
if (c < 0x0080)
|
||
|
{
|
||
|
unicodebuffer[unicodeindex] = (unsigned short) c;
|
||
|
}
|
||
|
else if (c < 0x00C0)
|
||
|
{
|
||
|
return(NULL); /* 0x0080..0x00BF illegal */
|
||
|
}
|
||
|
else if (c < 0x00E0)
|
||
|
{
|
||
|
unicodebuffer[unicodeindex] = (unsigned short) ((c & 0x001F) << 6);
|
||
|
|
||
|
c = (*utfString++ & 0x00FF);
|
||
|
|
||
|
if ((c < 0x0080) || (c > 0x00BF))
|
||
|
{
|
||
|
return(NULL); /* trail must be 0x0080..0x00BF */
|
||
|
}
|
||
|
|
||
|
unicodebuffer[unicodeindex] |= (c & 0x003F);
|
||
|
}
|
||
|
else if (c < 0x00F0)
|
||
|
{
|
||
|
unicodebuffer[unicodeindex] = (unsigned short) ((c & 0x000F) << 12);
|
||
|
|
||
|
c = (*utfString++ & 0x00FF);
|
||
|
|
||
|
if ((c < 0x0080) || (c > 0x00BF))
|
||
|
{
|
||
|
return(NULL); /* trails must be 0x0080..0x00BF */
|
||
|
}
|
||
|
|
||
|
unicodebuffer[unicodeindex] |= ((c & 0x003F) << 6);
|
||
|
|
||
|
c = (*utfString++ & 0x00FF);
|
||
|
|
||
|
if ((c < 0x0080) || (c > 0x00BF))
|
||
|
{
|
||
|
return(NULL); /* trails must be 0x0080..0x00BF */
|
||
|
}
|
||
|
|
||
|
unicodebuffer[unicodeindex] |= (c & 0x003F);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return(NULL); /* lead can't be > 0x00EF */
|
||
|
}
|
||
|
|
||
|
unicodeindex++;
|
||
|
}
|
||
|
|
||
|
unicodebuffer[unicodeindex] = 0;
|
||
|
|
||
|
return(unicodebuffer);
|
||
|
}
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// This function will expand the specified CAB file, putting all of the
|
||
|
// files in the specified destination directory.
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
|
||
|
BOOL OpenCABFile(const CString & filename, const CString & destination)
|
||
|
{
|
||
|
char szFilebuffer[MAX_UTF_LENGTH];
|
||
|
char szDestination[MAX_UTF_LENGTH];
|
||
|
|
||
|
// If the filename has Unicode characters which can't be represented
|
||
|
// directly by ANSI characters, we need to make a copy of it to the
|
||
|
// temp directory, and give it an ANSI name. The code we've borrowed
|
||
|
// for expanding CAB files can't open Unicode named files.
|
||
|
|
||
|
BOOL fNonANSICharacter = FALSE;
|
||
|
const TCHAR * pChar = (LPCTSTR) filename;
|
||
|
while (pChar && *pChar)
|
||
|
if (*pChar++ >= (TCHAR)0x0080)
|
||
|
{
|
||
|
fNonANSICharacter = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
CString strFilename(filename);
|
||
|
BOOL fMadeCopy = FALSE;
|
||
|
if (fNonANSICharacter)
|
||
|
{
|
||
|
TCHAR szNewFile[MAX_PATH + 10];
|
||
|
DWORD dwLength = 0;
|
||
|
|
||
|
dwLength = ::GetTempPath(MAX_PATH, szNewFile);
|
||
|
if (dwLength != 0 && dwLength < MAX_PATH)
|
||
|
{
|
||
|
_tcscat(szNewFile, _T("msitemp.cab"));
|
||
|
fMadeCopy = ::CopyFile((LPCTSTR) strFilename, szNewFile, FALSE);
|
||
|
strFilename = szNewFile;
|
||
|
}
|
||
|
}
|
||
|
BOOL fResult = FALSE;
|
||
|
//TD: better way to handle UNICODE vs non-unicode strings?
|
||
|
|
||
|
// for Unicode system
|
||
|
char * szFilename = Unicode2UTF((wchar_t*)(LPCTSTR)strFilename);
|
||
|
if (szFilename)
|
||
|
{
|
||
|
::strcpy(szFilebuffer, szFilename);
|
||
|
szFilename = Unicode2UTF((wchar_t*)(LPCTSTR)destination);
|
||
|
if (szFilename)
|
||
|
{
|
||
|
::strcpy(szDestination, szFilename);
|
||
|
fResult = explode_cab(szFilebuffer, szDestination);
|
||
|
}
|
||
|
}
|
||
|
//for non-Unicode system
|
||
|
if (!fResult)
|
||
|
{
|
||
|
fResult = explode_cab((char *)(LPCTSTR) filename, (char *)(LPCTSTR) destination);
|
||
|
}
|
||
|
|
||
|
// If we made a copy of the CAB file, we should delete it now.
|
||
|
|
||
|
if (fMadeCopy)
|
||
|
::DeleteFile((LPCTSTR)strFilename);
|
||
|
|
||
|
return fResult;
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// This function looks in the specified directory for an NFO file. If it
|
||
|
// finds one, it assigns it to filename and returns TRUE. This function
|
||
|
// will only find the first NFO file in a directory.
|
||
|
//
|
||
|
// If an NFO file cannot be found, then we'll look for another file type
|
||
|
// to open. Grab the string entry in the registry = "cabdefaultopen". An
|
||
|
// example value would be "*.nfo|hwinfo.dat|*.dat|*.txt" which would be
|
||
|
// interpreted as follows:
|
||
|
//
|
||
|
// 1. First look for any NFO file to open.
|
||
|
// 2. Then try to open a file called "hwinfo.dat".
|
||
|
// 3. Then try to open any file with a DAT extension.
|
||
|
// 4. Then try for any TXT file.
|
||
|
// 5. Finally, if none of these can be found, present an open dialog
|
||
|
// to the user.
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
LPCTSTR VAL_CABDEFAULTOPEN = _T("cabdefaultopen");
|
||
|
LPCTSTR cszDirSeparator = _T("\\");
|
||
|
|
||
|
BOOL IsDataspecFilePresent(CString strCabExplodedDir)
|
||
|
{
|
||
|
CStringList filesfound;
|
||
|
DirectorySearch(_T("dataspec.xml"), strCabExplodedDir, filesfound);
|
||
|
if (filesfound.GetHeadPosition() != NULL)
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL IsIncidentXMLFilePresent(CString strCabExplodedDir, CString strIncidentFileName)
|
||
|
{
|
||
|
CStringList filesfound;
|
||
|
DirectorySearch(strIncidentFileName, strCabExplodedDir, filesfound);
|
||
|
if (filesfound.GetHeadPosition() != NULL)
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
return FALSE;
|
||
|
|
||
|
}
|
||
|
|
||
|
BOOL FindFileToOpen(const CString & destination, CString & filename)
|
||
|
{
|
||
|
CString strCABDefaultOpen, strRegBase, strDirectory;
|
||
|
HKEY hkey;
|
||
|
|
||
|
filename.Empty();
|
||
|
strDirectory = destination;
|
||
|
if (strDirectory.Right(1) != CString(cszDirSeparator))
|
||
|
strDirectory += CString(cszDirSeparator);
|
||
|
|
||
|
// Set up a fallback string of the NFO file type, in case we can't
|
||
|
// find the registry entry.
|
||
|
|
||
|
strCABDefaultOpen.LoadString(IDS_DEFAULTEXTENSION);
|
||
|
strCABDefaultOpen = CString("*.") + strCABDefaultOpen;
|
||
|
|
||
|
// Load the string of files and file types to open from the registry.
|
||
|
|
||
|
strRegBase.LoadString(IDS_MSI_REG_BASE);
|
||
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, strRegBase, 0, KEY_READ, &hkey) == ERROR_SUCCESS)
|
||
|
{
|
||
|
char szData[MAX_PATH];
|
||
|
DWORD dwType, dwSize = MAX_PATH;
|
||
|
|
||
|
if (RegQueryValueEx(hkey, VAL_CABDEFAULTOPEN, NULL, &dwType, (LPBYTE) szData, &dwSize) == ERROR_SUCCESS)
|
||
|
if (dwType == REG_SZ)
|
||
|
strCABDefaultOpen = szData;
|
||
|
RegCloseKey(hkey);
|
||
|
}
|
||
|
|
||
|
// Look through each of the potential files and file types. If we find
|
||
|
// a match, return TRUE after setting filename appropriately. Note that
|
||
|
// we need to recurse down through directories.
|
||
|
|
||
|
CString strFileSpec;
|
||
|
CStringList filesfound;
|
||
|
POSITION pos;
|
||
|
|
||
|
while (!strCABDefaultOpen.IsEmpty())
|
||
|
{
|
||
|
if (strCABDefaultOpen.Find('|') == -1)
|
||
|
strFileSpec = strCABDefaultOpen;
|
||
|
else
|
||
|
strFileSpec = strCABDefaultOpen.Left(strCABDefaultOpen.Find('|'));
|
||
|
|
||
|
filesfound.RemoveAll();
|
||
|
DirectorySearch(strFileSpec, strDirectory, filesfound);
|
||
|
pos = filesfound.GetHeadPosition();
|
||
|
|
||
|
if (pos != NULL)
|
||
|
{
|
||
|
filename = filesfound.GetNext(pos);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
strCABDefaultOpen = strCABDefaultOpen.Right(strCABDefaultOpen.GetLength() - strFileSpec.GetLength());
|
||
|
if (strCABDefaultOpen.Find('|') == 0)
|
||
|
strCABDefaultOpen = strCABDefaultOpen.Right(strCABDefaultOpen.GetLength() - 1);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//a-kjaw
|
||
|
////Look for incident.xml file. It has to be an unicode file.
|
||
|
strCABDefaultOpen = _T("*.XML");
|
||
|
|
||
|
TCHAR pBuf[MAX_PATH];
|
||
|
WCHAR pwBuf[MAX_PATH];
|
||
|
HANDLE handle;
|
||
|
DWORD dw;
|
||
|
|
||
|
|
||
|
while (!strCABDefaultOpen.IsEmpty())
|
||
|
{
|
||
|
if (strCABDefaultOpen.Find('|') == -1)
|
||
|
strFileSpec = strCABDefaultOpen;
|
||
|
else
|
||
|
strFileSpec = strCABDefaultOpen.Left(strCABDefaultOpen.Find('|'));
|
||
|
|
||
|
filesfound.RemoveAll();
|
||
|
DirectorySearch(strFileSpec, strDirectory, filesfound);
|
||
|
pos = filesfound.GetHeadPosition();
|
||
|
|
||
|
while (pos != NULL)
|
||
|
{
|
||
|
filename = filesfound.GetNext(pos);
|
||
|
|
||
|
handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||
|
if (INVALID_HANDLE_VALUE == handle)
|
||
|
continue;
|
||
|
|
||
|
ReadFile(handle , pBuf , 1 , &dw , NULL);
|
||
|
|
||
|
if( pBuf[0] == _T('<'))
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
ReadFile(handle , pBuf , _tcslen(_T("MachineID")) * sizeof(TCHAR) , &dw , NULL);
|
||
|
if(_tcsicmp(pBuf , _T("MachineID")) == 0)
|
||
|
{
|
||
|
CloseHandle( handle );
|
||
|
return TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetFilePointer(handle , (1 - _tcslen(_T("MachineID")) )* sizeof(TCHAR) , 0 , FILE_CURRENT );
|
||
|
}
|
||
|
}while( dw == _tcslen(_T("MachineID")) );
|
||
|
|
||
|
}
|
||
|
else //Unicode?
|
||
|
{
|
||
|
|
||
|
ReadFile(handle , pwBuf , 1 , &dw , NULL);
|
||
|
do
|
||
|
{
|
||
|
|
||
|
ReadFile(handle , pwBuf , lstrlenW(L"MachineID") * sizeof(WCHAR) , &dw , NULL);
|
||
|
pwBuf[ lstrlenW(L"MachineID") ] = L'\0';
|
||
|
if(lstrcmpiW(pwBuf , L"MachineID") == 0)
|
||
|
{
|
||
|
CloseHandle( handle );
|
||
|
return TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetFilePointer(handle , (1 - lstrlenW(L"MachineID"))* sizeof(WCHAR) , 0 , FILE_CURRENT );
|
||
|
}
|
||
|
}while( dw == _tcslen(_T("MachineID")) * sizeof(WCHAR) );
|
||
|
}
|
||
|
CloseHandle( handle );
|
||
|
}
|
||
|
|
||
|
strCABDefaultOpen = strCABDefaultOpen.Right(strCABDefaultOpen.GetLength() - strFileSpec.GetLength());
|
||
|
if (strCABDefaultOpen.Find('|') == 0)
|
||
|
strCABDefaultOpen = strCABDefaultOpen.Right(strCABDefaultOpen.GetLength() - 1);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// DirectorySearch is used to locate all of the files in a directory or
|
||
|
// one of its subdirectories which match a file spec.
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
void DirectorySearch(const CString & strSpec, const CString & strDir, CStringList &results)
|
||
|
{
|
||
|
// Look for all of the files which match the file spec in the directory
|
||
|
// specified by strDir.
|
||
|
|
||
|
WIN32_FIND_DATA finddata;
|
||
|
CString strSearch, strDirectory;
|
||
|
|
||
|
strDirectory = strDir;
|
||
|
if (strDirectory.Right(1) != CString(cszDirSeparator)) strDirectory += CString(cszDirSeparator);
|
||
|
|
||
|
strSearch = strDirectory + strSpec;
|
||
|
HANDLE hFind = FindFirstFile(strSearch, &finddata);
|
||
|
if (hFind != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
results.AddHead(strDirectory + CString(finddata.cFileName));
|
||
|
} while (FindNextFile(hFind, &finddata));
|
||
|
FindClose(hFind);
|
||
|
}
|
||
|
|
||
|
// Now call this function recursively, with each of the subdirectories.
|
||
|
|
||
|
strSearch = strDirectory + CString(_T("*"));
|
||
|
hFind = FindFirstFile(strSearch, &finddata);
|
||
|
if (hFind != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
if (finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||
|
if (::_tcscmp(finddata.cFileName, _T(".")) != 0 && ::_tcscmp(finddata.cFileName, _T("..")) != 0)
|
||
|
DirectorySearch(strSpec, strDirectory + CString(finddata.cFileName), results);
|
||
|
} while (FindNextFile(hFind, &finddata));
|
||
|
FindClose(hFind);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// This function gets the directory in which to put exploded CAB files.
|
||
|
// This will be the same directory each time, so this function will create
|
||
|
// the directory (if necessary) and delete any files in the directory.
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
BOOL GetCABExplodeDir(CString &destination, BOOL fDeleteFiles, const CString & strDontDelete)
|
||
|
{
|
||
|
CString strMSInfoDir, strExplodeTo, strSubDirName;
|
||
|
|
||
|
// Determine the temporary path and add on a subdir name.
|
||
|
|
||
|
TCHAR szTempDir[MAX_PATH];
|
||
|
|
||
|
if (::GetTempPath(MAX_PATH, szTempDir) > MAX_PATH)
|
||
|
{
|
||
|
destination = _T("");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
strSubDirName.LoadString(IDS_CAB_DIR_NAME);
|
||
|
strExplodeTo = szTempDir;
|
||
|
if (strExplodeTo.Right(1) == CString(cszDirSeparator))
|
||
|
strExplodeTo = strExplodeTo + strSubDirName;
|
||
|
else
|
||
|
strExplodeTo = strExplodeTo + CString(cszDirSeparator) + strSubDirName;
|
||
|
|
||
|
// Kill the directory if it already exists.
|
||
|
|
||
|
if (fDeleteFiles)
|
||
|
KillDirectory(strExplodeTo, strDontDelete);
|
||
|
|
||
|
// Create the subdirectory.
|
||
|
|
||
|
if (!CreateDirectoryEx(szTempDir, strExplodeTo, NULL))
|
||
|
{
|
||
|
if (GetLastError() != ERROR_ALREADY_EXISTS)
|
||
|
{
|
||
|
// MSIError(IDS_GENERAL_ERROR, "couldn't create the target directory");
|
||
|
destination = "";
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
destination = strExplodeTo;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// This functions kills a directory by recursively deleting files and
|
||
|
// subdirectories.
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
void KillDirectory(const CString & strDir, const CString & strDontDelete)
|
||
|
{
|
||
|
CString strDirectory = strDir;
|
||
|
|
||
|
if (strDirectory.Right(1) == CString(cszDirSeparator))
|
||
|
strDirectory = strDirectory.Left(strDirectory.GetLength() - 1);
|
||
|
|
||
|
// Delete any files in directory.
|
||
|
|
||
|
CString strFilesToDelete = strDirectory + CString(_T("\\*.*"));
|
||
|
CString strDeleteFile;
|
||
|
WIN32_FIND_DATA filedata;
|
||
|
BOOL bFound = TRUE;
|
||
|
|
||
|
HANDLE hFindFile = FindFirstFile(strFilesToDelete, &filedata);
|
||
|
while (hFindFile != INVALID_HANDLE_VALUE && bFound)
|
||
|
{
|
||
|
if ((filedata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0L)
|
||
|
{
|
||
|
strDeleteFile = strDirectory + CString(cszDirSeparator) + filedata.cFileName;
|
||
|
|
||
|
if (strDontDelete.CompareNoCase(strDeleteFile) != 0)
|
||
|
{
|
||
|
::SetFileAttributes(strDeleteFile, FILE_ATTRIBUTE_NORMAL);
|
||
|
::DeleteFile(strDeleteFile);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bFound = FindNextFile(hFindFile, &filedata);
|
||
|
}
|
||
|
FindClose(hFindFile);
|
||
|
|
||
|
// Now call this function on any subdirectories in this directory.
|
||
|
|
||
|
CString strSearch = strDirectory + CString(_T("\\*"));
|
||
|
hFindFile = FindFirstFile(strSearch, &filedata);
|
||
|
if (hFindFile != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
if (filedata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||
|
if (::_tcscmp(filedata.cFileName, _T(".")) != 0 && ::_tcscmp(filedata.cFileName, _T("..")) != 0)
|
||
|
KillDirectory(strDirectory + CString(cszDirSeparator) + CString(filedata.cFileName));
|
||
|
} while (FindNextFile(hFindFile, &filedata));
|
||
|
FindClose(hFindFile);
|
||
|
}
|
||
|
|
||
|
// Finally, remove this directory.
|
||
|
|
||
|
::RemoveDirectory(strDirectory);
|
||
|
}
|