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.
501 lines
14 KiB
501 lines
14 KiB
#include <windows.h>
|
|
#include "cdinst.h"
|
|
|
|
|
|
VOID ParseCmdLine(LPSTR pszCmdLine)
|
|
{
|
|
LPSTR pszCurrArg;
|
|
LPSTR pszPtr;
|
|
|
|
GetNextField(&pszCmdLine, "/", 0); // point to the first argument
|
|
while ((pszCurrArg = GetNextField(&pszCmdLine, "/", 0)) != NULL)
|
|
{
|
|
switch (*pszCurrArg)
|
|
{
|
|
case 's':
|
|
case 'S':
|
|
if (*++pszCurrArg == ':')
|
|
pszCurrArg++;
|
|
|
|
// Source dir from where to grab the files
|
|
if ((pszPtr = Trim(GetNextField(&pszCurrArg, ",", REMOVE_QUOTES))) != NULL)
|
|
lstrcpy(g_szSrcDir, pszPtr);
|
|
else
|
|
*g_szSrcDir = '\0';
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
case 'D':
|
|
if (*++pszCurrArg == ':')
|
|
pszCurrArg++;
|
|
|
|
// Destination dir to where to copy the files
|
|
if ((pszPtr = Trim(GetNextField(&pszCurrArg, ",", REMOVE_QUOTES))) != NULL)
|
|
lstrcpy(g_szDstDir, pszPtr);
|
|
else
|
|
*g_szDstDir = '\0';
|
|
|
|
break;
|
|
|
|
default: // ignore these arguments
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
DWORD ReadSectionFromInf(LPCSTR pcszSecName, LPSTR *ppszBuf, PDWORD pdwBufLen, LPCSTR pcszInfName)
|
|
{
|
|
DWORD dwRet;
|
|
|
|
// set the file attrib of pcszInfName to NORMAL so that GetPrivateProfileSecion doesn't
|
|
// barf in case pcszInfName is read only
|
|
SetFileAttributes(pcszInfName, FILE_ATTRIBUTE_NORMAL);
|
|
|
|
// keep allocating buffers in increasing size of 1K till the entire section is read
|
|
*ppszBuf = NULL;
|
|
*pdwBufLen = 1024;
|
|
do
|
|
{
|
|
if (*ppszBuf != NULL)
|
|
LocalFree(*ppszBuf); // free the previously allocated memory
|
|
|
|
if (*pdwBufLen == MAX_BUF_LEN)
|
|
(*pdwBufLen)--; // 32K - 1 is the size limit for a section
|
|
|
|
if ((*ppszBuf = (LPSTR) LocalAlloc(LPTR, *pdwBufLen)) == NULL)
|
|
{
|
|
*pdwBufLen = 0;
|
|
return 0;
|
|
}
|
|
} while ((dwRet = GetPrivateProfileSection(pcszSecName, *ppszBuf, *pdwBufLen, pcszInfName)) == *pdwBufLen - 2 &&
|
|
(*pdwBufLen += 1024) <= MAX_BUF_LEN);
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
BOOL PathExists(LPCSTR pcszDir)
|
|
{
|
|
DWORD dwAttrib = GetFileAttributes(pcszDir);
|
|
|
|
return (dwAttrib != (DWORD) -1) && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY);
|
|
}
|
|
|
|
|
|
BOOL FileExists(LPCSTR pcszFileName)
|
|
{
|
|
DWORD dwAttrib = GetFileAttributes(pcszFileName);
|
|
|
|
if (dwAttrib == (DWORD) -1)
|
|
return FALSE;
|
|
|
|
return !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY);
|
|
}
|
|
|
|
|
|
DWORD FileSize(LPCSTR pcszFile)
|
|
{
|
|
DWORD dwFileSize = 0;
|
|
WIN32_FIND_DATA FindFileData;
|
|
HANDLE hFile;
|
|
|
|
if (pcszFile == NULL || *pcszFile == '\0')
|
|
return dwFileSize;
|
|
|
|
if ((hFile = FindFirstFile(pcszFile, &FindFileData)) != INVALID_HANDLE_VALUE)
|
|
{
|
|
// assumption here is that the size of the file doesn't exceed 4 gigs
|
|
dwFileSize = FindFileData.nFileSizeLow;
|
|
FindClose(hFile);
|
|
}
|
|
|
|
return dwFileSize;
|
|
}
|
|
|
|
|
|
LPSTR AddPath(LPSTR pszPath, LPCSTR pcszFileName)
|
|
{
|
|
LPSTR pszPtr;
|
|
|
|
if (pszPath == NULL)
|
|
return NULL;
|
|
|
|
pszPtr = pszPath + lstrlen(pszPath);
|
|
if (pszPtr > pszPath && *CharPrev(pszPath, pszPtr) != '\\')
|
|
*pszPtr++ = '\\';
|
|
|
|
if (pcszFileName != NULL)
|
|
lstrcpy(pszPtr, pcszFileName);
|
|
else
|
|
*pszPtr = '\0';
|
|
|
|
return pszPath;
|
|
}
|
|
|
|
|
|
BOOL PathIsUNCServer(LPCSTR pcszPath)
|
|
{
|
|
if (PathIsUNC(pcszPath))
|
|
{
|
|
int i = 0;
|
|
|
|
for ( ; pcszPath != NULL && *pcszPath; pcszPath = CharNext(pcszPath))
|
|
if (*pcszPath == '\\')
|
|
i++;
|
|
|
|
return i == 2;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL PathIsUNCServerShare(LPCSTR pcszPath)
|
|
{
|
|
if (PathIsUNC(pcszPath))
|
|
{
|
|
int i = 0;
|
|
|
|
for ( ; pcszPath != NULL && *pcszPath; pcszPath = CharNext(pcszPath))
|
|
if (*pcszPath == '\\')
|
|
i++;
|
|
|
|
return i == 3;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL PathCreatePath(LPCSTR pcszPathToCreate)
|
|
{
|
|
CHAR szPath[MAX_PATH];
|
|
LPSTR pszPtr;
|
|
|
|
if (pcszPathToCreate == NULL || lstrlen(pcszPathToCreate) <= 3)
|
|
return FALSE;
|
|
|
|
// eliminate relative paths
|
|
if (!PathIsFullPath(pcszPathToCreate) && !PathIsUNC(pcszPathToCreate))
|
|
return FALSE;
|
|
|
|
if (PathIsUNCServer(pcszPathToCreate) || PathIsUNCServerShare(pcszPathToCreate))
|
|
return FALSE;
|
|
|
|
lstrcpy(szPath, pcszPathToCreate);
|
|
|
|
// chop off the trailing backslash, if it exists
|
|
pszPtr = CharPrev(szPath, szPath + lstrlen(szPath));
|
|
if (*pszPtr == '\\')
|
|
*pszPtr = '\0';
|
|
|
|
// if it's a UNC path, seek up to the first dir after the share name
|
|
if (PathIsUNC(szPath))
|
|
{
|
|
INT i;
|
|
|
|
pszPtr = &szPath[2];
|
|
|
|
for (i = 0; i < 2; i++)
|
|
for ( ; *pszPtr != '\\'; pszPtr = CharNext(pszPtr))
|
|
;
|
|
|
|
pszPtr = CharNext(pszPtr);
|
|
}
|
|
else // otherwise, just point to the beginning of the first dir
|
|
pszPtr = &szPath[3];
|
|
|
|
for ( ; *pszPtr; pszPtr = CharNext(pszPtr))
|
|
{
|
|
CHAR ch;
|
|
|
|
// skip the non-backslash chars
|
|
while (*pszPtr && *pszPtr != '\\')
|
|
pszPtr = CharNext(pszPtr);
|
|
|
|
// save the current char
|
|
ch = *pszPtr;
|
|
|
|
*pszPtr = '\0';
|
|
if (GetFileAttributes(szPath) == 0xFFFFFFFF) // dir doesn't exist
|
|
if (!CreateDirectory(szPath, NULL))
|
|
return FALSE;
|
|
|
|
// restore the current char
|
|
*pszPtr = ch;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID ErrorMsg(UINT uStringID)
|
|
{
|
|
ErrorMsg(uStringID, "", "");
|
|
}
|
|
|
|
|
|
VOID ErrorMsg(UINT uStringID, LPCSTR pcszParam1, LPCSTR pcszParam2)
|
|
{
|
|
LPSTR pszTextString;
|
|
|
|
pszTextString = FormatMessageString(uStringID, pcszParam1, pcszParam2);
|
|
|
|
MessageBox(NULL, (pszTextString != NULL) ? pszTextString : "", g_szTitle, MB_ICONEXCLAMATION | MB_SETFOREGROUND | MB_OK);
|
|
|
|
if (pszTextString != NULL)
|
|
LocalFree(pszTextString);
|
|
}
|
|
|
|
|
|
INT ErrorMsg(UINT uStringID, DWORD dwParam1, DWORD dwParam2)
|
|
{
|
|
INT iRet;
|
|
LPSTR pszTextString;
|
|
|
|
pszTextString = FormatMessageString(uStringID, dwParam1, dwParam2);
|
|
|
|
iRet = MessageBox(NULL, (pszTextString != NULL) ? pszTextString : "", g_szTitle, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2 | MB_SETFOREGROUND);
|
|
|
|
if (pszTextString != NULL)
|
|
LocalFree(pszTextString);
|
|
|
|
return iRet;
|
|
}
|
|
|
|
|
|
LPSTR FormatMessageString(UINT uStringID, LPCSTR pcszParam1, LPCSTR pcszParam2)
|
|
{
|
|
CHAR szBuf[512];
|
|
|
|
if (LoadString(g_hInst, uStringID, szBuf, sizeof(szBuf)))
|
|
{
|
|
LPSTR pszTextString;
|
|
|
|
if ((pszTextString = FormatString(szBuf, pcszParam1, pcszParam2)) != NULL)
|
|
return pszTextString;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
LPSTR FormatMessageString(UINT uStringID, DWORD dwParam1, DWORD dwParam2)
|
|
{
|
|
CHAR szBuf[512];
|
|
|
|
if (LoadString(g_hInst, uStringID, szBuf, sizeof(szBuf)))
|
|
{
|
|
LPSTR pszTextString;
|
|
|
|
if ((pszTextString = FormatString(szBuf, dwParam1, dwParam2)) != NULL)
|
|
return pszTextString;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
LPSTR FormatString(LPCSTR pcszFormatString, ...)
|
|
{
|
|
va_list vaArgs;
|
|
LPSTR pszOutString = NULL;
|
|
|
|
va_start(vaArgs, pcszFormatString);
|
|
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_STRING,
|
|
(LPCVOID) pcszFormatString, 0, 0, (PSTR) &pszOutString, 0, &vaArgs);
|
|
va_end(vaArgs);
|
|
|
|
return pszOutString;
|
|
}
|
|
|
|
|
|
LPSTR GetNextField(LPSTR *ppszData, LPCSTR pcszDeLims, DWORD dwFlags)
|
|
// If (dwFlags & IGNORE_QUOTES) is TRUE, then look for any char in pcszDeLims in *ppszData. If found,
|
|
// replace it with the '\0' char and set *ppszData to point to the beginning of the next field and return
|
|
// pointer to current field.
|
|
//
|
|
// If (dwFlags & IGNORE_QUOTES) is FALSE, then look for any char in pcszDeLims outside of balanced quoted sub-strings
|
|
// in *ppszData. If found, replace it with the '\0' char and set *ppszData to point to the beginning of
|
|
// the next field and return pointer to current field.
|
|
//
|
|
// If (dwFlags & REMOVE_QUOTES) is TRUE, then remove the surrounding quotes and replace two consecutive quotes by one.
|
|
//
|
|
// NOTE: If IGNORE_QUOTES and REMOVE_QUOTES are both specified, then IGNORE_QUOTES takes precedence over REMOVE_QUOTES.
|
|
//
|
|
// If you just want to remove the quotes from a string, call this function as
|
|
// GetNextField(&pszData, "\"" or "'" or "", REMOVE_QUOTES).
|
|
//
|
|
// If you call this function as GetNextField(&pszData, "\"" or "'" or "", 0), you will get back the
|
|
// entire pszData as the field.
|
|
//
|
|
{
|
|
LPSTR pszRetPtr, pszPtr;
|
|
BOOL fWithinQuotes = FALSE, fRemoveQuote;
|
|
CHAR chQuote;
|
|
|
|
if (ppszData == NULL || *ppszData == NULL || **ppszData == '\0')
|
|
return NULL;
|
|
|
|
for (pszRetPtr = pszPtr = *ppszData; *pszPtr; pszPtr = CharNext(pszPtr))
|
|
{
|
|
if (!(dwFlags & IGNORE_QUOTES) && (*pszPtr == '"' || *pszPtr == '\''))
|
|
{
|
|
fRemoveQuote = FALSE;
|
|
|
|
if (*pszPtr == *(pszPtr + 1)) // two consecutive quotes become one
|
|
{
|
|
pszPtr++;
|
|
|
|
if (dwFlags & REMOVE_QUOTES)
|
|
fRemoveQuote = TRUE;
|
|
else
|
|
{
|
|
// if pcszDeLims is '"' or '\'', then *pszPtr == pcszDeLims would
|
|
// be TRUE and we would break out of the loop against the design specs;
|
|
// to prevent this just continue
|
|
continue;
|
|
}
|
|
}
|
|
else if (!fWithinQuotes)
|
|
{
|
|
fWithinQuotes = TRUE;
|
|
chQuote = *pszPtr; // save the quote char
|
|
|
|
fRemoveQuote = dwFlags & REMOVE_QUOTES;
|
|
}
|
|
else
|
|
{
|
|
if (*pszPtr == chQuote) // match the correct quote char
|
|
{
|
|
fWithinQuotes = FALSE;
|
|
fRemoveQuote = dwFlags & REMOVE_QUOTES;
|
|
}
|
|
}
|
|
|
|
if (fRemoveQuote)
|
|
{
|
|
// shift the entire string one char to the left to get rid of the quote char
|
|
MoveMemory(pszPtr, pszPtr + 1, lstrlen(pszPtr));
|
|
}
|
|
}
|
|
|
|
// BUGBUG: Is type casting pszPtr to UNALIGNED necessary? -- copied it from ANSIStrChr
|
|
// check if pszPtr is pointing to one of the chars in pcszDeLims
|
|
if (!fWithinQuotes &&
|
|
ANSIStrChr(pcszDeLims, (WORD) (IsDBCSLeadByte(*pszPtr) ? *((UNALIGNED WORD *) pszPtr) : *pszPtr)) != NULL)
|
|
break;
|
|
}
|
|
|
|
// NOTE: if fWithinQuotes is TRUE here, then we have an unbalanced quoted string; but we don't care!
|
|
// the entire string after the beginning quote becomes the field
|
|
|
|
if (*pszPtr) // pszPtr is pointing to a char in pcszDeLims
|
|
{
|
|
*ppszData = CharNext(pszPtr); // save the pointer to the beginning of next field in *ppszData
|
|
*pszPtr = '\0'; // replace the DeLim char with the '\0' char
|
|
}
|
|
else
|
|
*ppszData = pszPtr; // we have reached the end of the string; next call to this function
|
|
// would return NULL
|
|
|
|
return pszRetPtr;
|
|
}
|
|
|
|
|
|
LPSTR Trim(LPSTR pszData)
|
|
// Trim the leading and trailing white space chars in pszData
|
|
{
|
|
LPSTR pszRetPtr;
|
|
|
|
if (pszData == NULL)
|
|
return NULL;
|
|
|
|
// trim the leading white space chars
|
|
for ( ; *pszData; pszData = CharNext(pszData))
|
|
if (!IsSpace(*pszData))
|
|
break;
|
|
|
|
// save the return ptr
|
|
pszRetPtr = pszData;
|
|
|
|
// go to the end and start trimming the trailing white space chars
|
|
pszData += lstrlen(pszData);
|
|
while ((pszData = CharPrev(pszRetPtr, pszData)) != pszRetPtr)
|
|
if (!IsSpace(*pszData))
|
|
break;
|
|
|
|
if (*pszData)
|
|
{
|
|
pszData = CharNext(pszData);
|
|
*pszData = '\0';
|
|
}
|
|
|
|
return pszRetPtr;
|
|
}
|
|
|
|
|
|
// copied from \\trango\slmadd\src\shell\shlwapi\strings.c
|
|
/*
|
|
* StrChr - Find first occurrence of character in string
|
|
* Assumes lpStart points to start of null terminated string
|
|
* wMatch is the character to match
|
|
* returns ptr to the first occurrence of ch in str, NULL if not found.
|
|
*/
|
|
LPSTR FAR ANSIStrChr(LPCSTR lpStart, WORD wMatch)
|
|
{
|
|
for ( ; *lpStart; lpStart = CharNext(lpStart))
|
|
{
|
|
// (ChrCmp returns FALSE when characters match)
|
|
|
|
if (!ChrCmpA_inline(*(UNALIGNED WORD FAR *)lpStart, wMatch))
|
|
return((LPSTR)lpStart);
|
|
}
|
|
return (NULL);
|
|
}
|
|
|
|
|
|
// copied from \\trango\slmadd\src\shell\shlwapi\strings.c
|
|
/*
|
|
* StrRChr - Find last occurrence of character in string
|
|
* Assumes lpStart points to start of null terminated string
|
|
* wMatch is the character to match
|
|
* returns ptr to the last occurrence of ch in str, NULL if not found.
|
|
*/
|
|
LPSTR FAR ANSIStrRChr(LPCSTR lpStart, WORD wMatch)
|
|
{
|
|
LPCSTR lpFound = NULL;
|
|
|
|
for ( ; *lpStart; lpStart = CharNext(lpStart))
|
|
{
|
|
// (ChrCmp returns FALSE when characters match)
|
|
|
|
if (!ChrCmpA_inline(*(UNALIGNED WORD FAR *)lpStart, wMatch))
|
|
lpFound = lpStart;
|
|
}
|
|
return ((LPSTR)lpFound);
|
|
}
|
|
|
|
|
|
// copied from \\trango\slmadd\src\shell\shlwapi\strings.c
|
|
/*
|
|
* ChrCmp - Case sensitive character comparison for DBCS
|
|
* Assumes w1, wMatch are characters to be compared
|
|
* Return FALSE if they match, TRUE if no match
|
|
*/
|
|
__inline BOOL ChrCmpA_inline(WORD w1, WORD wMatch)
|
|
{
|
|
/* Most of the time this won't match, so test it first for speed.
|
|
*/
|
|
if (LOBYTE(w1) == LOBYTE(wMatch))
|
|
{
|
|
if (IsDBCSLeadByte(LOBYTE(w1)))
|
|
{
|
|
return(w1 != wMatch);
|
|
}
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|