windows-nt/Source/XPSP1/NT/base/mvdm/wow16/commdlg/parse.c
2020-09-26 16:20:57 +08:00

370 lines
11 KiB
C

#define NOCOMM
#define NOWH
#include "windows.h"
#include "parse.h"
#define chSpace ' '
#define chPeriod '.'
long ParseFile(ULPSTR lpstrFileName);
LPSTR mystrchr(LPSTR, int);
#define chMatchOne '?'
#define chMatchAny '*'
LPSTR mystrchr(LPSTR str, int ch)
{
while(*str)
{
if (ch == *str)
return(str);
str = AnsiNext(str);
}
return(NULL);
}
/*---------------------------------------------------------------------------
* GetFileTitle
* Purpose: API to outside world to obtain the title of a file given the
* file name. Useful if file name received via some method
* other that GetOpenFileName (e.g. command line, drag drop).
* Assumes: lpszFile points to NULL terminated DOS filename (may have path)
* lpszTitle points to buffer to receive NULL terminated file title
* wBufSize is the size of buffer pointed to by lpszTitle
* Returns: 0 on success
* < 0, Parsing failure (invalid file name)
* > 0, buffer too small, size needed (including NULL terminator)
*--------------------------------------------------------------------------*/
short FAR PASCAL
GetFileTitle(LPCSTR lpszFile, LPSTR lpszTitle, WORD wBufSize)
{
short nNeeded;
LPSTR lpszPtr;
nNeeded = (WORD) ParseFile((ULPSTR)lpszFile);
if (nNeeded >= 0) /* Is the filename valid? */
{
lpszPtr = (LPSTR)lpszFile + nNeeded;
if ((nNeeded = (short)(lstrlen(lpszPtr) + 1)) <= (short) wBufSize)
{
/* ParseFile() fails if wildcards in directory, but OK if in name */
/* Since they aren't OK here, the check needed here */
if (mystrchr(lpszPtr, chMatchAny) || mystrchr(lpszPtr, chMatchOne))
{
nNeeded = PARSE_WILDCARDINFILE; /* Failure */
}
else
{
lstrcpy(lpszTitle, lpszPtr);
nNeeded = 0; /* Success */
}
}
}
return(nNeeded);
}
/*---------------------------------------------------------------------------
* ParseFile
* Purpose: Determine if the filename is a legal DOS name
* Input: Long pointer to a SINGLE file name
* Circumstance checked:
* 1) Valid as directory name, but not as file name
* 2) Empty String
* 3) Illegal Drive label
* 4) Period in invalid location (in extention, 1st in file name)
* 5) Missing directory character
* 6) Illegal character
* 7) Wildcard in directory name
* 8) Double slash beyond 1st 2 characters
* 9) Space character in the middle of the name (trailing spaces OK)
* 10) Filename greater than 8 characters
* 11) Extention greater than 3 characters
* Notes:
* Filename length is NOT checked.
* Valid filenames will have leading spaces, trailing spaces and
* terminating period stripped in place.
*
* Returns: If valid, LOWORD is byte offset to filename
* HIWORD is byte offset to extention
* if string ends with period, 0
* if no extention is given, string length
* If invalid, LOWORD is error code suggesting problem (< 0)
* HIWORD is approximate offset where problem found
* Note that this may be beyond the offending character
* History:
* Thu 24-Jan-1991 12:20:00 -by- Clark R. Cyr [clarkc]
* Initial writing
* Thu 21-Feb-1991 10:19:00 -by- Clark R. Cyr [clarkc]
* Changed to unsigned character pointer
*--------------------------------------------------------------------------*/
long ParseFile(ULPSTR lpstrFileName)
{
short nFile, nExt, nFileOffset, nExtOffset;
BOOL bExt;
BOOL bWildcard;
short nNetwork = 0;
BOOL bUNCPath = FALSE;
ULPSTR lpstr = lpstrFileName;
/* Strip off initial white space. Note that TAB is not checked */
/* because it cannot be received out of a standard edit control */
/* 30 January 1991 clarkc */
while (*lpstr == chSpace)
lpstr++;
if (!*lpstr)
{
nFileOffset = PARSE_EMPTYSTRING;
goto FAILURE;
}
if (lpstr != lpstrFileName)
{
lstrcpy((LPSTR)lpstrFileName, (LPSTR)lpstr);
lpstr = lpstrFileName;
}
if (*AnsiNext((LPSTR)lpstr) == ':')
{
unsigned char cDrive = (unsigned char)((*lpstr | (unsigned char) 0x20)); /* make lowercase */
/* This does not test if the drive exists, only if it's legal */
if ((cDrive < 'a') || (cDrive > 'z'))
{
nFileOffset = PARSE_INVALIDDRIVE;
goto FAILURE;
}
lpstr = (ULPSTR)AnsiNext(AnsiNext((LPSTR)lpstr));
}
if ((*lpstr == '\\') || (*lpstr == '/'))
{
if (*++lpstr == chPeriod) /* cannot have c:\. */
{
if ((*++lpstr != '\\') && (*lpstr != '/'))
{
if (!*lpstr) /* it's the root directory */
goto MustBeDir;
nFileOffset = PARSE_INVALIDPERIOD;
goto FAILURE;
}
else
++lpstr; /* it's saying top directory (again), thus allowed */
}
else if ((*lpstr == '\\') && (*(lpstr-1) == '\\'))
{
/* It seems that for a full network path, whether a drive is declared or
* not is insignificant, though if a drive is given, it must be valid
* (hence the code above should remain there).
* 13 February 1991 clarkc
*/
++lpstr; /* ...since it's the first slash, 2 are allowed */
nNetwork = -1; /* Must receive server and share to be real */
bUNCPath = TRUE; /* No wildcards allowed if UNC name */
}
else if (*lpstr == '/')
{
nFileOffset = PARSE_INVALIDDIRCHAR;
goto FAILURE;
}
}
else if (*lpstr == chPeriod)
{
if (*++lpstr == chPeriod) /* Is this up one directory? */
++lpstr;
if (!*lpstr)
goto MustBeDir;
if ((*lpstr != '\\') && (*lpstr != '/'))
{
nFileOffset = PARSE_INVALIDPERIOD;
goto FAILURE;
}
else
++lpstr; /* it's saying directory, thus allowed */
}
if (!*lpstr)
{
goto MustBeDir;
}
/* Should point to first char in 8.3 filename by now */
nFileOffset = nExtOffset = nFile = nExt = 0;
bWildcard = bExt = FALSE;
while (*lpstr)
{
/*
* The next comparison MUST be unsigned to allow for extended characters!
* 21 Feb 1991 clarkc
*/
if (*lpstr < chSpace)
{
nFileOffset = PARSE_INVALIDCHAR;
goto FAILURE;
}
switch (*lpstr)
{
case '"': /* All invalid */
case '+':
case ',':
case ':':
case ';':
case '<':
case '=':
case '>':
case '[':
case ']':
case '|':
{
nFileOffset = PARSE_INVALIDCHAR;
goto FAILURE;
}
case '\\': /* Subdirectory indicators */
case '/':
nNetwork++;
if (bWildcard)
{
nFileOffset = PARSE_WILDCARDINDIR;
goto FAILURE;
}
else if (nFile == 0) /* can't have 2 in a row */
{
nFileOffset = PARSE_INVALIDDIRCHAR;
goto FAILURE;
}
else
{ /* reset flags */
++lpstr;
if (!nNetwork && !*lpstr)
{
nFileOffset = PARSE_INVALIDNETPATH;
goto FAILURE;
}
nFile = nExt = 0;
bExt = FALSE;
}
break;
case chSpace:
{
ULPSTR lpSpace = lpstr;
*lpSpace = '\0';
while (*++lpSpace)
{
if (*lpSpace != chSpace)
{
*lpstr = chSpace; /* Reset string, abandon ship */
nFileOffset = PARSE_INVALIDSPACE;
goto FAILURE;
}
}
}
break;
case chPeriod:
if (nFile == 0)
{
if (*++lpstr == chPeriod)
++lpstr;
if (!*lpstr)
goto MustBeDir;
if ((*lpstr != '\\') && (*lpstr != '/'))
{
nFileOffset = PARSE_INVALIDPERIOD;
goto FAILURE;
}
++lpstr; /* Flags are already set */
}
else if (bExt)
{
nFileOffset = PARSE_INVALIDPERIOD; /* can't have one in ext */
goto FAILURE;
}
else
{
nExtOffset = 0;
++lpstr;
bExt = TRUE;
}
break;
case '*':
case '?':
if (bUNCPath)
{
nFileOffset = PARSE_INVALIDNETPATH;
goto FAILURE;
}
bWildcard = TRUE;
/* Fall through to normal character processing */
default:
if (bExt)
{
if (++nExt == 1)
nExtOffset = (short)(lpstr - lpstrFileName);
else if (nExt > 3)
{
nFileOffset = PARSE_EXTENTIONTOOLONG;
goto FAILURE;
}
if ((nNetwork == -1) && (nFile + nExt > 11))
{
nFileOffset = PARSE_INVALIDNETPATH;
goto FAILURE;
}
}
else if (++nFile == 1)
nFileOffset = (short)(lpstr - lpstrFileName);
else if (nFile > 8)
{
/* If it's a server name, it can have 11 characters */
if (nNetwork != -1)
{
nFileOffset = PARSE_FILETOOLONG;
goto FAILURE;
}
else if (nFile > 11)
{
nFileOffset = PARSE_INVALIDNETPATH;
goto FAILURE;
}
}
lpstr = (ULPSTR)AnsiNext((LPSTR)lpstr);
break;
}
}
/* Did we start with a double backslash but not have any more slashes? */
if (nNetwork == -1)
{
nFileOffset = PARSE_INVALIDNETPATH;
goto FAILURE;
}
if (!nFile)
{
MustBeDir:
nFileOffset = PARSE_DIRECTORYNAME;
goto FAILURE;
}
if ((*(lpstr - 1) == chPeriod) && /* if true, no extention wanted */
(*AnsiNext((LPSTR)(lpstr-2)) == chPeriod))
*(lpstr - 1) = '\0'; /* Remove terminating period */
else if (!nExt)
FAILURE:
nExtOffset = (short)(lpstr - lpstrFileName);
return(MAKELONG(nFileOffset, nExtOffset));
}