mirror of
https://github.com/microsoft/Microsoft-3D-Movie-Maker.git
synced 2024-11-22 10:22:40 +01:00
567 lines
12 KiB
C
567 lines
12 KiB
C
/* Copyright (c) Microsoft Corporation.
|
|
Licensed under the MIT License. */
|
|
|
|
/***************************************************************************
|
|
**
|
|
** File: PARSECA.C
|
|
** Purpose: Custom Action data parsing routines
|
|
** for the Sample App DLL.
|
|
** Notes:
|
|
**
|
|
****************************************************************************/
|
|
|
|
#define PARSECA_C
|
|
|
|
#include "stdinc.h"
|
|
#include <stdlib.h> /* _MAX_PATH */
|
|
#include <ctype.h> /* isdigit */
|
|
#include "setupapi.h"
|
|
#include "cui.h"
|
|
#include "stdtypes.h"
|
|
#include "setupkit.h"
|
|
#include "datadef.h"
|
|
#include "parseca.h"
|
|
#include "sampcacb.h"
|
|
|
|
|
|
/* REVIEW: Put the strings in sampsz.h.
|
|
*/
|
|
#define STR_BADSECT_ERR "InstallWinPermFile Object: Bad INF Section data value"
|
|
#define STR_BADKEY_ERR "InstallWinPermFile Object: Bad INF Key data value"
|
|
#define STR_XTRADATA_ERR "InstallWinPermFile Object: extra unrecognized data values"
|
|
#define STR_PARSE_ERR "Setup Parse Error in Initialize pass"
|
|
#define STR_OBJID "Object ID %d: %s."
|
|
#define STR_MISSING_ERR "SingSelListDlg Object: Missing data value"
|
|
#define STR_BADDATA_ERR "SingSelListDlg Object: Bad data value"
|
|
#define STR_OBJID_ERR "Syntax Error in List of Obj IDs"
|
|
|
|
|
|
const CHAR chFieldSep = chTab;
|
|
#define FWhiteSpaceCh(ch) ((BOOL)((ch) == chSpace || (ch) == chTab))
|
|
#define chLorSep chComma
|
|
|
|
|
|
/*
|
|
****************************************************************************/
|
|
RC PUBLIC RcParseInfSectKey ( OR orCur, SZ szData, PSZ pszInfSect,
|
|
PSZ pszInfKey )
|
|
{
|
|
Assert(szData != szNull);
|
|
Assert(pszInfSect != pszNull);
|
|
Assert(pszInfKey != pszNull);
|
|
|
|
if (*pszInfSect != szNull) /* Already parsed and alloc'ed? */
|
|
return (rcOk);
|
|
|
|
if (!FReadDataFieldString(&szData, pszInfSect))
|
|
return (rcFail);
|
|
Assert(*pszInfSect != szNull);
|
|
if (!FValidInfSection(*pszInfSect) || !DoesInfSectionExist(*pszInfSect))
|
|
{
|
|
ParseError(orCur, STR_BADSECT_ERR);
|
|
return (rcFail);
|
|
}
|
|
|
|
if (!FReadDataFieldString(&szData, pszInfKey))
|
|
return (rcFail);
|
|
Assert(*pszInfKey != szNull);
|
|
if (!FValidInfKey(*pszInfKey)
|
|
|| !DoesInfSectionKeyExist(*pszInfSect, *pszInfKey))
|
|
{
|
|
ParseError(orCur, STR_BADKEY_ERR);
|
|
return (rcFail);
|
|
}
|
|
|
|
if (*szData != chEos)
|
|
{
|
|
ParseError(orCur, STR_XTRADATA_ERR);
|
|
return (rcFail);
|
|
}
|
|
|
|
return (rcOk);
|
|
}
|
|
|
|
|
|
/*
|
|
************************************************************************/
|
|
RC PUBLIC RcParseLor ( PCD pcd, OR orCur, SZ szData, PPLOR pplor )
|
|
{
|
|
Assert(pcd != lpvoidNull);
|
|
Assert(FValidOr(pcd, orCur));
|
|
Assert(szData != szNull);
|
|
Assert(pplor != pplorNull);
|
|
|
|
if (*pplor != plorNull)
|
|
return (rcOk);
|
|
|
|
while (FWhiteSpaceCh(*szData))
|
|
szData = SzNextChar(szData);
|
|
|
|
if (*szData == chEos)
|
|
{
|
|
ParseError(orCur, STR_MISSING_ERR);
|
|
return (rcFail);
|
|
}
|
|
|
|
/* OOM or non-digit chars msg handled inside PlorFromSz()
|
|
*/
|
|
if ((*pplor = PlorFromSz(orCur, szData)) == plorNull)
|
|
return (rcFail);
|
|
|
|
if (!FValidGroupPlor(pcd, *pplor, orCur))
|
|
{
|
|
FFreePlor(pplor);
|
|
ParseError(orCur, STR_BADDATA_ERR);
|
|
return (rcFail);
|
|
}
|
|
|
|
return (rcOk);
|
|
}
|
|
|
|
|
|
/*
|
|
************************************************************************/
|
|
BOOL PUBLIC FReadDataFieldString ( PSZ pszData, PSZ pszMember )
|
|
{
|
|
CHAR rgch[cchSzMax];
|
|
|
|
Assert(pszData != pszNull);
|
|
Assert(*pszData != szNull);
|
|
Assert(pszMember != pszNull);
|
|
|
|
*pszData = SzGetTableField(*pszData, rgch, cchSzMax, chComma);
|
|
|
|
if (*pszData == szNull)
|
|
return (fFalse);
|
|
|
|
if ((*pszMember = SzStrDupl(rgch)) == szNull)
|
|
return (fFalse);
|
|
|
|
return (fTrue);
|
|
}
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Duplicates a string.
|
|
** Arguments:
|
|
** sz: string to duplicate.
|
|
** Returns:
|
|
** duplicated string if successful, szNull if not.
|
|
** Notes:
|
|
****************************************************************************/
|
|
SZ PUBLIC SzStrDupl ( SZ sz )
|
|
{
|
|
SZ szNew;
|
|
|
|
Assert(sz != szNull);
|
|
|
|
while ((szNew = (SZ)PbAlloc(CbStrLen(sz) + 1)) == szNull)
|
|
{
|
|
if (!FHandleOOM())
|
|
return (szNull);
|
|
}
|
|
SzStrCopy(szNew, sz);
|
|
return (szNew);
|
|
}
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Determine if a string is a valid Inf section.
|
|
** Arguments:
|
|
** szSection: The section.
|
|
** Returns:
|
|
** fTrue if the string is valid, fFalse otherwise.
|
|
** Notes:
|
|
**
|
|
****************************************************************************/
|
|
BOOL PUBLIC FValidInfSection ( SZ szSection )
|
|
{
|
|
SZ szLast;
|
|
|
|
if (FEmptySz(szSection))
|
|
return (fFalse);
|
|
|
|
if (*szSection == chSpace)
|
|
return (fFalse);
|
|
|
|
szLast = szSection;
|
|
while (*szSection != chEos)
|
|
{
|
|
if (*szSection == chRgtSqBracket)
|
|
return (fFalse);
|
|
szLast = szSection;
|
|
szSection = SzNextChar(szSection);
|
|
}
|
|
|
|
if (*szLast == chSpace)
|
|
return (fFalse);
|
|
|
|
return (fTrue);
|
|
}
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Determine if a string is a valid Inf key.
|
|
** Arguments:
|
|
** szKey: The key.
|
|
** Returns:
|
|
** fTrue if the string is valid, fFalse otherwise.
|
|
** Notes:
|
|
**
|
|
****************************************************************************/
|
|
BOOL PUBLIC FValidInfKey ( SZ szKey )
|
|
{
|
|
SZ szLast;
|
|
|
|
if (FEmptySz(szKey))
|
|
return (fFalse);
|
|
|
|
if (*szKey == chSpace || *szKey == chLftSqBracket)
|
|
return (fFalse);
|
|
|
|
szLast = szKey;
|
|
while (*szKey != chEos)
|
|
{
|
|
if (*szKey == chEquals)
|
|
return (fFalse);
|
|
szLast = szKey;
|
|
szKey = SzNextChar(szKey);
|
|
}
|
|
|
|
if (*szLast == chSpace)
|
|
return (fFalse);
|
|
|
|
return (fTrue);
|
|
}
|
|
|
|
|
|
/*
|
|
** Notes
|
|
** Each OR in the PLOR must be greater than the group OR (which
|
|
** implicitly is greater than orNil). This prevents circular
|
|
** references and makes processing easier since it can run top
|
|
** to bottom.
|
|
************************************************************************/
|
|
BOOL PUBLIC FValidGroupPlor ( PCD pcd, PLOR plor, OR orGroup )
|
|
{
|
|
UINT ior;
|
|
|
|
Assert(plor != plorNull);
|
|
Assert(plor->cor > 0);
|
|
Assert(plor->rgor != rgorNull);
|
|
Assert(orGroup != orNil);
|
|
|
|
for (ior = 0; ior < plor->cor; ior++)
|
|
{
|
|
OR or = plor->rgor[ior];
|
|
UINT iorT;
|
|
|
|
if (or <= orGroup
|
|
|| or >= pcd->cObjectsMax
|
|
|| PodGetObjData(pcd, or) == podNull)
|
|
{
|
|
return (fFalse);
|
|
}
|
|
|
|
|
|
for (iorT = ior + 1; iorT < plor->cor; iorT++)
|
|
{
|
|
if (or == plor->rgor[iorT])
|
|
return (fFalse);
|
|
}
|
|
}
|
|
|
|
return (fTrue);
|
|
}
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Show a Message Box with the appropriate info.
|
|
** Arguments:
|
|
** or: object reference number.
|
|
** szcMsg: The error message.
|
|
** Returns:
|
|
** none.
|
|
** Notes:
|
|
**
|
|
****************************************************************************/
|
|
VOID PUBLIC ParseError ( OR or, SZ szMsg )
|
|
{
|
|
CHAR rgchText[2*cchSzMax];
|
|
|
|
Assert(CbStrLen(STR_OBJID) + 5 + CbStrLen(szMsg) < sizeof rgchText);
|
|
wsprintf(rgchText, STR_OBJID, or, szMsg);
|
|
DoMsgBox(rgchText, STR_PARSE_ERR, MB_OK | MB_ICONEXCLAMATION);
|
|
}
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Extract the first field in szLine.
|
|
** Arguments:
|
|
** szLine: The buffer to parse for a field.
|
|
** szField: The buffer to receive the field.
|
|
** cbFieldMax: The size of the output buffer.
|
|
** chSep: The separator character.
|
|
** Returns:
|
|
** A pointer to the start of the next field in szLine.
|
|
** szNull if an error was detected.
|
|
** Notes:
|
|
**
|
|
****************************************************************************/
|
|
SZ PUBLIC SzGetTableField ( SZ szLine, SZ szField, CB cbFieldMax,
|
|
CHAR chSep )
|
|
{
|
|
BOOL fQuotedField = fFalse;
|
|
BOOL fInQuotedField = fFalse;
|
|
CB cbFieldMaxCur = cbFieldMax;
|
|
SZ szFieldEnd = szField;
|
|
#ifdef DEBUG
|
|
SZ szLineStart = szLine;
|
|
SZ szFieldStart = szField;
|
|
#endif
|
|
|
|
Assert(szLine != szNull);
|
|
Assert(szField != szNull);
|
|
Assert(cbFieldMax > 0);
|
|
|
|
*szField = chEos;
|
|
cbFieldMaxCur--;
|
|
|
|
Assert(chSep != chSpace);
|
|
while (FWhiteSpaceCh(*szLine) && *szLine != chSep)
|
|
szLine = SzNextChar(szLine);
|
|
|
|
if (*szLine == chDblQuote) /* Strip off the outermost set of quotes. */
|
|
{
|
|
fQuotedField = fTrue;
|
|
fInQuotedField = fTrue;
|
|
szLine = SzNextChar(szLine);
|
|
}
|
|
|
|
while (*szLine != chEos && (fInQuotedField || *szLine != chSep))
|
|
{
|
|
BOOL fNonSpace;
|
|
|
|
if (*szLine == chDblQuote)
|
|
{
|
|
if (!fInQuotedField)
|
|
{
|
|
if (chSep == chFieldSep) /* in XL tab file only */
|
|
{
|
|
DebugMsgBox(szLineStart, "Badly formed field: Quote in "
|
|
"unquoted field");
|
|
return (szNull);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
szLine = SzNextChar(szLine);
|
|
if (*szLine == chSep || *szLine == chEos)
|
|
{
|
|
fInQuotedField = fFalse;
|
|
break;
|
|
}
|
|
/* Consecutive double quotes are treated as one quote. */
|
|
if (*szLine != chDblQuote)
|
|
{
|
|
/* Strip off trailing spaces
|
|
*/
|
|
while (FWhiteSpaceCh(*szLine) && *szLine != chSep)
|
|
szLine = SzNextChar(szLine);
|
|
if (*szLine == chSep || *szLine == chEos)
|
|
{
|
|
fInQuotedField = fFalse;
|
|
break;
|
|
}
|
|
DebugMsgBox(szLineStart, "Badly formed field: "
|
|
"Non-doubled quote in quoted field");
|
|
return (szNull);
|
|
}
|
|
}
|
|
}
|
|
if (cbFieldMaxCur == 0)
|
|
{
|
|
#ifdef DEBUG
|
|
CHAR rgch[cchSzMax];
|
|
|
|
wsprintf(rgch, "Error: Field is too long (>= %d)", cbFieldMax);
|
|
DebugMsgBox(szLineStart, rgch);
|
|
#endif
|
|
*szField = chEos;
|
|
return (szNull);
|
|
}
|
|
fNonSpace = (*szLine != chSpace);
|
|
CopyCharToBuf(&szLine, &szField, &cbFieldMaxCur);
|
|
if (fNonSpace)
|
|
szFieldEnd = szField;
|
|
}
|
|
|
|
if (!fQuotedField)
|
|
szField = szFieldEnd; /* Strip off trailing spaces */
|
|
*szField = chEos;
|
|
|
|
if (fInQuotedField)
|
|
{
|
|
DebugMsgBox(szLineStart, "Badly formed field: Unmatched quote");
|
|
return (szNull);
|
|
}
|
|
Assert(*szLine == chEos || *szLine == chSep);
|
|
if (*szLine == chSep)
|
|
szLine = SzNextChar(szLine);
|
|
|
|
return (szLine);
|
|
}
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Copies a character from one buffer to another and advancing pointers.
|
|
** Arguments:
|
|
** pszCur: Pointer to string to copy character from.
|
|
** pszBuf: Pointer to string to copy character to.
|
|
** pcbBuf: Pointer to useable size of pszBuf.
|
|
** Returns:
|
|
** none.
|
|
** Notes:
|
|
**
|
|
****************************************************************************/
|
|
VOID PUBLIC CopyCharToBuf ( PSZ pszCur, PSZ pszBuf, PCB pcbBuf )
|
|
{
|
|
SZ szEnd = SzNextChar(*pszCur);
|
|
|
|
if ((CB)(szEnd - *pszCur) <= *pcbBuf)
|
|
{
|
|
while (*pszCur < szEnd)
|
|
{
|
|
*(*pszBuf)++ = *(*pszCur)++;
|
|
(*pcbBuf)--;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pszCur = szEnd;
|
|
*pcbBuf = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
************************************************************************/
|
|
PLOR PUBLIC PlorFromSz ( OR orCur, SZ sz )
|
|
{
|
|
PLOR plor = plorNull;
|
|
SZ szCur;
|
|
UINT cor;
|
|
|
|
Assert(sz != szNull);
|
|
|
|
LWalkStringReadingLOR:
|
|
szCur = sz;
|
|
cor = 0;
|
|
while (*szCur != chEos)
|
|
{
|
|
SZ szSep;
|
|
|
|
while (FWhiteSpaceCh(*szCur))
|
|
szCur = SzNextChar(szCur);
|
|
if (*szCur == chEos)
|
|
break;
|
|
szSep = szCur;
|
|
while (*szSep != chEos
|
|
&& !FWhiteSpaceCh(*szSep)
|
|
&& *szSep != chLorSep)
|
|
{
|
|
if (!isdigit(*szSep))
|
|
{
|
|
ParseError(orCur, STR_OBJID_ERR);
|
|
FFreePlor(&plor);
|
|
return (plorNull);
|
|
}
|
|
szSep = SzNextChar(szSep);
|
|
}
|
|
|
|
if (plor != plorNull)
|
|
{
|
|
CHAR chSav;
|
|
|
|
Assert(plor->rgor != rgorNull);
|
|
chSav = *szSep;
|
|
*szSep = chEos;
|
|
plor->rgor[cor] = atoi(szCur);
|
|
*szSep = chSav;
|
|
}
|
|
|
|
cor++;
|
|
szCur = szSep;
|
|
if (*szCur != chEos)
|
|
szCur = SzNextChar(szCur);
|
|
}
|
|
|
|
if (plor == plorNull
|
|
&& cor > 0
|
|
&& (plor = PlorAlloc(cor)) != plorNull)
|
|
{
|
|
Assert(plor->rgor != rgorNull);
|
|
Assert(plor->cor == cor);
|
|
goto LWalkStringReadingLOR;
|
|
}
|
|
|
|
return (plor);
|
|
}
|
|
|
|
|
|
/*
|
|
************************************************************************/
|
|
BOOL PUBLIC FFreePlor ( PPLOR pplor )
|
|
{
|
|
PLOR plor = *pplor;
|
|
|
|
if (plor != plorNull)
|
|
{
|
|
Assert(plor->cor > 0);
|
|
Assert(plor->rgor != rgorNull);
|
|
|
|
FFree((PB)(plor->rgor), (CB)(plor->cor * sizeof(OR)));
|
|
FFree((PB)plor, (CB)sizeof(LOR));
|
|
*pplor = plorNull;
|
|
}
|
|
|
|
return (fTrue);
|
|
}
|
|
|
|
|
|
/*
|
|
************************************************************************/
|
|
PLOR PUBLIC PlorAlloc ( UINT cor )
|
|
{
|
|
PLOR plor;
|
|
|
|
Assert(cor > 0);
|
|
|
|
while ((plor = (PLOR)PbAlloc((CB)sizeof(LOR))) == plorNull)
|
|
{
|
|
if (!FHandleOOM())
|
|
return (plorNull);
|
|
}
|
|
|
|
plor->cor = cor;
|
|
while ((plor->rgor = (RGOR)PbAlloc((CB)(cor * sizeof(OR)))) == rgorNull)
|
|
{
|
|
if (!FHandleOOM())
|
|
{
|
|
FFree((PB)plor, (CB)sizeof(LOR));
|
|
return (plorNull);
|
|
}
|
|
}
|
|
|
|
return (plor);
|
|
}
|
|
|
|
|
|
|